From 7e7984766579abfe1cbe1aa9329f3861f7c9f9d8 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 15 Sep 2021 15:39:04 +1200 Subject: [PATCH 01/22] Start refactor of ToolsPanel component to typescript --- .../tools-panel/{context.js => context.ts} | 0 .../{component.js => component.tsx} | 6 +++- .../tools-panel/{hook.js => hook.ts} | 7 +++-- packages/components/src/tools-panel/types.ts | 28 +++++++++++++++++++ 4 files changed, 37 insertions(+), 4 deletions(-) rename packages/components/src/tools-panel/{context.js => context.ts} (100%) rename packages/components/src/tools-panel/tools-panel/{component.js => component.tsx} (83%) rename packages/components/src/tools-panel/tools-panel/{hook.js => hook.ts} (94%) create mode 100644 packages/components/src/tools-panel/types.ts diff --git a/packages/components/src/tools-panel/context.js b/packages/components/src/tools-panel/context.ts similarity index 100% rename from packages/components/src/tools-panel/context.js rename to packages/components/src/tools-panel/context.ts diff --git a/packages/components/src/tools-panel/tools-panel/component.js b/packages/components/src/tools-panel/tools-panel/component.tsx similarity index 83% rename from packages/components/src/tools-panel/tools-panel/component.js rename to packages/components/src/tools-panel/tools-panel/component.tsx index 8f38889fbc8e3c..c7ab4adae5dd25 100644 --- a/packages/components/src/tools-panel/tools-panel/component.js +++ b/packages/components/src/tools-panel/tools-panel/component.tsx @@ -6,8 +6,12 @@ import { ToolsPanelContext } from '../context'; import { useToolsPanel } from './hook'; import { View } from '../../view'; import { contextConnect } from '../../ui/context'; +import type { ToolsPanelProps, toolsPanelforwardRef } from '../types'; -const ToolsPanel = ( props, forwardedRef ) => { +const ToolsPanel = ( + props: ToolsPanelProps, + forwardedRef: toolsPanelforwardRef +) => { const { children, label, diff --git a/packages/components/src/tools-panel/tools-panel/hook.js b/packages/components/src/tools-panel/tools-panel/hook.ts similarity index 94% rename from packages/components/src/tools-panel/tools-panel/hook.js rename to packages/components/src/tools-panel/tools-panel/hook.ts index b2b7d35fc6bf5e..a74dcc7654ce00 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.js +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -9,6 +9,7 @@ import { useEffect, useMemo, useRef, useState } from '@wordpress/element'; import * as styles from '../styles'; import { useContextSystem } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; +import type { ToolsPanelProps, ToolPanelItem } from '../types'; const generateMenuItems = ( { panelItems, reset } ) => { const menuItems = { default: {}, optional: {} }; @@ -21,7 +22,7 @@ const generateMenuItems = ( { panelItems, reset } ) => { return menuItems; }; -export function useToolsPanel( props ) { +export function useToolsPanel( props: ToolsPanelProps ) { const { className, resetAll, panelId, ...otherProps } = useContextSystem( props, 'ToolsPanel' @@ -48,7 +49,7 @@ export function useToolsPanel( props ) { // Allow panel items to register themselves. const [ panelItems, setPanelItems ] = useState( [] ); - const registerPanelItem = ( item ) => { + const registerPanelItem = ( item: ToolPanelItem ) => { setPanelItems( ( items ) => [ ...items, item ] ); }; @@ -103,7 +104,7 @@ export function useToolsPanel( props ) { // 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 toggleItem = ( label: string ) => { const currentItem = panelItems.find( ( item ) => item.label === label ); if ( ! currentItem ) { diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts new file mode 100644 index 00000000000000..ffae6e0430475b --- /dev/null +++ b/packages/components/src/tools-panel/types.ts @@ -0,0 +1,28 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { ReactNode, Ref } from 'react'; + +export type toolsPanelforwardRef = Ref< any >; + +export interface ToolsPanelProps { + label: string; + header: string; + children: ReactNode; + resetAll: () => undefined; + className?: string; +} + +export interface ToolsPanelHeaderProps { + menuLabel: string; + header: string; + resetAll: () => undefined; + toggleItem: ( label: string ) => undefined; +} + +export interface ToolPanelItem { + hasValue: () => boolean; + isShownByDefault: boolean; + label: string; +} From b1e2fc0b01758fdd305f9bc3d6ec627daad7935b Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 12 Aug 2021 17:30:14 +1200 Subject: [PATCH 02/22] Add typing for dropdown menu --- .../components/src/dropdown-menu/index.js | 4 +- .../components/src/dropdown-menu/types.ts | 66 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 packages/components/src/dropdown-menu/types.ts diff --git a/packages/components/src/dropdown-menu/index.js b/packages/components/src/dropdown-menu/index.js index c3cd6ad969d3fd..5b2ab82a855622 100644 --- a/packages/components/src/dropdown-menu/index.js +++ b/packages/components/src/dropdown-menu/index.js @@ -32,7 +32,9 @@ function mergeProps( defaultProps = {}, props = {} ) { return mergedProps; } - +/** + * @param {import('./types').Props} props + */ function DropdownMenu( { children, className, diff --git a/packages/components/src/dropdown-menu/types.ts b/packages/components/src/dropdown-menu/types.ts new file mode 100644 index 00000000000000..11a621177508b7 --- /dev/null +++ b/packages/components/src/dropdown-menu/types.ts @@ -0,0 +1,66 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { ReactNode } from 'react'; + +export type Props = { + /** + * The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug to be shown in the collapsed menu button. + */ + icon?: JSX.Element; + /** + * A human-readable label to present as accessibility text on the focused collapsed menu button.. + * + * @default 'inherit' + */ + label: string; + /** + * An array of objects describing the options to be shown in the expanded menu. + * Each object should include an `icon` [Dashicon](https://developer.wordpress.org/resource/dashicons/) slug string, a + * human-readable `title` string, `isDisabled` boolean flag and an `onClick` function callback to invoke when the option is selected. + * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. + */ + controls?: number; + /** + * A [function render prop](https://reactjs.org/docs/render-props.html#using-props-other-than-render) which should return an element or + * elements valid for use in a DropdownMenu: `MenuItem`, `MenuItemsChoice`, or `MenuGroup`. Its first argument is a props object including + * the same values as given to a [`Dropdown`'s `renderContent`](/packages/components/src/dropdown#rendercontent) (`isOpen`, `onToggle`, `onClose`). + * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. + */ + children?: ReactNode; + /** + * A class name to apply to the dropdown menu's toggle element wrapper. + * + */ + className?: string; + /** + * Properties of `popoverProps` object will be passed as props to the nested `Popover` component. + * Use this object to modify props available for the `Popover` component that are not already exposed in the `DropdownMenu` component, + * e.g.: the direction in which the popover should open relative to its parent node set with `position` prop. + * + */ + popoverProps?: object; + /** + * Properties of `toggleProps` object will be passed as props to the nested `Button` component in the `renderToggle` implementation of the + * `Dropdown` component used internally. + * Use this object to modify props available for the `Button` component that are not already exposed in the `DropdownMenu` component, e.g.: + * the tooltip text displayed on hover set with `tooltip` prop. + * + */ + toggleProps?: object; + /** + * Properties of `menuProps` object will be passed as props to the nested `NavigableMenu` component in the `renderContent` implementation of + * the `Dropdown` component used internally. + * Use this object to modify props available for the `NavigableMenu` component that are not already exposed in the `DropdownMenu` component, e.g.: + * the orientation of the menu set with `orientation` prop.p.p. + * + */ + menuProps?: object; + /** + * In some contexts, the arrow down key used to open the dropdown menu might need to be disabled—for example when that key is used to perform + * another action. + * + */ + disableOpenOnArrowDown?: boolean; +}; From 65fa4f6ad906b703e42b01bb6ac9e7838250d72f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 15 Sep 2021 15:43:55 +1200 Subject: [PATCH 03/22] Start typing the ToolsPanelHeader component --- .../tools-panel-header/{component.js => component.tsx} | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) rename packages/components/src/tools-panel/tools-panel-header/{component.js => component.tsx} (94%) diff --git a/packages/components/src/tools-panel/tools-panel-header/component.js b/packages/components/src/tools-panel/tools-panel-header/component.tsx similarity index 94% rename from packages/components/src/tools-panel/tools-panel-header/component.js rename to packages/components/src/tools-panel/tools-panel-header/component.tsx index 2a1e82e2338f71..7717a5f903aa34 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.js +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -12,6 +12,11 @@ import MenuGroup from '../../menu-group'; import MenuItem from '../../menu-item'; import { useToolsPanelHeader } from './hook'; import { contextConnect } from '../../ui/context'; +import type { + ToolsPanelHeaderProps, + toolsPanelforwardRef, + ToolPanelItem, +} from '../types'; const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { if ( ! items.length ) { @@ -91,7 +96,10 @@ const OptionalControlsGroup = ( { items, onClose, toggleItem } ) => { ); }; -const ToolsPanelHeader = ( props, forwardedRef ) => { +const ToolsPanelHeader = ( + props: ToolsPanelHeaderProps, + forwardedRef: toolsPanelforwardRef +) => { const { dropdownMenuClassName, hasMenuItems, From 74ddbd8a3e5f4c52c95429c68a4828c23244f3ae Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 13 Aug 2021 10:59:43 +1200 Subject: [PATCH 04/22] Add types for ToolsPanelHeader --- packages/components/src/menu-group/index.js | 7 ++++ packages/components/src/menu-group/types.ts | 24 ++++++++++++ packages/components/src/menu-item/index.js | 13 ++----- packages/components/src/menu-item/types.ts | 38 +++++++++++++++++++ .../components/src/tools-panel/context.ts | 7 +++- .../tools-panel-header/component.tsx | 6 +-- .../tools-panel-header/{hook.js => hook.ts} | 3 +- packages/components/src/tools-panel/types.ts | 5 +++ 8 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 packages/components/src/menu-group/types.ts create mode 100644 packages/components/src/menu-item/types.ts rename packages/components/src/tools-panel/tools-panel-header/{hook.js => hook.ts} (86%) diff --git a/packages/components/src/menu-group/index.js b/packages/components/src/menu-group/index.js index 19e182ddc74ffe..6f880cce83da79 100644 --- a/packages/components/src/menu-group/index.js +++ b/packages/components/src/menu-group/index.js @@ -9,6 +9,13 @@ import classnames from 'classnames'; import { Children } from '@wordpress/element'; import { useInstanceId } from '@wordpress/compose'; +/** + * Renders a generic menu item for use inside the more menu + * + * @param {import('./types').Props} props + * + * @return {WPComponent} The component to be rendered. + */ export function MenuGroup( { children, className = '', diff --git a/packages/components/src/menu-group/types.ts b/packages/components/src/menu-group/types.ts new file mode 100644 index 00000000000000..c4e878a2ef8b6a --- /dev/null +++ b/packages/components/src/menu-group/types.ts @@ -0,0 +1,24 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { ReactNode } from 'react'; + +export type Props = { + /** + * Element to render as child of button. + */ + children?: ReactNode; + /** + * Optional classname string to add to wrapper div + */ + className?: string; + /** + * Optional label to display. + */ + label?: string; + /** + * Whether or not to show a separator between items. + */ + hideSeparator?: boolean; +}; diff --git a/packages/components/src/menu-item/index.js b/packages/components/src/menu-item/index.js index 8bed60d84df8f7..89a16df6d46e1e 100644 --- a/packages/components/src/menu-item/index.js +++ b/packages/components/src/menu-item/index.js @@ -17,17 +17,10 @@ import Button from '../button'; import Icon from '../icon'; /** - * Renders a generic menu item for use inside the more menu. + * Renders a generic menu item for use inside the more menu * - * @param {Object} props Component props. - * @param {WPElement} props.children Element to render as child of button. - * @param {string} props.info Text to use as description for button text. - * @param {string} props.className Class to set on the container. - * @param {WPIcon} props.icon Button's `icon` prop. - * @param {string|Object} props.shortcut Shortcut's `shortcut` prop. - * @param {boolean} props.isSelected Whether or not the menu item is currently selected. - * @param {string} [props.role="menuitem"] ARIA role of the menu item. - * @param {Object} ref React Element ref. + * @param {import('./types').Props} props + * @param {Object} ref React Element ref. * * @return {WPComponent} The component to be rendered. */ diff --git a/packages/components/src/menu-item/types.ts b/packages/components/src/menu-item/types.ts new file mode 100644 index 00000000000000..16ee90524dad52 --- /dev/null +++ b/packages/components/src/menu-item/types.ts @@ -0,0 +1,38 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { ReactNode } from 'react'; + +export type Props = { + /** + * Element to render as child of button. + */ + children?: ReactNode; + /** + * Text to use as description for button text. + * Refer to documentation for [`label`](#label). + */ + info?: string; + /** + * Refer to documentation for [Button's `icon` prop](/packages/components/src/icon-button/README.md#icon). + */ + icon?: string | JSX.Element; + /** + * Whether or not the menu item is currently selected. + */ + isSelected?: boolean; + /** + * Refer to documentation for [Shortcut's `shortcut` prop](/packages/components/src/shortcut/README.md#shortcut). + */ + shortcut?: string; + /** + * [Aria Spec](https://www.w3.org/TR/wai-aria-1.1/#aria-checked). If you need to have selectable menu items use menuitemradio for + * single select, and menuitemcheckbox for multiselect. + */ + role?: string; + /** + * Handler for click events. + */ + onClick?: () => void; +}; diff --git a/packages/components/src/tools-panel/context.ts b/packages/components/src/tools-panel/context.ts index e74e08708db9f9..fc10763a28f215 100644 --- a/packages/components/src/tools-panel/context.ts +++ b/packages/components/src/tools-panel/context.ts @@ -3,5 +3,10 @@ */ import { createContext, useContext } from '@wordpress/element'; -export const ToolsPanelContext = createContext( {} ); +/** + * Internal dependencies + */ +import type { TPContext } from './types'; + +export const ToolsPanelContext = createContext< TPContext >( {} ); export const useToolsPanelContext = () => useContext( ToolsPanelContext ); diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index 7717a5f903aa34..d7bac9b08f0320 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -12,11 +12,7 @@ import MenuGroup from '../../menu-group'; import MenuItem from '../../menu-item'; import { useToolsPanelHeader } from './hook'; import { contextConnect } from '../../ui/context'; -import type { - ToolsPanelHeaderProps, - toolsPanelforwardRef, - ToolPanelItem, -} from '../types'; +import type { ToolsPanelHeaderProps, toolsPanelforwardRef } from '../types'; const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { if ( ! items.length ) { diff --git a/packages/components/src/tools-panel/tools-panel-header/hook.js b/packages/components/src/tools-panel/tools-panel-header/hook.ts similarity index 86% rename from packages/components/src/tools-panel/tools-panel-header/hook.js rename to packages/components/src/tools-panel/tools-panel-header/hook.ts index 462d515b7b6fa2..8f8c5a1eade2b9 100644 --- a/packages/components/src/tools-panel/tools-panel-header/hook.js +++ b/packages/components/src/tools-panel/tools-panel-header/hook.ts @@ -10,8 +10,9 @@ import * as styles from '../styles'; import { useToolsPanelContext } from '../context'; import { useContextSystem } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; +import type { ToolsPanelHeaderProps } from '../types'; -export function useToolsPanelHeader( props ) { +export function useToolsPanelHeader( props: ToolsPanelHeaderProps ) { const { className, ...otherProps } = useContextSystem( props, 'ToolsPanelHeader' diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index ffae6e0430475b..98d37554ace1cd 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -19,6 +19,7 @@ export interface ToolsPanelHeaderProps { header: string; resetAll: () => undefined; toggleItem: ( label: string ) => undefined; + className?: string; } export interface ToolPanelItem { @@ -26,3 +27,7 @@ export interface ToolPanelItem { isShownByDefault: boolean; label: string; } + +export interface TPContext { + menuItems?: { [ key: string ]: boolean }; +} From 15c0ae3a693c9fb8e7ffea3a18ef4f31649ccd52 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 13 Aug 2021 11:40:01 +1200 Subject: [PATCH 05/22] Add remaining types --- .../tools-panel-header/component.tsx | 4 ++-- .../{component.js => component.tsx} | 6 +++++- .../tools-panel-item/{hook.js => hook.ts} | 5 +++-- .../src/tools-panel/tools-panel/component.tsx | 7 ++----- .../src/tools-panel/tools-panel/hook.ts | 4 ++-- packages/components/src/tools-panel/types.ts | 18 +++++++++++++----- 6 files changed, 27 insertions(+), 17 deletions(-) rename packages/components/src/tools-panel/tools-panel-item/{component.js => component.tsx} (81%) rename packages/components/src/tools-panel/tools-panel-item/{hook.js => hook.ts} (94%) diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index d7bac9b08f0320..9fb89769d40221 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -12,7 +12,7 @@ import MenuGroup from '../../menu-group'; import MenuItem from '../../menu-item'; import { useToolsPanelHeader } from './hook'; import { contextConnect } from '../../ui/context'; -import type { ToolsPanelHeaderProps, toolsPanelforwardRef } from '../types'; +import type { ToolsPanelHeaderProps, forwardRef } from '../types'; const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { if ( ! items.length ) { @@ -94,7 +94,7 @@ const OptionalControlsGroup = ( { items, onClose, toggleItem } ) => { const ToolsPanelHeader = ( props: ToolsPanelHeaderProps, - forwardedRef: toolsPanelforwardRef + forwardedRef: forwardRef ) => { const { dropdownMenuClassName, diff --git a/packages/components/src/tools-panel/tools-panel-item/component.js b/packages/components/src/tools-panel/tools-panel-item/component.tsx similarity index 81% rename from packages/components/src/tools-panel/tools-panel-item/component.js rename to packages/components/src/tools-panel/tools-panel-item/component.tsx index 92cca8a626022f..3efd81bd55a1e6 100644 --- a/packages/components/src/tools-panel/tools-panel-item/component.js +++ b/packages/components/src/tools-panel/tools-panel-item/component.tsx @@ -4,10 +4,14 @@ import { useToolsPanelItem } from './hook'; import { View } from '../../view'; import { contextConnect } from '../../ui/context'; +import type { forwardRef, ToolsPanelItemProps } from '../types'; // 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 ToolsPanelItem = ( + props: ToolsPanelItemProps, + forwardedRef: forwardRef +) => { const { children, isShown, ...toolsPanelItemProps } = useToolsPanelItem( props ); diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.js b/packages/components/src/tools-panel/tools-panel-item/hook.ts similarity index 94% rename from packages/components/src/tools-panel/tools-panel-item/hook.js rename to packages/components/src/tools-panel/tools-panel-item/hook.ts index 6b7b5cfd3023de..2b9a2a102065b2 100644 --- a/packages/components/src/tools-panel/tools-panel-item/hook.js +++ b/packages/components/src/tools-panel/tools-panel-item/hook.ts @@ -11,8 +11,9 @@ import * as styles from '../styles'; import { useToolsPanelContext } from '../context'; import { useContextSystem } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; +import type { ToolsPanelItemProps } from '../types'; -export function useToolsPanelItem( props ) { +export function useToolsPanelItem( props: ToolsPanelItemProps ) { const { className, hasValue, @@ -28,7 +29,7 @@ export function useToolsPanelItem( props ) { const cx = useCx(); const classes = useMemo( () => { return cx( styles.ToolsPanelItem, className ); - } ); + }, [ styles.ToolsPanelItem, className ] ); const { panelId: currentPanelId, diff --git a/packages/components/src/tools-panel/tools-panel/component.tsx b/packages/components/src/tools-panel/tools-panel/component.tsx index c7ab4adae5dd25..19938661cc5a9c 100644 --- a/packages/components/src/tools-panel/tools-panel/component.tsx +++ b/packages/components/src/tools-panel/tools-panel/component.tsx @@ -6,12 +6,9 @@ import { ToolsPanelContext } from '../context'; import { useToolsPanel } from './hook'; import { View } from '../../view'; import { contextConnect } from '../../ui/context'; -import type { ToolsPanelProps, toolsPanelforwardRef } from '../types'; +import type { ToolsPanelProps, forwardRef } from '../types'; -const ToolsPanel = ( - props: ToolsPanelProps, - forwardedRef: toolsPanelforwardRef -) => { +const ToolsPanel = ( props: ToolsPanelProps, forwardedRef: forwardRef ) => { const { children, label, diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index a74dcc7654ce00..fd1869b706f63c 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -9,7 +9,7 @@ import { useEffect, useMemo, useRef, useState } from '@wordpress/element'; import * as styles from '../styles'; import { useContextSystem } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; -import type { ToolsPanelProps, ToolPanelItem } from '../types'; +import type { ToolsPanelProps, ToolsPanelItem } from '../types'; const generateMenuItems = ( { panelItems, reset } ) => { const menuItems = { default: {}, optional: {} }; @@ -49,7 +49,7 @@ export function useToolsPanel( props: ToolsPanelProps ) { // Allow panel items to register themselves. const [ panelItems, setPanelItems ] = useState( [] ); - const registerPanelItem = ( item: ToolPanelItem ) => { + const registerPanelItem = ( item: ToolsPanelItem ) => { setPanelItems( ( items ) => [ ...items, item ] ); }; diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index 98d37554ace1cd..41a660cf30bbe5 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -4,30 +4,38 @@ // eslint-disable-next-line no-restricted-imports import type { ReactNode, Ref } from 'react'; -export type toolsPanelforwardRef = Ref< any >; +export type forwardRef = Ref< any >; export interface ToolsPanelProps { label: string; header: string; children: ReactNode; - resetAll: () => undefined; + resetAll: () => void; className?: string; } export interface ToolsPanelHeaderProps { menuLabel: string; header: string; - resetAll: () => undefined; - toggleItem: ( label: string ) => undefined; + resetAll: () => void; + toggleItem: ( label: string ) => void; className?: string; } -export interface ToolPanelItem { +export interface ToolsPanelItem { hasValue: () => boolean; isShownByDefault: boolean; label: string; } +export interface ToolsPanelItemProps extends ToolsPanelItem { + children?: ReactNode; + onDeselect?: () => void; + onSelect?: () => void; + className?: string; +} + export interface TPContext { menuItems?: { [ key: string ]: boolean }; + registerPanelItem?: ( item: ToolsPanelItem ) => void; } From 336efbae318c2c836c051e0ce3a5956da62e8824 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 15 Sep 2021 15:47:24 +1200 Subject: [PATCH 06/22] More conflict resolution --- .../tools-panel/tools-panel-header/component.tsx | 14 ++++++++++---- .../src/tools-panel/tools-panel-header/hook.ts | 6 ++++-- .../tools-panel/tools-panel-item/component.tsx | 14 ++++++++++---- .../src/tools-panel/tools-panel-item/hook.ts | 6 ++++-- .../src/tools-panel/tools-panel/component.tsx | 15 ++++++++++++--- .../src/tools-panel/tools-panel/hook.ts | 6 ++++-- packages/components/src/tools-panel/types.ts | 4 +--- 7 files changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index 9fb89769d40221..08d2cbb9ea9649 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -1,3 +1,9 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { Ref } from 'react'; + /** * WordPress dependencies */ @@ -11,8 +17,8 @@ import DropdownMenu from '../../dropdown-menu'; import MenuGroup from '../../menu-group'; import MenuItem from '../../menu-item'; import { useToolsPanelHeader } from './hook'; -import { contextConnect } from '../../ui/context'; -import type { ToolsPanelHeaderProps, forwardRef } from '../types'; +import { contextConnect, PolymorphicComponentProps } from '../../ui/context'; +import type { ToolsPanelHeaderProps } from '../types'; const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { if ( ! items.length ) { @@ -93,8 +99,8 @@ const OptionalControlsGroup = ( { items, onClose, toggleItem } ) => { }; const ToolsPanelHeader = ( - props: ToolsPanelHeaderProps, - forwardedRef: forwardRef + props: PolymorphicComponentProps< ToolsPanelHeaderProps, 'h2' >, + forwardedRef: Ref< any > ) => { const { dropdownMenuClassName, diff --git a/packages/components/src/tools-panel/tools-panel-header/hook.ts b/packages/components/src/tools-panel/tools-panel-header/hook.ts index 8f8c5a1eade2b9..eab8e8e7fdad47 100644 --- a/packages/components/src/tools-panel/tools-panel-header/hook.ts +++ b/packages/components/src/tools-panel/tools-panel-header/hook.ts @@ -8,11 +8,13 @@ import { useMemo } from '@wordpress/element'; */ import * as styles from '../styles'; import { useToolsPanelContext } from '../context'; -import { useContextSystem } from '../../ui/context'; +import { useContextSystem, PolymorphicComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelHeaderProps } from '../types'; -export function useToolsPanelHeader( props: ToolsPanelHeaderProps ) { +export function useToolsPanelHeader( + props: PolymorphicComponentProps< ToolsPanelHeaderProps, 'h2' > +) { const { className, ...otherProps } = useContextSystem( props, 'ToolsPanelHeader' diff --git a/packages/components/src/tools-panel/tools-panel-item/component.tsx b/packages/components/src/tools-panel/tools-panel-item/component.tsx index 3efd81bd55a1e6..d2627930d50c77 100644 --- a/packages/components/src/tools-panel/tools-panel-item/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-item/component.tsx @@ -1,16 +1,22 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { Ref } from 'react'; + /** * Internal dependencies */ import { useToolsPanelItem } from './hook'; import { View } from '../../view'; -import { contextConnect } from '../../ui/context'; -import type { forwardRef, ToolsPanelItemProps } from '../types'; +import { contextConnect, PolymorphicComponentProps } from '../../ui/context'; +import type { ToolsPanelItemProps } from '../types'; // 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: ToolsPanelItemProps, - forwardedRef: forwardRef + props: PolymorphicComponentProps< ToolsPanelItemProps, 'div' >, + forwardedRef: Ref< any > ) => { const { children, isShown, ...toolsPanelItemProps } = useToolsPanelItem( props diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.ts b/packages/components/src/tools-panel/tools-panel-item/hook.ts index 2b9a2a102065b2..3cf80cc3714898 100644 --- a/packages/components/src/tools-panel/tools-panel-item/hook.ts +++ b/packages/components/src/tools-panel/tools-panel-item/hook.ts @@ -9,11 +9,13 @@ import { useEffect, useMemo } from '@wordpress/element'; */ import * as styles from '../styles'; import { useToolsPanelContext } from '../context'; -import { useContextSystem } from '../../ui/context'; +import { useContextSystem, PolymorphicComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelItemProps } from '../types'; -export function useToolsPanelItem( props: ToolsPanelItemProps ) { +export function useToolsPanelItem( + props: PolymorphicComponentProps< ToolsPanelItemProps, 'div' > +) { const { className, hasValue, diff --git a/packages/components/src/tools-panel/tools-panel/component.tsx b/packages/components/src/tools-panel/tools-panel/component.tsx index 19938661cc5a9c..9b4629ba877ce7 100644 --- a/packages/components/src/tools-panel/tools-panel/component.tsx +++ b/packages/components/src/tools-panel/tools-panel/component.tsx @@ -1,3 +1,9 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type { Ref } from 'react'; + /** * Internal dependencies */ @@ -5,10 +11,13 @@ import ToolsPanelHeader from '../tools-panel-header'; import { ToolsPanelContext } from '../context'; import { useToolsPanel } from './hook'; import { View } from '../../view'; -import { contextConnect } from '../../ui/context'; -import type { ToolsPanelProps, forwardRef } from '../types'; +import { contextConnect, PolymorphicComponentProps } from '../../ui/context'; +import type { ToolsPanelProps } from '../types'; -const ToolsPanel = ( props: ToolsPanelProps, forwardedRef: forwardRef ) => { +const ToolsPanel = ( + props: PolymorphicComponentProps< ToolsPanelProps, 'div' >, + forwardedRef: Ref< any > +) => { const { children, label, diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index fd1869b706f63c..49e77c116d2bc0 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -7,7 +7,7 @@ import { useEffect, useMemo, useRef, useState } from '@wordpress/element'; * Internal dependencies */ import * as styles from '../styles'; -import { useContextSystem } from '../../ui/context'; +import { useContextSystem, PolymorphicComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelProps, ToolsPanelItem } from '../types'; @@ -22,7 +22,9 @@ const generateMenuItems = ( { panelItems, reset } ) => { return menuItems; }; -export function useToolsPanel( props: ToolsPanelProps ) { +export function useToolsPanel( + props: PolymorphicComponentProps< ToolsPanelProps, 'div' > +) { const { className, resetAll, panelId, ...otherProps } = useContextSystem( props, 'ToolsPanel' diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index 41a660cf30bbe5..67a2d0133bca62 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -2,9 +2,7 @@ * External dependencies */ // eslint-disable-next-line no-restricted-imports -import type { ReactNode, Ref } from 'react'; - -export type forwardRef = Ref< any >; +import type { ReactNode } from 'react'; export interface ToolsPanelProps { label: string; From a1fe2874519f7238930fa3021db1d3093f41b760 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 3 Sep 2021 10:03:27 +1200 Subject: [PATCH 07/22] Update PolymorphicComponent* references to WordPressComponentProps* --- .../src/tools-panel/tools-panel-header/component.tsx | 4 ++-- .../components/src/tools-panel/tools-panel-header/hook.ts | 4 ++-- .../components/src/tools-panel/tools-panel-item/component.tsx | 4 ++-- packages/components/src/tools-panel/tools-panel-item/hook.ts | 4 ++-- packages/components/src/tools-panel/tools-panel/component.tsx | 4 ++-- packages/components/src/tools-panel/tools-panel/hook.ts | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index 08d2cbb9ea9649..50f6b1564aa8fe 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -17,7 +17,7 @@ import DropdownMenu from '../../dropdown-menu'; import MenuGroup from '../../menu-group'; import MenuItem from '../../menu-item'; import { useToolsPanelHeader } from './hook'; -import { contextConnect, PolymorphicComponentProps } from '../../ui/context'; +import { contextConnect, WordPressComponentProps } from '../../ui/context'; import type { ToolsPanelHeaderProps } from '../types'; const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { @@ -99,7 +99,7 @@ const OptionalControlsGroup = ( { items, onClose, toggleItem } ) => { }; const ToolsPanelHeader = ( - props: PolymorphicComponentProps< ToolsPanelHeaderProps, 'h2' >, + props: WordPressComponentProps< ToolsPanelHeaderProps, 'h2' >, forwardedRef: Ref< any > ) => { const { diff --git a/packages/components/src/tools-panel/tools-panel-header/hook.ts b/packages/components/src/tools-panel/tools-panel-header/hook.ts index eab8e8e7fdad47..f31e8cb6372df6 100644 --- a/packages/components/src/tools-panel/tools-panel-header/hook.ts +++ b/packages/components/src/tools-panel/tools-panel-header/hook.ts @@ -8,12 +8,12 @@ import { useMemo } from '@wordpress/element'; */ import * as styles from '../styles'; import { useToolsPanelContext } from '../context'; -import { useContextSystem, PolymorphicComponentProps } from '../../ui/context'; +import { useContextSystem, WordPressComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelHeaderProps } from '../types'; export function useToolsPanelHeader( - props: PolymorphicComponentProps< ToolsPanelHeaderProps, 'h2' > + props: WordPressComponentProps< ToolsPanelHeaderProps, 'h2' > ) { const { className, ...otherProps } = useContextSystem( props, diff --git a/packages/components/src/tools-panel/tools-panel-item/component.tsx b/packages/components/src/tools-panel/tools-panel-item/component.tsx index d2627930d50c77..cde52e5f3ec0fd 100644 --- a/packages/components/src/tools-panel/tools-panel-item/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-item/component.tsx @@ -9,13 +9,13 @@ import type { Ref } from 'react'; */ import { useToolsPanelItem } from './hook'; import { View } from '../../view'; -import { contextConnect, PolymorphicComponentProps } from '../../ui/context'; +import { contextConnect, WordPressComponentProps } from '../../ui/context'; import type { ToolsPanelItemProps } from '../types'; // 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: PolymorphicComponentProps< ToolsPanelItemProps, 'div' >, + props: WordPressComponentProps< ToolsPanelItemProps, 'div' >, forwardedRef: Ref< any > ) => { const { children, isShown, ...toolsPanelItemProps } = useToolsPanelItem( diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.ts b/packages/components/src/tools-panel/tools-panel-item/hook.ts index 3cf80cc3714898..f434f8dd2f770d 100644 --- a/packages/components/src/tools-panel/tools-panel-item/hook.ts +++ b/packages/components/src/tools-panel/tools-panel-item/hook.ts @@ -9,12 +9,12 @@ import { useEffect, useMemo } from '@wordpress/element'; */ import * as styles from '../styles'; import { useToolsPanelContext } from '../context'; -import { useContextSystem, PolymorphicComponentProps } from '../../ui/context'; +import { useContextSystem, WordPressComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelItemProps } from '../types'; export function useToolsPanelItem( - props: PolymorphicComponentProps< ToolsPanelItemProps, 'div' > + props: WordPressComponentProps< ToolsPanelItemProps, 'div' > ) { const { className, diff --git a/packages/components/src/tools-panel/tools-panel/component.tsx b/packages/components/src/tools-panel/tools-panel/component.tsx index 9b4629ba877ce7..77199630ed72c2 100644 --- a/packages/components/src/tools-panel/tools-panel/component.tsx +++ b/packages/components/src/tools-panel/tools-panel/component.tsx @@ -11,11 +11,11 @@ import ToolsPanelHeader from '../tools-panel-header'; import { ToolsPanelContext } from '../context'; import { useToolsPanel } from './hook'; import { View } from '../../view'; -import { contextConnect, PolymorphicComponentProps } from '../../ui/context'; +import { contextConnect, WordPressComponentProps } from '../../ui/context'; import type { ToolsPanelProps } from '../types'; const ToolsPanel = ( - props: PolymorphicComponentProps< ToolsPanelProps, 'div' >, + props: WordPressComponentProps< ToolsPanelProps, 'div' >, forwardedRef: Ref< any > ) => { const { diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index 49e77c116d2bc0..b4f62f3f129b73 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -7,7 +7,7 @@ import { useEffect, useMemo, useRef, useState } from '@wordpress/element'; * Internal dependencies */ import * as styles from '../styles'; -import { useContextSystem, PolymorphicComponentProps } from '../../ui/context'; +import { useContextSystem, WordPressComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelProps, ToolsPanelItem } from '../types'; @@ -23,7 +23,7 @@ const generateMenuItems = ( { panelItems, reset } ) => { }; export function useToolsPanel( - props: PolymorphicComponentProps< ToolsPanelProps, 'div' > + props: WordPressComponentProps< ToolsPanelProps, 'div' > ) { const { className, resetAll, panelId, ...otherProps } = useContextSystem( props, From 8d9d8d77eb9306a9aab99c08615fa2f330af60b7 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 15 Sep 2021 16:52:55 +1200 Subject: [PATCH 08/22] Fix type issues following rebase --- packages/components/src/menu-item/types.ts | 4 +++ .../src/tools-panel/tools-panel/hook.ts | 5 ++-- packages/components/src/tools-panel/types.ts | 27 ++++++++++++++----- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/packages/components/src/menu-item/types.ts b/packages/components/src/menu-item/types.ts index 16ee90524dad52..7c98489d348833 100644 --- a/packages/components/src/menu-item/types.ts +++ b/packages/components/src/menu-item/types.ts @@ -35,4 +35,8 @@ export type Props = { * Handler for click events. */ onClick?: () => void; + /** + * Flag to indicate if the menu item is disabled. + */ + disabled?: boolean; }; diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index b4f62f3f129b73..ddf15a44bc1402 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -57,7 +57,7 @@ export function useToolsPanel( // 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 ) => { + const deregisterPanelItem = ( 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 @@ -73,7 +73,7 @@ export function useToolsPanel( // This is intended for use with default panel items. They are displayed // separately to optional items and have different display states, //.we need to update that when their value is customized. - const flagItemCustomization = ( label, group = 'default' ) => { + const flagItemCustomization = ( label: string, group = 'default' ) => { setMenuItems( { ...menuItems, [ group ]: { @@ -94,7 +94,6 @@ export function useToolsPanel( filters.push( item.resetAllFilter ); } } ); - return filters; }; diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index 67a2d0133bca62..45a9a19e66e081 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -4,36 +4,49 @@ // eslint-disable-next-line no-restricted-imports import type { ReactNode } from 'react'; +type ResetAll = ( filters?: any[] ) => void; +type PanelId = string; +type ResetAllFilter = () => void; +type Label = string; + export interface ToolsPanelProps { - label: string; + panelId: PanelId; + label: Label; header: string; children: ReactNode; - resetAll: () => void; + resetAll: ResetAll; className?: string; } export interface ToolsPanelHeaderProps { - menuLabel: string; - header: string; - resetAll: () => void; + label: Label; + resetAll: ResetAll; toggleItem: ( label: string ) => void; - className?: string; } export interface ToolsPanelItem { hasValue: () => boolean; isShownByDefault: boolean; - label: string; + label: Label; + resetAllFilter: ResetAllFilter; + panelId: PanelId; } export interface ToolsPanelItemProps extends ToolsPanelItem { + panelId: PanelId; children?: ReactNode; onDeselect?: () => void; onSelect?: () => void; className?: string; + resetAllFilter: ResetAllFilter; } export interface TPContext { + panelId?: PanelId; menuItems?: { [ key: string ]: boolean }; + hasMenuItems?: number; registerPanelItem?: ( item: ToolsPanelItem ) => void; + deregisterPanelItem?: ( label: Label ) => void; + flagItemCustomization?: ( label: Label ) => void; + isResetting?: boolean; } From ee69bf88696a1453b2a73afdf2212ac875adb259 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 15 Sep 2021 17:05:29 +1200 Subject: [PATCH 09/22] fix remaining menu item type issues --- packages/components/src/menu-item/types.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/components/src/menu-item/types.ts b/packages/components/src/menu-item/types.ts index 7c98489d348833..c425bad140d2c2 100644 --- a/packages/components/src/menu-item/types.ts +++ b/packages/components/src/menu-item/types.ts @@ -36,7 +36,15 @@ export type Props = { */ onClick?: () => void; /** - * Flag to indicate if the menu item is disabled. + * Flag to indicate if the menu item is disabled. This prop is passed down to the underlying menu component */ disabled?: boolean; + /** + * String that is passed down to the underlying button component to use for aria label'. + */ + label?: string; + /** + * String that is passed down to the underlying button component to specify the button style. + */ + variant?: string; }; From 1174878527ac2c172f323c2a9e2241683b8f8f3f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 16 Sep 2021 15:44:50 +1200 Subject: [PATCH 10/22] Improve menu item types --- packages/components/src/dropdown-menu/types.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/components/src/dropdown-menu/types.ts b/packages/components/src/dropdown-menu/types.ts index 11a621177508b7..39ab526ddd873a 100644 --- a/packages/components/src/dropdown-menu/types.ts +++ b/packages/components/src/dropdown-menu/types.ts @@ -4,6 +4,12 @@ // eslint-disable-next-line no-restricted-imports import type { ReactNode } from 'react'; +interface DropdownMenuControl { + icon: string; + title: string; + isDisabled: boolean; + onClick: () => void; +} export type Props = { /** * The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug to be shown in the collapsed menu button. @@ -21,14 +27,14 @@ export type Props = { * human-readable `title` string, `isDisabled` boolean flag and an `onClick` function callback to invoke when the option is selected. * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. */ - controls?: number; + controls?: Array< DropdownMenuControl >; /** * A [function render prop](https://reactjs.org/docs/render-props.html#using-props-other-than-render) which should return an element or * elements valid for use in a DropdownMenu: `MenuItem`, `MenuItemsChoice`, or `MenuGroup`. Its first argument is a props object including * the same values as given to a [`Dropdown`'s `renderContent`](/packages/components/src/dropdown#rendercontent) (`isOpen`, `onToggle`, `onClose`). * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. */ - children?: ReactNode; + children?: ( props: any ) => ReactNode; /** * A class name to apply to the dropdown menu's toggle element wrapper. * From 19dec18154093abc59150281b1ead2b747712014 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 17 Sep 2021 13:28:05 +1000 Subject: [PATCH 11/22] Move remaining eligible ToolsPanel files to TS --- packages/components/src/tools-panel/{index.js => index.ts} | 0 packages/components/src/tools-panel/{styles.js => styles.ts} | 0 .../src/tools-panel/tools-panel-header/{index.js => index.ts} | 0 .../src/tools-panel/tools-panel-item/{index.js => index.ts} | 0 .../components/src/tools-panel/tools-panel/{index.js => index.ts} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename packages/components/src/tools-panel/{index.js => index.ts} (100%) rename packages/components/src/tools-panel/{styles.js => styles.ts} (100%) rename packages/components/src/tools-panel/tools-panel-header/{index.js => index.ts} (100%) rename packages/components/src/tools-panel/tools-panel-item/{index.js => index.ts} (100%) rename packages/components/src/tools-panel/tools-panel/{index.js => index.ts} (100%) diff --git a/packages/components/src/tools-panel/index.js b/packages/components/src/tools-panel/index.ts similarity index 100% rename from packages/components/src/tools-panel/index.js rename to packages/components/src/tools-panel/index.ts diff --git a/packages/components/src/tools-panel/styles.js b/packages/components/src/tools-panel/styles.ts similarity index 100% rename from packages/components/src/tools-panel/styles.js rename to packages/components/src/tools-panel/styles.ts diff --git a/packages/components/src/tools-panel/tools-panel-header/index.js b/packages/components/src/tools-panel/tools-panel-header/index.ts similarity index 100% rename from packages/components/src/tools-panel/tools-panel-header/index.js rename to packages/components/src/tools-panel/tools-panel-header/index.ts diff --git a/packages/components/src/tools-panel/tools-panel-item/index.js b/packages/components/src/tools-panel/tools-panel-item/index.ts similarity index 100% rename from packages/components/src/tools-panel/tools-panel-item/index.js rename to packages/components/src/tools-panel/tools-panel-item/index.ts diff --git a/packages/components/src/tools-panel/tools-panel/index.js b/packages/components/src/tools-panel/tools-panel/index.ts similarity index 100% rename from packages/components/src/tools-panel/tools-panel/index.js rename to packages/components/src/tools-panel/tools-panel/index.ts From bb89386b05cd47046f1eb85fc3cd779ba76d67c4 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 17 Sep 2021 13:31:21 +1000 Subject: [PATCH 12/22] Revert "Improve menu item types" This reverts commit 2676061b2f68577eb65cc977d28baab85694f057. --- packages/components/src/dropdown-menu/types.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/components/src/dropdown-menu/types.ts b/packages/components/src/dropdown-menu/types.ts index 39ab526ddd873a..11a621177508b7 100644 --- a/packages/components/src/dropdown-menu/types.ts +++ b/packages/components/src/dropdown-menu/types.ts @@ -4,12 +4,6 @@ // eslint-disable-next-line no-restricted-imports import type { ReactNode } from 'react'; -interface DropdownMenuControl { - icon: string; - title: string; - isDisabled: boolean; - onClick: () => void; -} export type Props = { /** * The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug to be shown in the collapsed menu button. @@ -27,14 +21,14 @@ export type Props = { * human-readable `title` string, `isDisabled` boolean flag and an `onClick` function callback to invoke when the option is selected. * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. */ - controls?: Array< DropdownMenuControl >; + controls?: number; /** * A [function render prop](https://reactjs.org/docs/render-props.html#using-props-other-than-render) which should return an element or * elements valid for use in a DropdownMenu: `MenuItem`, `MenuItemsChoice`, or `MenuGroup`. Its first argument is a props object including * the same values as given to a [`Dropdown`'s `renderContent`](/packages/components/src/dropdown#rendercontent) (`isOpen`, `onToggle`, `onClose`). * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. */ - children?: ( props: any ) => ReactNode; + children?: ReactNode; /** * A class name to apply to the dropdown menu's toggle element wrapper. * From 8369760cd83e2f336d7c2329608104eb1de16095 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 17 Sep 2021 13:32:12 +1000 Subject: [PATCH 13/22] Revert "Add typing for dropdown menu" This reverts commit 81c00480d842383b1e20b39a508540ac27c22854. --- .../components/src/dropdown-menu/index.js | 4 +- .../components/src/dropdown-menu/types.ts | 66 ------------------- 2 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 packages/components/src/dropdown-menu/types.ts diff --git a/packages/components/src/dropdown-menu/index.js b/packages/components/src/dropdown-menu/index.js index 5b2ab82a855622..c3cd6ad969d3fd 100644 --- a/packages/components/src/dropdown-menu/index.js +++ b/packages/components/src/dropdown-menu/index.js @@ -32,9 +32,7 @@ function mergeProps( defaultProps = {}, props = {} ) { return mergedProps; } -/** - * @param {import('./types').Props} props - */ + function DropdownMenu( { children, className, diff --git a/packages/components/src/dropdown-menu/types.ts b/packages/components/src/dropdown-menu/types.ts deleted file mode 100644 index 11a621177508b7..00000000000000 --- a/packages/components/src/dropdown-menu/types.ts +++ /dev/null @@ -1,66 +0,0 @@ -/** - * External dependencies - */ -// eslint-disable-next-line no-restricted-imports -import type { ReactNode } from 'react'; - -export type Props = { - /** - * The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug to be shown in the collapsed menu button. - */ - icon?: JSX.Element; - /** - * A human-readable label to present as accessibility text on the focused collapsed menu button.. - * - * @default 'inherit' - */ - label: string; - /** - * An array of objects describing the options to be shown in the expanded menu. - * Each object should include an `icon` [Dashicon](https://developer.wordpress.org/resource/dashicons/) slug string, a - * human-readable `title` string, `isDisabled` boolean flag and an `onClick` function callback to invoke when the option is selected. - * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. - */ - controls?: number; - /** - * A [function render prop](https://reactjs.org/docs/render-props.html#using-props-other-than-render) which should return an element or - * elements valid for use in a DropdownMenu: `MenuItem`, `MenuItemsChoice`, or `MenuGroup`. Its first argument is a props object including - * the same values as given to a [`Dropdown`'s `renderContent`](/packages/components/src/dropdown#rendercontent) (`isOpen`, `onToggle`, `onClose`). - * A valid DropdownMenu must specify one or the other of a `controls` or `children` prop. - */ - children?: ReactNode; - /** - * A class name to apply to the dropdown menu's toggle element wrapper. - * - */ - className?: string; - /** - * Properties of `popoverProps` object will be passed as props to the nested `Popover` component. - * Use this object to modify props available for the `Popover` component that are not already exposed in the `DropdownMenu` component, - * e.g.: the direction in which the popover should open relative to its parent node set with `position` prop. - * - */ - popoverProps?: object; - /** - * Properties of `toggleProps` object will be passed as props to the nested `Button` component in the `renderToggle` implementation of the - * `Dropdown` component used internally. - * Use this object to modify props available for the `Button` component that are not already exposed in the `DropdownMenu` component, e.g.: - * the tooltip text displayed on hover set with `tooltip` prop. - * - */ - toggleProps?: object; - /** - * Properties of `menuProps` object will be passed as props to the nested `NavigableMenu` component in the `renderContent` implementation of - * the `Dropdown` component used internally. - * Use this object to modify props available for the `NavigableMenu` component that are not already exposed in the `DropdownMenu` component, e.g.: - * the orientation of the menu set with `orientation` prop.p.p. - * - */ - menuProps?: object; - /** - * In some contexts, the arrow down key used to open the dropdown menu might need to be disabled—for example when that key is used to perform - * another action. - * - */ - disableOpenOnArrowDown?: boolean; -}; From d853e9a87b7374e43c4fb621591c2756164f3830 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 17 Sep 2021 14:57:48 +1000 Subject: [PATCH 14/22] Remove menu group and item type doc block annotations --- packages/components/src/menu-group/index.js | 7 --- packages/components/src/menu-group/types.ts | 24 ---------- packages/components/src/menu-item/index.js | 13 ++++-- packages/components/src/menu-item/types.ts | 50 --------------------- 4 files changed, 10 insertions(+), 84 deletions(-) delete mode 100644 packages/components/src/menu-group/types.ts delete mode 100644 packages/components/src/menu-item/types.ts diff --git a/packages/components/src/menu-group/index.js b/packages/components/src/menu-group/index.js index 6f880cce83da79..19e182ddc74ffe 100644 --- a/packages/components/src/menu-group/index.js +++ b/packages/components/src/menu-group/index.js @@ -9,13 +9,6 @@ import classnames from 'classnames'; import { Children } from '@wordpress/element'; import { useInstanceId } from '@wordpress/compose'; -/** - * Renders a generic menu item for use inside the more menu - * - * @param {import('./types').Props} props - * - * @return {WPComponent} The component to be rendered. - */ export function MenuGroup( { children, className = '', diff --git a/packages/components/src/menu-group/types.ts b/packages/components/src/menu-group/types.ts deleted file mode 100644 index c4e878a2ef8b6a..00000000000000 --- a/packages/components/src/menu-group/types.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * External dependencies - */ -// eslint-disable-next-line no-restricted-imports -import type { ReactNode } from 'react'; - -export type Props = { - /** - * Element to render as child of button. - */ - children?: ReactNode; - /** - * Optional classname string to add to wrapper div - */ - className?: string; - /** - * Optional label to display. - */ - label?: string; - /** - * Whether or not to show a separator between items. - */ - hideSeparator?: boolean; -}; diff --git a/packages/components/src/menu-item/index.js b/packages/components/src/menu-item/index.js index 89a16df6d46e1e..8bed60d84df8f7 100644 --- a/packages/components/src/menu-item/index.js +++ b/packages/components/src/menu-item/index.js @@ -17,10 +17,17 @@ import Button from '../button'; import Icon from '../icon'; /** - * Renders a generic menu item for use inside the more menu + * Renders a generic menu item for use inside the more menu. * - * @param {import('./types').Props} props - * @param {Object} ref React Element ref. + * @param {Object} props Component props. + * @param {WPElement} props.children Element to render as child of button. + * @param {string} props.info Text to use as description for button text. + * @param {string} props.className Class to set on the container. + * @param {WPIcon} props.icon Button's `icon` prop. + * @param {string|Object} props.shortcut Shortcut's `shortcut` prop. + * @param {boolean} props.isSelected Whether or not the menu item is currently selected. + * @param {string} [props.role="menuitem"] ARIA role of the menu item. + * @param {Object} ref React Element ref. * * @return {WPComponent} The component to be rendered. */ diff --git a/packages/components/src/menu-item/types.ts b/packages/components/src/menu-item/types.ts deleted file mode 100644 index c425bad140d2c2..00000000000000 --- a/packages/components/src/menu-item/types.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * External dependencies - */ -// eslint-disable-next-line no-restricted-imports -import type { ReactNode } from 'react'; - -export type Props = { - /** - * Element to render as child of button. - */ - children?: ReactNode; - /** - * Text to use as description for button text. - * Refer to documentation for [`label`](#label). - */ - info?: string; - /** - * Refer to documentation for [Button's `icon` prop](/packages/components/src/icon-button/README.md#icon). - */ - icon?: string | JSX.Element; - /** - * Whether or not the menu item is currently selected. - */ - isSelected?: boolean; - /** - * Refer to documentation for [Shortcut's `shortcut` prop](/packages/components/src/shortcut/README.md#shortcut). - */ - shortcut?: string; - /** - * [Aria Spec](https://www.w3.org/TR/wai-aria-1.1/#aria-checked). If you need to have selectable menu items use menuitemradio for - * single select, and menuitemcheckbox for multiselect. - */ - role?: string; - /** - * Handler for click events. - */ - onClick?: () => void; - /** - * Flag to indicate if the menu item is disabled. This prop is passed down to the underlying menu component - */ - disabled?: boolean; - /** - * String that is passed down to the underlying button component to use for aria label'. - */ - label?: string; - /** - * String that is passed down to the underlying button component to specify the button style. - */ - variant?: string; -}; From 19bdce71490d5371ece2def5d422e7f95fbc9329 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 17 Sep 2021 14:59:27 +1000 Subject: [PATCH 15/22] Add ts-nocheck to ToolsPanelHeader The typing for DropdownMenu, MenuGroup and MenuItem will be handled separately and may entail a full TypeScript conversion rather than only doc block annotations. --- .../src/tools-panel/tools-panel-header/component.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index 50f6b1564aa8fe..2ef7ab290c5049 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -1,3 +1,7 @@ +// This can be removed once typing has been completed for DropdownMenu, +// MenuGroup & MenuItem. +// @ts-nocheck + /** * External dependencies */ From bce9e125e661df09bdad1acd66bb536fd87826ef Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 20 Sep 2021 14:41:21 +1000 Subject: [PATCH 16/22] Move ts-nocheck to dependencies and fix type errors --- .../components/src/dropdown-menu/index.js | 29 +++++---- packages/components/src/dropdown/index.js | 1 + packages/components/src/menu-group/index.js | 9 +-- packages/components/src/menu-item/index.js | 29 +++------ .../src/navigable-container/container.js | 1 + .../src/navigable-container/index.js | 1 + .../src/navigable-container/menu.js | 1 + .../src/navigable-container/tabbable.js | 1 + .../components/src/tools-panel/context.ts | 3 +- .../tools-panel-header/component.tsx | 19 +++--- .../src/tools-panel/tools-panel-item/hook.ts | 6 +- .../src/tools-panel/tools-panel/hook.ts | 59 +++++++++++++------ packages/components/src/tools-panel/types.ts | 19 +++++- packages/components/tsconfig.json | 6 ++ 14 files changed, 113 insertions(+), 71 deletions(-) diff --git a/packages/components/src/dropdown-menu/index.js b/packages/components/src/dropdown-menu/index.js index c3cd6ad969d3fd..85983f92305aca 100644 --- a/packages/components/src/dropdown-menu/index.js +++ b/packages/components/src/dropdown-menu/index.js @@ -1,3 +1,4 @@ +// @ts-nocheck /** * External dependencies */ @@ -33,19 +34,21 @@ function mergeProps( defaultProps = {}, props = {} ) { return mergedProps; } -function DropdownMenu( { - children, - className, - controls, - icon = menu, - label, - popoverProps, - toggleProps, - menuProps, - disableOpenOnArrowDown = false, - text, - noIcons, -} ) { +function DropdownMenu( dropdownMenuProps ) { + const { + children, + className, + controls, + icon = menu, + label, + popoverProps, + toggleProps, + menuProps, + disableOpenOnArrowDown = false, + text, + noIcons, + } = dropdownMenuProps; + if ( isEmpty( controls ) && ! isFunction( children ) ) { return null; } diff --git a/packages/components/src/dropdown/index.js b/packages/components/src/dropdown/index.js index ebee9c2b5abd3c..09477a87e0509b 100644 --- a/packages/components/src/dropdown/index.js +++ b/packages/components/src/dropdown/index.js @@ -1,3 +1,4 @@ +// @ts-nocheck /** * External dependencies */ diff --git a/packages/components/src/menu-group/index.js b/packages/components/src/menu-group/index.js index 19e182ddc74ffe..6054bfcb3e4e29 100644 --- a/packages/components/src/menu-group/index.js +++ b/packages/components/src/menu-group/index.js @@ -1,3 +1,4 @@ +// @ts-nocheck /** * External dependencies */ @@ -9,12 +10,8 @@ import classnames from 'classnames'; import { Children } from '@wordpress/element'; import { useInstanceId } from '@wordpress/compose'; -export function MenuGroup( { - children, - className = '', - label, - hideSeparator, -} ) { +export function MenuGroup( props ) { + const { children, className = '', label, hideSeparator } = props; const instanceId = useInstanceId( MenuGroup ); if ( ! Children.count( children ) ) { diff --git a/packages/components/src/menu-item/index.js b/packages/components/src/menu-item/index.js index 8bed60d84df8f7..f8a97b801b0a02 100644 --- a/packages/components/src/menu-item/index.js +++ b/packages/components/src/menu-item/index.js @@ -1,3 +1,4 @@ +// @ts-nocheck /** * External dependencies */ @@ -16,23 +17,8 @@ import Shortcut from '../shortcut'; import Button from '../button'; import Icon from '../icon'; -/** - * Renders a generic menu item for use inside the more menu. - * - * @param {Object} props Component props. - * @param {WPElement} props.children Element to render as child of button. - * @param {string} props.info Text to use as description for button text. - * @param {string} props.className Class to set on the container. - * @param {WPIcon} props.icon Button's `icon` prop. - * @param {string|Object} props.shortcut Shortcut's `shortcut` prop. - * @param {boolean} props.isSelected Whether or not the menu item is currently selected. - * @param {string} [props.role="menuitem"] ARIA role of the menu item. - * @param {Object} ref React Element ref. - * - * @return {WPComponent} The component to be rendered. - */ -export function MenuItem( - { +export function MenuItem( props, ref ) { + let { children, info, className, @@ -40,10 +26,9 @@ export function MenuItem( shortcut, isSelected, role = 'menuitem', - ...props - }, - ref -) { + ...buttonProps + } = props; + className = classnames( 'components-menu-item__button', className ); if ( info ) { @@ -72,7 +57,7 @@ export function MenuItem( } role={ role } className={ className } - { ...props } + { ...buttonProps } > { children } ( {} ); -export const useToolsPanelContext = () => useContext( ToolsPanelContext ); +export const useToolsPanelContext = () => + useContext< TPContext >( ToolsPanelContext ); diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index 2ef7ab290c5049..d739f295228aa7 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -1,7 +1,3 @@ -// This can be removed once typing has been completed for DropdownMenu, -// MenuGroup & MenuItem. -// @ts-nocheck - /** * External dependencies */ @@ -22,9 +18,14 @@ import MenuGroup from '../../menu-group'; import MenuItem from '../../menu-item'; import { useToolsPanelHeader } from './hook'; import { contextConnect, WordPressComponentProps } from '../../ui/context'; -import type { ToolsPanelHeaderProps } from '../types'; +import type { + ToolsPanelControlsGroupProps, + ToolsPanelHeaderProps, +} from '../types'; + +const DefaultControlsGroup = ( props: ToolsPanelControlsGroupProps ) => { + const { items, onClose, toggleItem } = props; -const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { if ( ! items.length ) { return null; } @@ -62,7 +63,9 @@ const DefaultControlsGroup = ( { items, onClose, toggleItem } ) => { ); }; -const OptionalControlsGroup = ( { items, onClose, toggleItem } ) => { +const OptionalControlsGroup = ( props: ToolsPanelControlsGroupProps ) => { + const { items, onClose, toggleItem } = props; + if ( ! items.length ) { return null; } @@ -132,7 +135,7 @@ const ToolsPanelHeader = ( label={ labelText } menuProps={ { className: dropdownMenuClassName } } > - { ( { onClose } ) => ( + { ( { onClose = () => undefined } ) => ( <> undefined, + deregisterPanelItem = () => undefined, + flagItemCustomization = () => undefined, isResetting, } = useToolsPanelContext(); diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index ddf15a44bc1402..9ed1cdd2c764a7 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -9,12 +9,20 @@ import { useEffect, useMemo, useRef, useState } from '@wordpress/element'; import * as styles from '../styles'; import { useContextSystem, WordPressComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; -import type { ToolsPanelProps, ToolsPanelItem } from '../types'; - -const generateMenuItems = ( { panelItems, reset } ) => { - const menuItems = { default: {}, optional: {} }; - - panelItems.forEach( ( { hasValue, isShownByDefault, label } ) => { +import type { + ToolsPanelItem, + ToolsPanelMenuItemKey, + ToolsPanelMenuItems, + ToolsPanelMenuItemsConfig, + ToolsPanelProps, +} from '../types'; + +const generateMenuItems = ( config: ToolsPanelMenuItemsConfig ) => { + const { panelItems, reset } = config; + const menuItems: ToolsPanelMenuItems = { default: {}, optional: {} }; + + panelItems.forEach( ( panelItem: ToolsPanelItem ) => { + const { hasValue, isShownByDefault, label } = panelItem; const group = isShownByDefault ? 'default' : 'optional'; menuItems[ group ][ label ] = reset ? false : hasValue(); } ); @@ -49,7 +57,7 @@ export function useToolsPanel( }, [ wasResetting ] ); // Allow panel items to register themselves. - const [ panelItems, setPanelItems ] = useState( [] ); + const [ panelItems, setPanelItems ] = useState( [] ); const registerPanelItem = ( item: ToolsPanelItem ) => { setPanelItems( ( items ) => [ ...items, item ] ); @@ -62,7 +70,9 @@ export function useToolsPanel( // 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. - const index = panelItems.findIndex( ( item ) => item.label === label ); + const index = panelItems.findIndex( + ( item: ToolsPanelItem ) => item.label === label + ); if ( index !== -1 ) { setPanelItems( ( items ) => items.splice( index, 1 ) ); @@ -73,7 +83,10 @@ export function useToolsPanel( // This is intended for use with default panel items. They are displayed // separately to optional items and have different display states, //.we need to update that when their value is customized. - const flagItemCustomization = ( label: string, group = 'default' ) => { + const flagItemCustomization = ( + label: string, + group: ToolsPanelMenuItemKey = 'default' + ) => { setMenuItems( { ...menuItems, [ group ]: { @@ -84,12 +97,15 @@ export function useToolsPanel( }; // Manage and share display state of menu items representing child controls. - const [ menuItems, setMenuItems ] = useState( {} ); + const [ menuItems, setMenuItems ] = useState< ToolsPanelMenuItems >( { + default: {}, + optional: {}, + } ); const getResetAllFilters = () => { - const filters = []; + const filters: Array< Function > = []; - panelItems.forEach( ( item ) => { + panelItems.forEach( ( item: ToolsPanelItem ) => { if ( item.resetAllFilter ) { filters.push( item.resetAllFilter ); } @@ -99,28 +115,37 @@ export function useToolsPanel( // Setup menuItems state as panel items register themselves. useEffect( () => { - const items = generateMenuItems( { panelItems, reset: false } ); + const items: ToolsPanelMenuItems = generateMenuItems( { + panelItems, + reset: false, + } ); setMenuItems( items ); }, [ panelItems ] ); // Toggle the checked state of a menu item which is then used to determine // display of the item within the panel. const toggleItem = ( label: string ) => { - const currentItem = panelItems.find( ( item ) => item.label === label ); + const currentItem: ToolsPanelItem | undefined = panelItems.find( + ( item: ToolsPanelItem ) => item.label === label + ); if ( ! currentItem ) { return; } - const menuGroup = currentItem.isShownByDefault ? 'default' : 'optional'; + const menuGroup: ToolsPanelMenuItemKey = currentItem.isShownByDefault + ? 'default' + : 'optional'; - setMenuItems( { + const newMenuItems: ToolsPanelMenuItems = { ...menuItems, [ menuGroup ]: { ...menuItems[ menuGroup ], [ label ]: ! menuItems[ menuGroup ][ label ], }, - } ); + }; + + setMenuItems( newMenuItems ); }; // Resets display of children and executes resetAll callback if available. diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index 45a9a19e66e081..d7e0e997604ef4 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -41,12 +41,29 @@ export interface ToolsPanelItemProps extends ToolsPanelItem { resetAllFilter: ResetAllFilter; } +export type ToolsPanelMenuItemKey = 'default' | 'optional'; + +export type ToolsPanelMenuItems = { + [ menuItemKey in ToolsPanelMenuItemKey ]: { [ key: string ]: boolean }; +}; + export interface TPContext { panelId?: PanelId; - menuItems?: { [ key: string ]: boolean }; + menuItems?: ToolsPanelMenuItems; hasMenuItems?: number; registerPanelItem?: ( item: ToolsPanelItem ) => void; deregisterPanelItem?: ( label: Label ) => void; flagItemCustomization?: ( label: Label ) => void; isResetting?: boolean; } + +export interface ToolsPanelControlsGroupProps { + items: [ string, boolean ][]; + onClose: () => void; + toggleItem: ( label: Label ) => void; +} + +export interface ToolsPanelMenuItemsConfig { + panelItems: ToolsPanelItem[]; + reset: boolean; +} diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index a0a0e879a3066f..cd26b356e617e0 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -31,6 +31,8 @@ "src/disabled/**/*", "src/divider/**/*", "src/draggable/**/*", + "src/dropdown/**/*", + "src/dropdown-menu/**/*", "src/elevation/**/*", "src/flex/**/*", "src/flyout/**/*", @@ -41,6 +43,9 @@ "src/item-group/**/*", "src/input-control/**/*", "src/icon/**/*", + "src/menu-item/**/*", + "src/menu-group/**/*", + "src/navigable-container/**/*", "src/number-control/**/*", "src/popover/**/*", "src/range-control/**/*", @@ -55,6 +60,7 @@ "src/text/**/*", "src/tip/**/*", "src/toggle-group-control/**/*", + "src/tools-panel/**/*", "src/tooltip/**/*", "src/truncate/**/*", "src/ui/**/*", From 87127dbf684068b4564abdcb4a1dd74bae6a0632 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Tue, 21 Sep 2021 13:11:23 +1000 Subject: [PATCH 17/22] Improve typing of ToolsPanel Removes redundant typing, improves naming and adds JSDocs etc --- .../components/src/tools-panel/context.ts | 13 +- .../tools-panel-header/component.tsx | 18 ++- .../src/tools-panel/tools-panel-item/hook.ts | 14 +- .../src/tools-panel/tools-panel/hook.ts | 84 ++++++------ packages/components/src/tools-panel/types.ts | 127 +++++++++++++----- 5 files changed, 165 insertions(+), 91 deletions(-) diff --git a/packages/components/src/tools-panel/context.ts b/packages/components/src/tools-panel/context.ts index 30a1e2d0e87364..32ae49c373d77d 100644 --- a/packages/components/src/tools-panel/context.ts +++ b/packages/components/src/tools-panel/context.ts @@ -6,8 +6,15 @@ import { createContext, useContext } from '@wordpress/element'; /** * Internal dependencies */ -import type { TPContext } from './types'; +import type { ToolsPanelContext as ToolsPanelContextType } from './types'; + +const noop = () => undefined; + +export const ToolsPanelContext = createContext< ToolsPanelContextType >( { + registerPanelItem: noop, + deregisterPanelItem: noop, + flagItemCustomization: noop, +} ); -export const ToolsPanelContext = createContext< TPContext >( {} ); export const useToolsPanelContext = () => - useContext< TPContext >( ToolsPanelContext ); + useContext< ToolsPanelContextType >( ToolsPanelContext ); diff --git a/packages/components/src/tools-panel/tools-panel-header/component.tsx b/packages/components/src/tools-panel/tools-panel-header/component.tsx index d739f295228aa7..3204615434b4b3 100644 --- a/packages/components/src/tools-panel/tools-panel-header/component.tsx +++ b/packages/components/src/tools-panel/tools-panel-header/component.tsx @@ -23,9 +23,13 @@ import type { ToolsPanelHeaderProps, } from '../types'; -const DefaultControlsGroup = ( props: ToolsPanelControlsGroupProps ) => { - const { items, onClose, toggleItem } = props; +const noop = () => {}; +const DefaultControlsGroup = ( { + items, + onClose, + toggleItem, +}: ToolsPanelControlsGroupProps ) => { if ( ! items.length ) { return null; } @@ -63,9 +67,11 @@ const DefaultControlsGroup = ( props: ToolsPanelControlsGroupProps ) => { ); }; -const OptionalControlsGroup = ( props: ToolsPanelControlsGroupProps ) => { - const { items, onClose, toggleItem } = props; - +const OptionalControlsGroup = ( { + items, + onClose, + toggleItem, +}: ToolsPanelControlsGroupProps ) => { if ( ! items.length ) { return null; } @@ -135,7 +141,7 @@ const ToolsPanelHeader = ( label={ labelText } menuProps={ { className: dropdownMenuClassName } } > - { ( { onClose = () => undefined } ) => ( + { ( { onClose = noop } ) => ( <> undefined; + export function useToolsPanelItem( props: WordPressComponentProps< ToolsPanelItemProps, 'div' > ) { @@ -23,22 +25,22 @@ export function useToolsPanelItem( label, panelId, resetAllFilter, - onDeselect = () => undefined, - onSelect = () => undefined, + onDeselect = noop, + onSelect = noop, ...otherProps } = useContextSystem( props, 'ToolsPanelItem' ); const cx = useCx(); const classes = useMemo( () => { return cx( styles.ToolsPanelItem, className ); - }, [ styles.ToolsPanelItem, className ] ); + }, [ className ] ); const { panelId: currentPanelId, menuItems, - registerPanelItem = () => undefined, - deregisterPanelItem = () => undefined, - flagItemCustomization = () => undefined, + registerPanelItem, + deregisterPanelItem, + flagItemCustomization, isResetting, } = useToolsPanelContext(); diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index 9ed1cdd2c764a7..2c73eeb09af20a 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -17,14 +17,15 @@ import type { ToolsPanelProps, } from '../types'; -const generateMenuItems = ( config: ToolsPanelMenuItemsConfig ) => { - const { panelItems, reset } = config; +const generateMenuItems = ( { + panelItems, + shouldReset, +}: ToolsPanelMenuItemsConfig ) => { const menuItems: ToolsPanelMenuItems = { default: {}, optional: {} }; - panelItems.forEach( ( panelItem: ToolsPanelItem ) => { - const { hasValue, isShownByDefault, label } = panelItem; + panelItems.forEach( ( { hasValue, isShownByDefault, label } ) => { const group = isShownByDefault ? 'default' : 'optional'; - menuItems[ group ][ label ] = reset ? false : hasValue(); + menuItems[ group ][ label ] = shouldReset ? false : hasValue(); } ); return menuItems; @@ -57,7 +58,7 @@ export function useToolsPanel( }, [ wasResetting ] ); // Allow panel items to register themselves. - const [ panelItems, setPanelItems ] = useState( [] ); + const [ panelItems, setPanelItems ] = useState< ToolsPanelItem[] >( [] ); const registerPanelItem = ( item: ToolsPanelItem ) => { setPanelItems( ( items ) => [ ...items, item ] ); @@ -70,15 +71,28 @@ export function useToolsPanel( // 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. - const index = panelItems.findIndex( - ( item: ToolsPanelItem ) => item.label === label - ); + const index = panelItems.findIndex( ( item ) => item.label === label ); if ( index !== -1 ) { setPanelItems( ( items ) => items.splice( index, 1 ) ); } }; + // Manage and share display state of menu items representing child controls. + const [ menuItems, setMenuItems ] = useState< ToolsPanelMenuItems >( { + default: {}, + optional: {}, + } ); + + // Setup menuItems state as panel items register themselves. + useEffect( () => { + const items = generateMenuItems( { + panelItems, + shouldReset: false, + } ); + setMenuItems( items ); + }, [ panelItems ] ); + // Force a menu item to be checked. // This is intended for use with default panel items. They are displayed // separately to optional items and have different display states, @@ -96,48 +110,18 @@ export function useToolsPanel( } ); }; - // Manage and share display state of menu items representing child controls. - const [ menuItems, setMenuItems ] = useState< ToolsPanelMenuItems >( { - default: {}, - optional: {}, - } ); - - const getResetAllFilters = () => { - const filters: Array< Function > = []; - - panelItems.forEach( ( item: ToolsPanelItem ) => { - if ( item.resetAllFilter ) { - filters.push( item.resetAllFilter ); - } - } ); - return filters; - }; - - // Setup menuItems state as panel items register themselves. - useEffect( () => { - const items: ToolsPanelMenuItems = generateMenuItems( { - panelItems, - reset: false, - } ); - setMenuItems( items ); - }, [ panelItems ] ); - // Toggle the checked state of a menu item which is then used to determine // display of the item within the panel. const toggleItem = ( label: string ) => { - const currentItem: ToolsPanelItem | undefined = panelItems.find( - ( item: ToolsPanelItem ) => item.label === label - ); + const currentItem = panelItems.find( ( item ) => item.label === label ); if ( ! currentItem ) { return; } - const menuGroup: ToolsPanelMenuItemKey = currentItem.isShownByDefault - ? 'default' - : 'optional'; + const menuGroup = currentItem.isShownByDefault ? 'default' : 'optional'; - const newMenuItems: ToolsPanelMenuItems = { + const newMenuItems = { ...menuItems, [ menuGroup ]: { ...menuItems[ menuGroup ], @@ -148,6 +132,17 @@ export function useToolsPanel( setMenuItems( newMenuItems ); }; + const getResetAllFilters = () => { + const filters: Array< () => void > = []; + + panelItems.forEach( ( item ) => { + if ( item.resetAllFilter ) { + filters.push( item.resetAllFilter ); + } + } ); + return filters; + }; + // Resets display of children and executes resetAll callback if available. const resetAllItems = () => { if ( typeof resetAll === 'function' ) { @@ -156,7 +151,10 @@ export function useToolsPanel( } // Turn off display of all non-default items. - const resetMenuItems = generateMenuItems( { panelItems, reset: true } ); + const resetMenuItems = generateMenuItems( { + panelItems, + shouldReset: true, + } ); setMenuItems( resetMenuItems ); }; diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index d7e0e997604ef4..26cac32266866e 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -4,42 +4,103 @@ // eslint-disable-next-line no-restricted-imports import type { ReactNode } from 'react'; -type ResetAll = ( filters?: any[] ) => void; -type PanelId = string; type ResetAllFilter = () => void; -type Label = string; +type ResetAll = ( filters?: ResetAllFilter[] ) => void; -export interface ToolsPanelProps { - panelId: PanelId; - label: Label; - header: string; +export type ToolsPanelProps = { + /** + * The child elements. + */ children: ReactNode; + /** + * Text to be displayed within the panel's header and as the `aria-label` + * for the panel's dropdown menu. + */ + label: string; + /** + * If a `panelId` is set, it is passed through the `ToolsPanelContext` and + * used to restrict panel items. Only items with a matching `panelId` will + * be able to register themselves with this panel. + */ + panelId: string; + /** + * A function to call when the `Reset all` menu option is selected. This is + * passed through to the panel's header component. + */ resetAll: ResetAll; - className?: string; -} +}; -export interface ToolsPanelHeaderProps { - label: Label; +export type ToolsPanelHeaderProps = { + /** + * Text to be displayed within the panel header. It is also passed along as + * the `label` for the panel header's `DropdownMenu`. + */ + label: string; + /** + * The `resetAll` prop provides the callback to execute when the "Reset all" + * menu item is selected. Its purpose is to facilitate resetting any control + * values for items contained within this header's panel. + */ resetAll: ResetAll; + /** + * This is executed when an individual control's menu item is toggled. It + * will update the panel's menu item state and call the panel item's + * `onSelect` or `onDeselect` callbacks as appropriate. + */ toggleItem: ( label: string ) => void; -} +}; -export interface ToolsPanelItem { +export type ToolsPanelItem = { + /** + * This is called when building the `ToolsPanel` menu to determine the + * item's initial checked state. + */ hasValue: () => boolean; + /** + * This prop identifies the current item as being displayed by default. This + * means it will show regardless of whether it has a value set or is toggled + * on in the panel's menu. + */ isShownByDefault: boolean; - label: Label; + /** + * The supplied label is dual purpose. It is used as: + * 1. the human-readable label for the panel's dropdown menu + * 2. a key to locate the corresponding item in the panel's menu context to + * determine if the panel item should be displayed. + * A panel item's `label` should be unique among all items within a single + * panel. + */ + label: string; + /** + * Panel items will ensure they are only registering with their intended + * panel by comparing the `panelId` props set on both the item and the panel + * itself. This allows items to be injected from a shared source. + */ + panelId: string; + /** + * A `ToolsPanel` will collect each item's `resetAllFilter` and pass an + * array of these functions through to the panel's `resetAll` callback. They + * can then be iterated over to perform additional tasks. + */ resetAllFilter: ResetAllFilter; - panelId: PanelId; -} +}; -export interface ToolsPanelItemProps extends ToolsPanelItem { - panelId: PanelId; +export type ToolsPanelItemProps = ToolsPanelItem & { + /** + * The child elements. + */ children?: ReactNode; + /** + * Called when this item is deselected in the `ToolsPanel` menu. This is + * normally used to reset the panel item control's value. + */ onDeselect?: () => void; + /** + * A callback to take action when this item is selected in the `ToolsPanel` + * menu. + */ onSelect?: () => void; - className?: string; - resetAllFilter: ResetAllFilter; -} +}; export type ToolsPanelMenuItemKey = 'default' | 'optional'; @@ -47,23 +108,23 @@ export type ToolsPanelMenuItems = { [ menuItemKey in ToolsPanelMenuItemKey ]: { [ key: string ]: boolean }; }; -export interface TPContext { - panelId?: PanelId; +export type ToolsPanelContext = { + panelId?: string; menuItems?: ToolsPanelMenuItems; hasMenuItems?: number; - registerPanelItem?: ( item: ToolsPanelItem ) => void; - deregisterPanelItem?: ( label: Label ) => void; - flagItemCustomization?: ( label: Label ) => void; + registerPanelItem: ( item: ToolsPanelItem ) => void; + deregisterPanelItem: ( label: string ) => void; + flagItemCustomization: ( label: string ) => void; isResetting?: boolean; -} +}; -export interface ToolsPanelControlsGroupProps { +export type ToolsPanelControlsGroupProps = { items: [ string, boolean ][]; onClose: () => void; - toggleItem: ( label: Label ) => void; -} + toggleItem: ( label: string ) => void; +}; -export interface ToolsPanelMenuItemsConfig { +export type ToolsPanelMenuItemsConfig = { panelItems: ToolsPanelItem[]; - reset: boolean; -} + shouldReset: boolean; +}; From 6c4180e1f8e8901f35730641590b607eaf5a7c41 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Tue, 21 Sep 2021 16:15:10 +1000 Subject: [PATCH 18/22] Add missing dependencies to tools panel item hook In order to prevent excessive renders and guard against consumers not memoizing the hasValue and resetAllFilter functions, these changes include useCallback calls to handle this before adding them to the hook dependencies. --- .../src/tools-panel/tools-panel-item/hook.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.ts b/packages/components/src/tools-panel/tools-panel-item/hook.ts index 09ff678d62b5c8..caea9c5045841c 100644 --- a/packages/components/src/tools-panel/tools-panel-item/hook.ts +++ b/packages/components/src/tools-panel/tools-panel-item/hook.ts @@ -2,7 +2,7 @@ * WordPress dependencies */ import { usePrevious } from '@wordpress/compose'; -import { useEffect, useMemo } from '@wordpress/element'; +import { useCallback, useEffect, useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -44,21 +44,31 @@ export function useToolsPanelItem( isResetting, } = useToolsPanelContext(); + const hasValueCallback = useCallback( hasValue, [ panelId ] ); + const resetAllFilterCallback = useCallback( resetAllFilter, [ panelId ] ); + // Registering the panel item allows the panel to include it in its // automatically generated menu and determine its initial checked status. useEffect( () => { if ( currentPanelId === panelId ) { registerPanelItem( { - hasValue, + hasValue: hasValueCallback, isShownByDefault, label, - resetAllFilter, + resetAllFilter: resetAllFilterCallback, panelId, } ); } return () => deregisterPanelItem( label ); - }, [ panelId ] ); + }, [ + currentPanelId, + panelId, + isShownByDefault, + label, + hasValueCallback, + resetAllFilterCallback, + ] ); const isValueSet = hasValue(); const wasValueSet = usePrevious( isValueSet ); From 19cd49498d814d755af9fa1aad2fc2812d283758 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 22 Sep 2021 12:39:36 +1000 Subject: [PATCH 19/22] Use optional chaining for onSelect and onDeselect calls --- .../src/tools-panel/tools-panel-item/hook.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.ts b/packages/components/src/tools-panel/tools-panel-item/hook.ts index caea9c5045841c..57189eea3916a7 100644 --- a/packages/components/src/tools-panel/tools-panel-item/hook.ts +++ b/packages/components/src/tools-panel/tools-panel-item/hook.ts @@ -13,8 +13,6 @@ import { useContextSystem, WordPressComponentProps } from '../../ui/context'; import { useCx } from '../../utils/hooks/use-cx'; import type { ToolsPanelItemProps } from '../types'; -const noop = () => undefined; - export function useToolsPanelItem( props: WordPressComponentProps< ToolsPanelItemProps, 'div' > ) { @@ -25,8 +23,8 @@ export function useToolsPanelItem( label, panelId, resetAllFilter, - onDeselect = noop, - onSelect = noop, + onDeselect, + onSelect, ...otherProps } = useContextSystem( props, 'ToolsPanelItem' ); @@ -95,11 +93,11 @@ export function useToolsPanelItem( } if ( isMenuItemChecked && ! isValueSet && ! wasMenuItemChecked ) { - onSelect(); + onSelect?.(); } if ( ! isMenuItemChecked && wasMenuItemChecked ) { - onDeselect(); + onDeselect?.(); } }, [ isMenuItemChecked, wasMenuItemChecked, isValueSet, isResetting ] ); From f061db7e35806068d692fde289c67442750cd05b Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 22 Sep 2021 12:52:42 +1000 Subject: [PATCH 20/22] Add TypeScript types for function props in READMEs --- .../src/tools-panel/tools-panel-header/README.md | 4 ++-- .../components/src/tools-panel/tools-panel-item/README.md | 8 ++++---- packages/components/src/tools-panel/tools-panel/README.md | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/components/src/tools-panel/tools-panel-header/README.md b/packages/components/src/tools-panel/tools-panel-header/README.md index 90c50006dca29e..07a7544b6b1435 100644 --- a/packages/components/src/tools-panel/tools-panel-header/README.md +++ b/packages/components/src/tools-panel/tools-panel-header/README.md @@ -25,7 +25,7 @@ Text to be displayed within the panel header. It is also passed along as the - Required: Yes -### `resetAll`: `function` +### `resetAll`: `() => void` The `resetAll` prop provides the callback to execute when the "Reset all" menu item is selected. Its purpose is to facilitate resetting any control values @@ -33,7 +33,7 @@ for items contained within this header's panel. - Required: Yes -### `toggleItem`: `function` +### `toggleItem`: `( label: string ) => void` This is executed when an individual control's menu item is toggled. It will update the panel's menu item state and call the panel item's `onSelect` or diff --git a/packages/components/src/tools-panel/tools-panel-item/README.md b/packages/components/src/tools-panel/tools-panel-item/README.md index 35a5fae6dba44f..85d03f96d1d04f 100644 --- a/packages/components/src/tools-panel/tools-panel-item/README.md +++ b/packages/components/src/tools-panel/tools-panel-item/README.md @@ -18,7 +18,7 @@ for how to use `ToolsPanelItem`. ## Props -### `hasValue`: `function` +### `hasValue`: `() => boolean` This is called when building the `ToolsPanel` menu to determine the item's initial checked state. @@ -45,14 +45,14 @@ A panel item's `label` should be unique among all items within a single panel. - Required: Yes -### `onDeselect`: `function` +### `onDeselect`: `() => void` Called when this item is deselected in the `ToolsPanel` menu. This is normally used to reset the panel item control's value. - Required: No -### `onSelect`: `function` +### `onSelect`: `() => void` A callback to take action when this item is selected in the `ToolsPanel` menu. @@ -66,7 +66,7 @@ allows items to be injected from a shared source. - Required: No -### `resetAllFilter`: `function` +### `resetAllFilter`: `() => void` A `ToolsPanel` will collect each item's `resetAllFilter` and pass an array of these functions through to the panel's `resetAll` callback. They can then be diff --git a/packages/components/src/tools-panel/tools-panel/README.md b/packages/components/src/tools-panel/tools-panel/README.md index 889950361eb2f6..de56ab3bdd5c96 100644 --- a/packages/components/src/tools-panel/tools-panel/README.md +++ b/packages/components/src/tools-panel/tools-panel/README.md @@ -74,7 +74,7 @@ panel's dropdown menu. - Required: Yes -### `panelId`: `function` +### `panelId`: `string` If a `panelId` is set, it is passed through the `ToolsPanelContext` and used to restrict panel items. Only items with a matching `panelId` will be able @@ -82,7 +82,7 @@ to register themselves with this panel. - Required: No -### `resetAll`: `function` +### `resetAll`: `() => void` A function to call when the `Reset all` menu option is selected. This is passed through to the panel's header component. From d4674f1c53496f536ac5067b8930844abefd97e6 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 22 Sep 2021 12:55:41 +1000 Subject: [PATCH 21/22] Enforce boolean for hasMenuItems in ToolsPanelContext --- packages/components/src/tools-panel/tools-panel/hook.ts | 2 +- packages/components/src/tools-panel/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/tools-panel/tools-panel/hook.ts b/packages/components/src/tools-panel/tools-panel/hook.ts index 2c73eeb09af20a..9aacf97ed26fa3 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.ts +++ b/packages/components/src/tools-panel/tools-panel/hook.ts @@ -164,7 +164,7 @@ export function useToolsPanel( registerPanelItem, deregisterPanelItem, flagItemCustomization, - hasMenuItems: panelItems.length, + hasMenuItems: !! panelItems.length, isResetting: isResetting.current, }; diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index 26cac32266866e..6669d91350159c 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -111,7 +111,7 @@ export type ToolsPanelMenuItems = { export type ToolsPanelContext = { panelId?: string; menuItems?: ToolsPanelMenuItems; - hasMenuItems?: number; + hasMenuItems?: boolean; registerPanelItem: ( item: ToolsPanelItem ) => void; deregisterPanelItem: ( label: string ) => void; flagItemCustomization: ( label: string ) => void; From 1f833abb0b28db8de07c1f0a103a549d959e83b3 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 22 Sep 2021 13:01:06 +1000 Subject: [PATCH 22/22] Make all properties except panelId mandatory in ToolsPanelContext --- packages/components/src/tools-panel/context.ts | 3 +++ packages/components/src/tools-panel/types.ts | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/components/src/tools-panel/context.ts b/packages/components/src/tools-panel/context.ts index 32ae49c373d77d..5627b458efa25d 100644 --- a/packages/components/src/tools-panel/context.ts +++ b/packages/components/src/tools-panel/context.ts @@ -11,6 +11,9 @@ import type { ToolsPanelContext as ToolsPanelContextType } from './types'; const noop = () => undefined; export const ToolsPanelContext = createContext< ToolsPanelContextType >( { + menuItems: { default: {}, optional: {} }, + hasMenuItems: false, + isResetting: false, registerPanelItem: noop, deregisterPanelItem: noop, flagItemCustomization: noop, diff --git a/packages/components/src/tools-panel/types.ts b/packages/components/src/tools-panel/types.ts index 6669d91350159c..f763fe13e1ce80 100644 --- a/packages/components/src/tools-panel/types.ts +++ b/packages/components/src/tools-panel/types.ts @@ -110,12 +110,12 @@ export type ToolsPanelMenuItems = { export type ToolsPanelContext = { panelId?: string; - menuItems?: ToolsPanelMenuItems; - hasMenuItems?: boolean; + menuItems: ToolsPanelMenuItems; + hasMenuItems: boolean; registerPanelItem: ( item: ToolsPanelItem ) => void; deregisterPanelItem: ( label: string ) => void; flagItemCustomization: ( label: string ) => void; - isResetting?: boolean; + isResetting: boolean; }; export type ToolsPanelControlsGroupProps = {