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 4 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
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: 26 additions & 4 deletions packages/components/src/item-group/item/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,47 @@ import { useItemGroupContext } from '../context';
import { useCx } from '../../utils/hooks/use-cx';
import type { ItemProps } from '../types';

function useDeprecatedProps( {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we need this since this component is experimental and probably only used in Gutenberg.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ItemGroup was promoted in #33701 and released in Gutenberg 11.3, but it's always been marked as experimental and, as you said, doesn't probably any usages outside of Gutenberg. I will go ahead and remove all traces of isAction

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as,
isAction = false,
...otherProps
}: WordPressComponentProps< ItemProps, 'div' > ) {
let computedAs = as;

if ( isAction ) {
computedAs ??= 'button';
}

return {
...otherProps,
as: computedAs,
};
}

export function useItem( props: WordPressComponentProps< ItemProps, 'div' > ) {
const {
isAction = false,
as: asProp,
className,
onClick,
role = 'listitem',
size: sizeProp,
...otherProps
} = useContextSystem( props, 'Item' );
} = useContextSystem( useDeprecatedProps( props ), 'Item' );

const { spacedAround, size: contextSize } = useItemGroupContext();

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,
as === 'button' && styles.unstyledButton,
styles.itemSizes[ size ] || styles.itemSizes.medium,
styles.item,
spacedAround && styles.spacedAround,
Expand All @@ -44,6 +65,7 @@ export function useItem( props: WordPressComponentProps< ItemProps, 'div' > ) {
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
65 changes: 55 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 Expand Up @@ -132,5 +150,32 @@ describe( 'ItemGroup', () => {
largeSize.firstChild
);
} );

it( 'should render a button with the isAction prop is true', () => {
// By default, `isAction` is `false`
const { rerender } = render( <Item>Code is poetry</Item> );

expect( screen.queryByRole( 'button' ) ).not.toBeInTheDocument();

rerender( <Item isAction>Code is poetry</Item> );

expect( screen.getByRole( 'button' ) ).toBeInTheDocument();
} );

it( 'should give priority to the `as` prop even if the isAction prop is true', () => {
const { rerender } = render( <Item isAction>Code is poetry</Item> );

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

rerender(
<Item as="a" href="#" isAction>
Code is poetry
</Item>
);

expect( screen.queryByRole( 'button' ) ).not.toBeInTheDocument();
expect( screen.getByRole( 'link' ) ).toBeInTheDocument();
} );
} );
} );
13 changes: 7 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 All @@ -48,6 +42,13 @@ export interface ItemProps {
* The children elements.
*/
children: React.ReactNode;
/**
* Renders the item as an interactive `button` element.
*
* @default false
* @deprecated
*/
isAction?: boolean;
}

export type ItemGroupContext = {
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