Skip to content

Commit

Permalink
Components: promote ItemGroup (#33701)
Browse files Browse the repository at this point in the history
  • Loading branch information
ciampo committed Jul 29, 2021
1 parent f0b55c2 commit 85cfab1
Show file tree
Hide file tree
Showing 20 changed files with 634 additions and 61 deletions.
12 changes: 12 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,18 @@
"markdown_source": "../packages/components/src/isolated-event-container/README.md",
"parent": "components"
},
{
"title": "ItemGroup",
"slug": "item-group",
"markdown_source": "../packages/components/src/item-group/item-group/README.md",
"parent": "components"
},
{
"title": "Item",
"slug": "item",
"markdown_source": "../packages/components/src/item-group/item/README.md",
"parent": "components"
},
{
"title": "KeyboardShortcuts",
"slug": "keyboard-shortcuts",
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export { Heading as __experimentalHeading } from './heading';
export { HStack as __experimentalHStack } from './h-stack';
export { default as Icon } from './icon';
export { default as IconButton } from './button/deprecated';
export {
ItemGroup as __experimentalItemGroup,
Item as __experimentalItem,
} from './item-group';
export { default as __experimentalInputControl } from './input-control';
export { default as KeyboardShortcuts } from './keyboard-shortcuts';
export { default as MenuGroup } from './menu-group';
Expand Down
File renamed without changes.
78 changes: 78 additions & 0 deletions packages/components/src/item-group/item-group/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# `ItemGroup`

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
</div>

`ItemGroup` displays a list of `Item`s grouped and styled together.

## Usage

`ItemGroup` should be used in combination with the [`Item` sub-component](/packages/components/src/item-group/item/README.md).

```jsx
import {
__experimentalItemGroup as ItemGroup,
__experimentalItem as Item,
} from '@wordpress/components';

function Example() {
return (
<ItemGroup>
<Item>Code</Item>
<Item>is</Item>
<Item>Poetry</Item>
</ItemGroup>
);
}
```

## Props

### `isBordered`: `boolean`

Renders borders around each items.

- Required: No
- Default: `false`

### `isRounded`: `boolean`

Renders with rounded corners.

- Required: No
- Default: `true`

### `isSeparated`: `boolean`

Renders items individually. Even if `isBordered` is `false`, a border in between each item will be still be displayed.

- Required: No
- Default: `false`

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

Determines the amount of padding within the component.
When not defined, it defaults to the value from the context (which is `medium` by default).

- Required: No
- Default: `medium`

### Context

The [`Item` sub-component](/packages/components/src/item-group/item/README.md) is connected to `<ItemGroup />` using [Context](https://reactjs.org/docs/context.html). Therefore, `Item` receives the `size` prop from the `ItemGroup` parent component.

In the following example, the `<Item />` will render with a size of `small`:

```jsx
import {
__experimentalItemGroup as ItemGroup,
__experimentalItem as Item,
} from '@wordpress/components';

const Example = () => (
<ItemGroup size="small">
<Item>Item text</Item>
</ItemGroup>
);
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ import type { Ref } from 'react';
/**
* Internal dependencies
*/
import type { PolymorphicComponentProps } from '../context';
// eslint-disable-next-line no-duplicate-imports
import { contextConnect } from '../context';
import { useItemGroup } from './use-item-group';
import { ItemGroupContext, useItemGroupContext } from './context';
import { contextConnect, PolymorphicComponentProps } from '../../ui/context';
import { useItemGroup } from './hook';
import { ItemGroupContext, useItemGroupContext } from '../context';
import { View } from '../../view';
import type { ItemGroupProps } from './types';
import type { ItemGroupProps } from '../types';

function ItemGroup(
props: PolymorphicComponentProps< ItemGroupProps, 'div' >,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/**
* Internal dependencies
*/
import { useContextSystem } from '../context';
// eslint-disable-next-line no-duplicate-imports
import type { PolymorphicComponentProps } from '../context';
import { useContextSystem, PolymorphicComponentProps } from '../../ui/context';

/**
* Internal dependencies
*/
import * as styles from './styles';
import * as styles from '../styles';
import { useCx } from '../../utils/hooks/use-cx';
import type { ItemGroupProps } from './types';
import type { ItemGroupProps } from '../types';

export function useItemGroup(
props: PolymorphicComponentProps< ItemGroupProps, 'div' >
Expand All @@ -28,7 +26,7 @@ export function useItemGroup(

const classes = cx(
isBordered && styles.bordered,
( isBordered || isSeparated ) && styles.separated,
isSeparated && styles.separated,
isRounded && styles.rounded,
className
);
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/item-group/item-group/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './component';
export { useItemGroup } from './hook';
63 changes: 63 additions & 0 deletions packages/components/src/item-group/item/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# `Item`

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
</div>

`Item` is used in combination with `ItemGroup` to display a list of items grouped and styled together.

## Usage

`Item` should be used in combination with the [`ItemGroup` component](/packages/components/src/item-group/item-group/README.md).

```jsx
import {
__experimentalItemGroup as ItemGroup,
__experimentalItem as Item,
} from '@wordpress/components';

function Example() {
return (
<ItemGroup>
<Item>Code</Item>
<Item>is</Item>
<Item>Poetry</Item>
</ItemGroup>
);
}
```

## Props

### `isAction`: `boolean`

Renders the item as an interactive `button` element.

- Required: No
- Default: `false`

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

Determines the amount of padding within the component.

- Required: No
- Default: `medium`

### Context

`Item` is connected to [the `<ItemGroup />` parent component](/packages/components/src/item-group/item-group/README.md) using [Context](https://reactjs.org/docs/context.html). Therefore, `Item` receives the `size` prop from the `ItemGroup` parent component.

In the following example, the `<Item />` will render with a size of `small`:

```jsx
import {
__experimentalItemGroup as ItemGroup,
__experimentalItem as Item,
} from '@wordpress/components';

const Example = () => (
<ItemGroup size="small">
<Item>...</Item>
</ItemGroup>
);
```
28 changes: 28 additions & 0 deletions packages/components/src/item-group/item/component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* External dependencies
*/
// eslint-disable-next-line no-restricted-imports
import type { Ref } from 'react';

/**
* Internal dependencies
*/
import type { ItemProps } from '../types';
import { useItem } from './hook';
import { contextConnect, PolymorphicComponentProps } from '../../ui/context';
import { View } from '../../view';

function Item(
props: PolymorphicComponentProps< ItemProps, 'div' >,
forwardedRef: Ref< any >
) {
const { role, wrapperClassName, ...otherProps } = useItem( props );

return (
<div role={ role } className={ wrapperClassName }>
<View { ...otherProps } ref={ forwardedRef } />
</div>
);
}

export default contextConnect( Item, 'Item' );
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ import type { ElementType } from 'react';
/**
* Internal dependencies
*/
import { useContextSystem } from '../context';
// eslint-disable-next-line no-duplicate-imports
import type { PolymorphicComponentProps } from '../context';
import * as styles from './styles';
import { useItemGroupContext } from './context';
import { useContextSystem, PolymorphicComponentProps } from '../../ui/context';
import * as styles from '../styles';
import { useItemGroupContext } from '../context';
import { useCx } from '../../utils/hooks/use-cx';
import type { ItemProps } from './types';
import type { ItemProps } from '../types';

export function useItem(
props: PolymorphicComponentProps< ItemProps, 'div' >
Expand Down Expand Up @@ -43,9 +41,12 @@ export function useItem(
className
);

const wrapperClassName = cx( styles.itemWrapper );

return {
as,
className: classes,
wrapperClassName,
role,
...otherProps,
};
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/item-group/item/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './component';
export { useItem } from './hook';
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,52 @@ import { boolean, select } from '@storybook/addon-knobs';
* Internal dependencies
*/
import { ItemGroup, Item } from '..';
import { Flyout } from '../../../flyout';
import Button from '../../../button';
import { Flyout } from '../../flyout';
import Button from '../../button';

export default {
component: ItemGroup,
title: 'Components (Experimental)/ItemGroup',
};

// Using `unset` instead of `undefined` as Storybook seems to sometimes pass an
// empty string instead of `undefined`, which is not ideal.
// https://github.com/storybookjs/storybook/issues/800
const PROP_UNSET = 'unset';

export const _default = () => {
const itemGroupProps = {
isBordered: boolean( 'ItemGroup: isBordered', true ),
isBordered: boolean( 'ItemGroup: isBordered', false ),
isSeparated: boolean( 'ItemGroup: isSeparated', false ),
isRounded: boolean( 'ItemGroup: isRounded', true ),
size: select(
'ItemGroup: size',
[ 'small', 'medium', 'large' ],
'medium'
),
isSeparated: boolean( 'ItemGroup: isSeparated', false ),
isRounded: boolean( 'ItemGroup: isRounded', false ),
};

const itemProps = {
size: select(
'Item 1: size',
[ 'small', 'medium', 'large' ],
'medium'
{
'unset (defaults to the value set on the <ItemGroup> parent)': PROP_UNSET,
small: 'small',
medium: 'medium',
large: 'large',
},
PROP_UNSET
),
isAction: boolean( 'Item 1: isAction', true ),
};

// Do not pass the `size` prop when its value is `undefined`.
// This allows the `Item` component to use the values that are set on the
// parent `ItemGroup` component by default.
if ( itemProps.size === PROP_UNSET ) {
delete itemProps.size;
}

return (
<ItemGroup style={ { width: '350px' } } { ...itemGroupProps }>
<Item { ...itemProps } onClick={ () => alert( 'WordPress.org' ) }>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { css } from '@emotion/react';
/**
* Internal dependencies
*/
import { CONFIG } from '../../utils';
import COLORS from '../../utils/colors-values';
import { CONFIG, COLORS } from '../utils';

export const unstyledButton = css`
appearance: none;
Expand All @@ -28,21 +27,23 @@ export const unstyledButton = css`
}
`;

export const item = css`
export const itemWrapper = css`
width: 100%;
display: block;
`;

export const item = itemWrapper;

export const bordered = css`
border: 1px solid ${ CONFIG.surfaceBorderColor };
`;

export const separated = css`
> *:not( marquee ) {
> *:not( marquee ) > * {
border-bottom: 1px solid ${ CONFIG.surfaceBorderColor };
}
> *:last-of-type:not( :focus ) {
> *:last-of-type > *:not( :focus ) {
border-bottom-color: transparent;
}
`;
Expand All @@ -56,12 +57,12 @@ export const spacedAround = css`
export const rounded = css`
border-radius: ${ borderRadius };
> *:first-of-type {
> *:first-of-type > * {
border-top-left-radius: ${ borderRadius };
border-top-right-radius: ${ borderRadius };
}
> *:last-of-type {
> *:last-of-type > * {
border-bottom-left-radius: ${ borderRadius };
border-bottom-right-radius: ${ borderRadius };
}
Expand Down
Loading

0 comments on commit 85cfab1

Please sign in to comment.