Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item: remove isAction, use onClick to discriminate if it should render as button #35152

Merged
merged 7 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Removed the deprecated `position` and `menuLabel` from the `DropdownMenu` component ([#34537](https://github.com/WordPress/gutenberg/pull/34537)).
- Removed the deprecated `onClickOutside` prop from the `Popover` component ([#34537](https://github.com/WordPress/gutenberg/pull/34537)).
- Changed `RangeControl` component to not apply `shiftStep` to inputs from its `<input type="range"/>` ([35020](https://github.com/WordPress/gutenberg/pull/35020)).
- Removed `isAction` prop from `Item`. The component will now rely on `onClick` to render as a `button` ([35152](https://github.com/WordPress/gutenberg/pull/35152)).

### New Feature

Expand Down
5 changes: 2 additions & 3 deletions packages/components/src/item-group/item/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ function Example() {

## Props

### `isAction`: `boolean`
### `onClick`: `React.MouseEventHandler<HTMLDivElement>`

Renders the item as an interactive `button` element.
Even handler for processing `click` events. When defined, the `Item` component will render as a `button` (unless differently specified via the `as` prop).

- Required: No
- Default: `false`

### `size`: `'small' | 'medium' | 'large'`

Expand Down
30 changes: 22 additions & 8 deletions packages/components/src/item-group/item/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
// eslint-disable-next-line no-restricted-imports
import type { ElementType } from 'react';

/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
Expand All @@ -15,9 +20,9 @@ import type { ItemProps } from '../types';

export function useItem( props: WordPressComponentProps< ItemProps, 'div' > ) {
const {
isAction = false,
as: asProp,
className,
onClick,
role = 'listitem',
size: sizeProp,
...otherProps
Expand All @@ -27,23 +32,32 @@ export function useItem( props: WordPressComponentProps< ItemProps, 'div' > ) {

const size = sizeProp || contextSize;

const as = ( asProp || isAction ? 'button' : 'div' ) as ElementType;
const as =
asProp ||
( ( typeof onClick !== 'undefined'
? 'button'
: 'div' ) as ElementType );

const cx = useCx();

const classes = cx(
isAction && styles.unstyledButton,
styles.itemSizes[ size ] || styles.itemSizes.medium,
styles.item,
spacedAround && styles.spacedAround,
className
const classes = useMemo(
() =>
cx(
as === 'button' && styles.unstyledButton,
styles.itemSizes[ size ] || styles.itemSizes.medium,
styles.item,
spacedAround && styles.spacedAround,
className
),
[ as, className, size, spacedAround ]
);

const wrapperClassName = cx( styles.itemWrapper );

return {
as,
className: classes,
onClick,
wrapperClassName,
role,
...otherProps,
Expand Down
30 changes: 11 additions & 19 deletions packages/components/src/item-group/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export const _default = () => {
},
PROP_UNSET
),
isAction: boolean( 'Item 1: isAction', true ),
};

// Do not pass the `size` prop when its value is `undefined`.
Expand All @@ -68,16 +67,14 @@ export const _default = () => {

return (
<ItemGroup style={ { width: '350px' } } { ...itemGroupProps }>
<Item { ...itemProps } onClick={ () => alert( 'WordPress.org' ) }>
<Item { ...itemProps }>Code is Poetry (no click handlers)</Item>
<Item onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
<Item onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
<Item onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
</ItemGroup>
Expand All @@ -90,16 +87,14 @@ export const dropdown = () => (
trigger={ <Button>Open Popover</Button> }
>
<ItemGroup style={ { padding: 4 } }>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
<Item>Code is Poetry (no click handlers)</Item>
<Item onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
<Item onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
<Item isAction onClick={ () => alert( 'WordPress.org' ) }>
<Item onClick={ () => alert( 'WordPress.org' ) }>
Code is Poetry — Click me!
</Item>
</ItemGroup>
Expand Down Expand Up @@ -141,7 +136,7 @@ export const complexLayouts = () => {

return (
<ItemGroup isBordered isSeparated style={ { width: '250px' } }>
<Item isAction onClick={ () => alert( 'Color palette' ) }>
<Item onClick={ () => alert( 'Color palette' ) }>
<HStack>
<FlexBlock>
<ZStack isLayered={ false } offset={ -8 }>
Expand All @@ -156,7 +151,7 @@ export const complexLayouts = () => {
</HStack>
</Item>

<Item isAction onClick={ () => alert( 'Single color setting' ) }>
<Item onClick={ () => alert( 'Single color setting' ) }>
<HStack justify="flex-start">
<FlexItem
as={ SimpleColorSwatch }
Expand All @@ -169,10 +164,7 @@ export const complexLayouts = () => {
</HStack>
</Item>

<Item
isAction
onClick={ () => alert( 'Single typography setting' ) }
>
<Item onClick={ () => alert( 'Single typography setting' ) }>
<HStack justify="flex-start">
<FlexItem>
<Icon icon={ typography } size={ 24 } />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,6 @@ Snapshot Diff:
</div>
`;

exports[`ItemGroup Item should render a button with the isAction prop is true 1`] = `
Snapshot Diff:
- First value
+ Second value

<div
class="css-dcjs67-itemWrapper"
role="listitem"
>
- <div
- class="components-item css-gqguxs-View-medium-itemWrapper em57xhy0"
+ <button
+ class="components-item css-1t39803-View-unstyledButton-medium-itemWrapper em57xhy0"
data-wp-c16t="true"
data-wp-component="Item"
>
Code is poetry
- </div>
+ </button>
</div>
`;

exports[`ItemGroup Item should use different amounts of padding depending on the value of the size prop 1`] = `
Snapshot Diff:
- First value
Expand Down
38 changes: 28 additions & 10 deletions packages/components/src/item-group/test/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';
import { fireEvent, render, screen } from '@testing-library/react';

/**
* Internal dependencies
Expand Down Expand Up @@ -79,18 +79,36 @@ describe( 'ItemGroup', () => {
} );

describe( 'Item', () => {
it( 'should render a button with the isAction prop is true', () => {
// By default, `isAction` is `false`
const { container: normalItem } = render(
<Item>Code is poetry</Item>
);
const { container: actionItem } = render(
<Item isAction={ true }>Code is poetry</Item>
it( 'should render as a `button` if the `onClick` handler is specified', () => {
const spy = jest.fn();
render( <Item onClick={ spy }>Code is poetry</Item> );

const button = screen.getByRole( 'button' );

expect( button ).toBeInTheDocument();

fireEvent.click( button );

expect( spy ).toHaveBeenCalled();
} );

it( 'should give priority to the `as` prop even if the `onClick` handler is specified', () => {
const spy = jest.fn();
const { rerender } = render(
<Item onClick={ spy }>Code is poetry</Item>
);

expect( normalItem.firstChild ).toMatchDiffSnapshot(
actionItem.firstChild
expect( screen.getByRole( 'button' ) ).toBeInTheDocument();
expect( screen.queryByRole( 'label' ) ).not.toBeInTheDocument();

rerender(
<Item as="a" href="#" onClick={ spy }>
Code is poetry
</Item>
);

expect( screen.queryByRole( 'button' ) ).not.toBeInTheDocument();
expect( screen.getByRole( 'link' ) ).toBeInTheDocument();
} );

it( 'should use different amounts of padding depending on the value of the size prop', () => {
Expand Down
6 changes: 0 additions & 6 deletions packages/components/src/item-group/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ export interface ItemGroupProps {
}

export interface ItemProps {
/**
* Renders the item as an interactive `button` element.
*
* @default false
*/
isAction?: boolean;
/**
* Determines the amount of padding within the component.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,7 @@ function NavigationButton( {
} ) {
const navigator = useNavigator();
return (
<Item
isAction
onClick={ () => navigator.push( path, { isBack } ) }
{ ...props }
>
<Item onClick={ () => navigator.push( path, { isBack } ) } { ...props }>
<HStack justify="flex-start">
{ icon && (
<FlexItem>
Expand Down