Move experimental list components to experimental package (https://github.com/woocommerce/woocommerce-admin/pull/6950)
* Move experimental list components to experimental package * Update changelogs * Fix lint errors * Fix lint error * Update css lint * Fix test * Update package lock
This commit is contained in:
parent
820bf30e29
commit
812743d3ff
|
@ -4,8 +4,7 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import { Icon, check } from '@wordpress/icons';
|
||||
import { Button, Tooltip } from '@wordpress/components';
|
||||
import { Text } from '@woocommerce/experimental';
|
||||
import { __experimentalListItem as ListItem } from '@woocommerce/components';
|
||||
import { Text, ListItem } from '@woocommerce/experimental';
|
||||
import NoticeOutline from 'gridicons/dist/notice-outline';
|
||||
import classnames from 'classnames';
|
||||
|
||||
|
|
|
@ -5,16 +5,11 @@ import { __, _n, sprintf } from '@wordpress/i18n';
|
|||
import { useEffect, useRef } from '@wordpress/element';
|
||||
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import {
|
||||
EllipsisMenu,
|
||||
Badge,
|
||||
__experimentalList as List,
|
||||
__experimentalCollapsibleList as CollapsibleList,
|
||||
} from '@woocommerce/components';
|
||||
import { EllipsisMenu, Badge } from '@woocommerce/components';
|
||||
import { updateQueryString } from '@woocommerce/navigation';
|
||||
import { OPTIONS_STORE_NAME, ONBOARDING_STORE_NAME } from '@woocommerce/data';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { Text } from '@woocommerce/experimental';
|
||||
import { Text, List, CollapsibleList } from '@woocommerce/experimental';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
|
|
@ -10851,13 +10851,17 @@
|
|||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "7.14.0",
|
||||
"@wordpress/components": "10.2.0"
|
||||
"@wordpress/components": "10.2.0",
|
||||
"@wordpress/element": "2.19.0",
|
||||
"@wordpress/keycodes": "2.18.0",
|
||||
"classnames": "^2.3.1",
|
||||
"react-transition-group": "4.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.13.17",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.17.tgz",
|
||||
"integrity": "sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==",
|
||||
"version": "7.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz",
|
||||
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
|
@ -10949,6 +10953,17 @@
|
|||
"@babel/runtime": "7.14.0",
|
||||
"@wordpress/a11y": "2.15.2",
|
||||
"@wordpress/data": "4.26.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz",
|
||||
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@woocommerce/number": {
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
- SelectControl: automatically scroll to selected options when list is displayed. #6906
|
||||
- SelectControl: no longer auto selects on rendering list. #6906
|
||||
- Make `Search` accept synchronous `autocompleter.options`. #6884
|
||||
- Add new (experimental) collapsible list item to collapse list items. #6869
|
||||
- SelectControl: fix display of multiple selections without inline tags. #6862
|
||||
- Add new (experimental) list, and add depreciation notice for the current list. #6787
|
||||
- Add depreciation notice for the current list. #6787
|
||||
- Force `<SearchListItem>` form elements id to be unique. #6871
|
||||
- Add `controlId` and `name` props to `<SearchListItem>`. #6871
|
||||
- Minor styling tweaks and fixes to `<SearchListcontrol>`. #6871
|
||||
|
|
|
@ -25,13 +25,7 @@ export { default as Gravatar } from './gravatar';
|
|||
export { H, Section } from './section';
|
||||
export { default as ImageUpload } from './image-upload';
|
||||
export { default as Link } from './link';
|
||||
export {
|
||||
default as List,
|
||||
ExperimentalList as __experimentalList,
|
||||
ExperimentalListItem as __experimentalListItem,
|
||||
ExperimentalListItemCollapse as __experimentalListItemCollapse,
|
||||
ExperimentalCollapsibleList as __experimentalCollapsibleList,
|
||||
} from './list';
|
||||
export { default as List } from './list';
|
||||
export { default as MenuItem } from './ellipsis-menu/menu-item';
|
||||
export { default as MenuTitle } from './ellipsis-menu/menu-title';
|
||||
export { default as OrderStatus } from './order-status';
|
||||
|
|
|
@ -112,7 +112,3 @@ List.propTypes = {
|
|||
};
|
||||
|
||||
export default List;
|
||||
|
||||
export { ExperimentalListItem } from './experimental-list-item';
|
||||
export { ExperimentalList } from './experimental-list';
|
||||
export { ExperimentalCollapsibleList } from './collapsible-list';
|
||||
|
|
|
@ -1,278 +1,15 @@
|
|||
jest.mock( '../list-item', () => ( {
|
||||
__esModule: true,
|
||||
...jest.requireActual( '../list-item' ),
|
||||
handleKeyDown: jest.fn(),
|
||||
} ) );
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
waitForElementToBeRemoved,
|
||||
} from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import List, {
|
||||
ExperimentalList,
|
||||
ExperimentalListItem,
|
||||
ExperimentalCollapsibleList,
|
||||
} from '../index';
|
||||
import { handleKeyDown } from '../list-item';
|
||||
import List from '../index';
|
||||
|
||||
describe( 'List', () => {
|
||||
describe( 'Experimental List', () => {
|
||||
it( 'should render the new List which defaults to a ul component if items are not passed in', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalList>
|
||||
<div>Test</div>
|
||||
</ExperimentalList>
|
||||
);
|
||||
|
||||
expect( container.querySelector( 'ul' ) ).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should render children passed in', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalList>
|
||||
<div>Test</div>
|
||||
</ExperimentalList>
|
||||
);
|
||||
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
} );
|
||||
|
||||
it( 'should allow overriding the list type, and passing in arbitrary element props', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalList listType="ol" role="menu">
|
||||
<div>Test</div>
|
||||
</ExperimentalList>
|
||||
);
|
||||
|
||||
expect( container.querySelector( 'ol' ) ).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
describe( 'ExperimentalListItem', () => {
|
||||
it( 'should render children passed in', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalListItem>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
} );
|
||||
|
||||
it( 'allows disabling the gutter styling', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalListItem disableGutters>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.has-gutters' )
|
||||
).not.toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should disable animations by default and for unsupported values', () => {
|
||||
// disabled by default
|
||||
const { container, rerender } = render(
|
||||
<ExperimentalListItem>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.transitions-disabled' )
|
||||
).toBeInTheDocument();
|
||||
|
||||
// invalid value
|
||||
rerender(
|
||||
<ExperimentalListItem animation="bounce-up-and-down">
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.transitions-disabled' )
|
||||
).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should not disable animations if you provide a valid animation value', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalListItem animation="slide-right">
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.transitions-disabled' )
|
||||
).not.toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'supports onClick on the list item, and handles keyboard events', () => {
|
||||
const dummyOnClick = jest.fn();
|
||||
|
||||
const { container, queryByRole } = render(
|
||||
<ExperimentalListItem onClick={ dummyOnClick }>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
const listItem = container.querySelector(
|
||||
'.woocommerce-list__item'
|
||||
);
|
||||
|
||||
userEvent.click( listItem );
|
||||
|
||||
// it doesn't actually matter what key you hit here while handleKeyDown is mocked.
|
||||
userEvent.type( listItem, '{enter}' );
|
||||
|
||||
// TODO check that the button role was added.
|
||||
expect( queryByRole( 'button' ) ).toBeInTheDocument();
|
||||
expect( handleKeyDown ).toHaveBeenCalled();
|
||||
expect( dummyOnClick ).toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'includes correct ARIA roles and a11y attributes when the item has an action', () => {
|
||||
const clickHandler = jest.fn();
|
||||
render(
|
||||
<ExperimentalListItem onClick={ clickHandler }>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
const item = screen.getByRole( 'button' );
|
||||
expect( item ).toBeInTheDocument();
|
||||
expect( item ).toHaveAttribute( 'role', 'button' );
|
||||
expect( item ).toHaveAttribute( 'tabindex', '0' );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'ExperimentalListItemCollapse', () => {
|
||||
it( 'should not render its children intially, but an extra list footer with show text', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
>
|
||||
<div>Test</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
expect( container ).not.toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Show more items' );
|
||||
} );
|
||||
|
||||
it( 'should render list items when footer is clicked and trigger onExpand', () => {
|
||||
const onExpand = jest.fn();
|
||||
const onCollapse = jest.fn();
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
onExpand={ onExpand }
|
||||
onCollapse={ onCollapse }
|
||||
>
|
||||
<div>Test</div>
|
||||
<div>Test 2</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
const listItem = container.querySelector(
|
||||
'.list-item-collapse'
|
||||
);
|
||||
|
||||
userEvent.click( listItem );
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).not.toHaveTextContent( 'Show more items' );
|
||||
expect( container ).toHaveTextContent( 'Show less' );
|
||||
expect( onExpand ).toHaveBeenCalled();
|
||||
expect( onCollapse ).not.toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'should render minimum children if minChildrenToShow is set and show the rest on expand', () => {
|
||||
const onExpand = jest.fn();
|
||||
const onCollapse = jest.fn();
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
onExpand={ onExpand }
|
||||
onCollapse={ onCollapse }
|
||||
show={ 2 }
|
||||
>
|
||||
<div>Test</div>
|
||||
<div>Test 2</div>
|
||||
<div>Test 3</div>
|
||||
<div>Test 4</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).not.toHaveTextContent( 'Test 3' );
|
||||
expect( container ).not.toHaveTextContent( 'Test 4' );
|
||||
const listItem = container.querySelector(
|
||||
'.list-item-collapse'
|
||||
);
|
||||
|
||||
userEvent.click( listItem );
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).toHaveTextContent( 'Test 3' );
|
||||
expect( container ).toHaveTextContent( 'Test 4' );
|
||||
expect( container ).not.toHaveTextContent( 'Show more items' );
|
||||
expect( container ).toHaveTextContent( 'Show less' );
|
||||
expect( onExpand ).toHaveBeenCalled();
|
||||
expect( onCollapse ).not.toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'should correctly toggle the list', async () => {
|
||||
const onExpand = jest.fn();
|
||||
const onCollapse = jest.fn();
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
onExpand={ onExpand }
|
||||
onCollapse={ onCollapse }
|
||||
>
|
||||
<div id="test">Test</div>
|
||||
<div>Test 2</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
let listItem = container.querySelector( '.list-item-collapse' );
|
||||
|
||||
userEvent.click( listItem );
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).not.toHaveTextContent( 'Show more items' );
|
||||
expect( container ).toHaveTextContent( 'Show less' );
|
||||
|
||||
listItem = container.querySelector( '.list-item-collapse' );
|
||||
|
||||
userEvent.click( listItem );
|
||||
await waitForElementToBeRemoved(
|
||||
container.querySelector( '#test' )
|
||||
);
|
||||
expect( container ).not.toHaveTextContent( 'Test' );
|
||||
expect( container ).not.toHaveTextContent( 'Test 2' );
|
||||
expect( container ).toHaveTextContent( 'Show more items' );
|
||||
expect( container ).not.toHaveTextContent( 'Show less' );
|
||||
expect( onExpand ).toHaveBeenCalledTimes( 1 );
|
||||
expect( onCollapse ).toHaveBeenCalledTimes( 1 );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'Legacy List', () => {
|
||||
it( 'should have aria roles for items', () => {
|
||||
const clickHandler = jest.fn();
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
@import 'gravatar/style.scss';
|
||||
@import 'image-upload/style.scss';
|
||||
@import 'list/style.scss';
|
||||
@import 'list/collapsible-list/style.scss';
|
||||
@import 'order-status/style.scss';
|
||||
@import 'pagination/style.scss';
|
||||
@import 'pill/style.scss';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Unreleased
|
||||
|
||||
- Export component ExperimentalList and ExperimentalListItem as List and ListItem.
|
||||
- Add new (experimental) collapsible list item to collapse list items. #6869
|
||||
- Add new (experimental) list. #6787
|
||||
|
||||
# 1.0.0
|
||||
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
"react-native": "src/index",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.14.0",
|
||||
"@wordpress/components": "10.2.0"
|
||||
"@wordpress/components": "10.2.0",
|
||||
"@wordpress/element": "2.19.0",
|
||||
"@wordpress/keycodes": "2.18.0",
|
||||
"classnames": "^2.3.1",
|
||||
"react-transition-group": "4.4.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.woocommerce-list__item.list-item-collapse {
|
||||
.woocommerce-experimental-list__item.list-item-collapse {
|
||||
justify-content: space-between;
|
||||
|
||||
p {
|
|
@ -2,12 +2,19 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { CSSTransition } from 'react-transition-group';
|
||||
import { ENTER } from '@wordpress/keycodes';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { handleKeyDown } from './list-item';
|
||||
function handleKeyDown(
|
||||
event: React.KeyboardEvent< HTMLElement >,
|
||||
onClick?:
|
||||
| React.MouseEventHandler< HTMLElement >
|
||||
| React.KeyboardEventHandler< HTMLElement >
|
||||
) {
|
||||
if ( typeof onClick === 'function' && event.keyCode === ENTER ) {
|
||||
( onClick as React.KeyboardEventHandler< HTMLElement > )( event );
|
||||
}
|
||||
}
|
||||
|
||||
type CSSTransitionProps = {
|
||||
in: boolean;
|
||||
|
@ -73,7 +80,7 @@ export const ExperimentalListItem: React.FC< ListItemProps > = ( {
|
|||
// spread role props first, in case it is desired to override them
|
||||
{ ...roleProps }
|
||||
{ ...otherProps }
|
||||
className={ `woocommerce-list__item ${ tagClasses } ${ className }` }
|
||||
className={ `woocommerce-experimental-list__item ${ tagClasses } ${ className }` }
|
||||
>
|
||||
{ children }
|
||||
</li>
|
|
@ -26,7 +26,7 @@ export const ExperimentalList: React.FC< ListProps > = ( {
|
|||
return (
|
||||
<TransitionGroup
|
||||
component={ listType }
|
||||
className="woocommerce-list"
|
||||
className="woocommerce-experimental-list"
|
||||
{ ...otherProps }
|
||||
>
|
||||
{ /* Wrapping all children in a CSS Transition means no invalid props are passed to children and that anything can be animated. */ }
|
|
@ -0,0 +1,158 @@
|
|||
.woocommerce-experimental-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a.woocommerce-experimental-list__item {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.woocommerce-experimental-list__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
text-decoration: none;
|
||||
|
||||
&.has-gutters {
|
||||
padding: $gap $gap-large;
|
||||
}
|
||||
|
||||
&.has-action {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 1px $studio-wordpress-blue,
|
||||
inset 0 0 0 2px $studio-white;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
// transitions
|
||||
&:not(.transitions-disabled) {
|
||||
&.woocommerce-list__item-enter {
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
&.woocommerce-list__item-enter-active {
|
||||
opacity: 1;
|
||||
max-height: 100vh;
|
||||
transform: translateX(0%);
|
||||
transition: opacity 500ms, transform 500ms, max-height 500ms;
|
||||
}
|
||||
|
||||
&.woocommerce-list__item-exit {
|
||||
opacity: 1;
|
||||
max-height: 100vh;
|
||||
transform: translateX(0%);
|
||||
}
|
||||
|
||||
&.woocommerce-list__item-exit-active {
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
transform: translateX(50%);
|
||||
transition: opacity 500ms, transform 500ms, max-height 500ms;
|
||||
}
|
||||
}
|
||||
|
||||
> .woocommerce-list__item-inner {
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: $gap $gap-large;
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 1px $studio-wordpress-blue,
|
||||
inset 0 0 0 2px $studio-white;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-list__item-title {
|
||||
color: $studio-gray-90;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-content {
|
||||
margin-top: $gap-smallest;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #50575d;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-before {
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-after {
|
||||
margin-left: $gap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
$chevron-color: $gray-900;
|
||||
$background-color: $white;
|
||||
$background-color-hover: $gray-100;
|
||||
$border-color: $gray-100;
|
||||
$foreground-color: var(--wp-admin-theme-color);
|
||||
$foreground-color-hover: var(--wp-admin-theme-color);
|
||||
|
||||
background-color: $background-color;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid $border-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $background-color-hover;
|
||||
|
||||
.woocommerce-list__item-title {
|
||||
color: $foreground-color-hover;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-before > svg {
|
||||
fill: $foreground-color-hover;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-list__item-title {
|
||||
color: $foreground-color;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-before > svg {
|
||||
fill: $foreground-color;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-after > svg {
|
||||
fill: $chevron-color;
|
||||
}
|
||||
|
||||
&.is-complete {
|
||||
.woocommerce-task__icon {
|
||||
background-color: var(--wp-admin-theme-color);
|
||||
}
|
||||
|
||||
.woocommerce-list__item-title {
|
||||
color: $gray-700;
|
||||
}
|
||||
|
||||
.woocommerce-list__item-content {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-experimental-list__item-title {
|
||||
color: $studio-gray-80;
|
||||
}
|
||||
|
||||
.woocommerce-experimental-list__item-content {
|
||||
color: $studio-gray-50;
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
waitForElementToBeRemoved,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ExperimentalList } from '../experimental-list';
|
||||
import { ExperimentalListItem } from '../experimental-list-item';
|
||||
import { ExperimentalCollapsibleList } from '../collapsible-list';
|
||||
|
||||
describe( 'Experimental List', () => {
|
||||
it( 'should render the new List which defaults to a ul component if items are not passed in', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalList>
|
||||
<div>Test</div>
|
||||
</ExperimentalList>
|
||||
);
|
||||
|
||||
expect( container.querySelector( 'ul' ) ).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should render children passed in', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalList>
|
||||
<div>Test</div>
|
||||
</ExperimentalList>
|
||||
);
|
||||
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
} );
|
||||
|
||||
it( 'should allow overriding the list type, and passing in arbitrary element props', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalList listType="ol" role="menu">
|
||||
<div>Test</div>
|
||||
</ExperimentalList>
|
||||
);
|
||||
|
||||
expect( container.querySelector( 'ol' ) ).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
describe( 'ExperimentalListItem', () => {
|
||||
it( 'should render children passed in', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalListItem>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
} );
|
||||
|
||||
it( 'allows disabling the gutter styling', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalListItem disableGutters>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.has-gutters' )
|
||||
).not.toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should disable animations by default and for unsupported values', () => {
|
||||
// disabled by default
|
||||
const { container, rerender } = render(
|
||||
<ExperimentalListItem>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.transitions-disabled' )
|
||||
).toBeInTheDocument();
|
||||
|
||||
// invalid value
|
||||
rerender(
|
||||
<ExperimentalListItem animation="none">
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.transitions-disabled' )
|
||||
).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should not disable animations if you provide a valid animation value', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalListItem animation="slide-right">
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
expect(
|
||||
container.querySelector( '.transitions-disabled' )
|
||||
).not.toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'supports onClick on the list item, and handles keyboard events', () => {
|
||||
const dummyOnClick = jest.fn();
|
||||
|
||||
const { container, queryByRole } = render(
|
||||
<ExperimentalListItem onClick={ dummyOnClick }>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
const listItem = container.querySelector(
|
||||
'.woocommerce-experimental-list__item'
|
||||
);
|
||||
|
||||
if ( listItem ) {
|
||||
userEvent.click( listItem );
|
||||
|
||||
// it doesn't actually matter what key you hit here while handleKeyDown is mocked.
|
||||
userEvent.type( listItem, '{enter}' );
|
||||
}
|
||||
|
||||
// TODO check that the button role was added.
|
||||
expect( queryByRole( 'button' ) ).toBeInTheDocument();
|
||||
expect( dummyOnClick ).toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'includes correct ARIA roles and a11y attributes when the item has an action', () => {
|
||||
const clickHandler = jest.fn();
|
||||
render(
|
||||
<ExperimentalListItem onClick={ clickHandler }>
|
||||
<div>Test</div>
|
||||
</ExperimentalListItem>
|
||||
);
|
||||
|
||||
const item = screen.getByRole( 'button' );
|
||||
expect( item ).toBeInTheDocument();
|
||||
expect( item ).toHaveAttribute( 'role', 'button' );
|
||||
expect( item ).toHaveAttribute( 'tabindex', '0' );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'ExperimentalListItemCollapse', () => {
|
||||
it( 'should not render its children intially, but an extra list footer with show text', () => {
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
>
|
||||
<div>Test</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
expect( container ).not.toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Show more items' );
|
||||
} );
|
||||
|
||||
it( 'should render list items when footer is clicked and trigger onExpand', () => {
|
||||
const onExpand = jest.fn();
|
||||
const onCollapse = jest.fn();
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
onExpand={ onExpand }
|
||||
onCollapse={ onCollapse }
|
||||
>
|
||||
<div>Test</div>
|
||||
<div>Test 2</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
const listItem = container.querySelector( '.list-item-collapse' );
|
||||
|
||||
if ( listItem ) {
|
||||
userEvent.click( listItem );
|
||||
}
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).not.toHaveTextContent( 'Show more items' );
|
||||
expect( container ).toHaveTextContent( 'Show less' );
|
||||
expect( onExpand ).toHaveBeenCalled();
|
||||
expect( onCollapse ).not.toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'should render minimum children if minChildrenToShow is set and show the rest on expand', () => {
|
||||
const onExpand = jest.fn();
|
||||
const onCollapse = jest.fn();
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
onExpand={ onExpand }
|
||||
onCollapse={ onCollapse }
|
||||
show={ 2 }
|
||||
>
|
||||
<div>Test</div>
|
||||
<div>Test 2</div>
|
||||
<div>Test 3</div>
|
||||
<div>Test 4</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).not.toHaveTextContent( 'Test 3' );
|
||||
expect( container ).not.toHaveTextContent( 'Test 4' );
|
||||
const listItem = container.querySelector( '.list-item-collapse' );
|
||||
|
||||
if ( listItem ) {
|
||||
userEvent.click( listItem );
|
||||
}
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).toHaveTextContent( 'Test 3' );
|
||||
expect( container ).toHaveTextContent( 'Test 4' );
|
||||
expect( container ).not.toHaveTextContent( 'Show more items' );
|
||||
expect( container ).toHaveTextContent( 'Show less' );
|
||||
expect( onExpand ).toHaveBeenCalled();
|
||||
expect( onCollapse ).not.toHaveBeenCalled();
|
||||
} );
|
||||
|
||||
it( 'should correctly toggle the list', async () => {
|
||||
const onExpand = jest.fn();
|
||||
const onCollapse = jest.fn();
|
||||
const { container } = render(
|
||||
<ExperimentalCollapsibleList
|
||||
collapseLabel="Show less"
|
||||
expandLabel="Show more items"
|
||||
onExpand={ onExpand }
|
||||
onCollapse={ onCollapse }
|
||||
>
|
||||
<div id="test">Test</div>
|
||||
<div>Test 2</div>
|
||||
</ExperimentalCollapsibleList>
|
||||
);
|
||||
|
||||
let listItem = container.querySelector( '.list-item-collapse' );
|
||||
|
||||
if ( listItem ) {
|
||||
userEvent.click( listItem );
|
||||
}
|
||||
expect( container ).toHaveTextContent( 'Test' );
|
||||
expect( container ).toHaveTextContent( 'Test 2' );
|
||||
expect( container ).not.toHaveTextContent( 'Show more items' );
|
||||
expect( container ).toHaveTextContent( 'Show less' );
|
||||
|
||||
listItem = container.querySelector( '.list-item-collapse' );
|
||||
|
||||
if ( listItem ) {
|
||||
userEvent.click( listItem );
|
||||
}
|
||||
await waitForElementToBeRemoved(
|
||||
container.querySelector( '#test' )
|
||||
);
|
||||
expect( container ).not.toHaveTextContent( 'Test' );
|
||||
expect( container ).not.toHaveTextContent( 'Test 2' );
|
||||
expect( container ).toHaveTextContent( 'Show more items' );
|
||||
expect( container ).not.toHaveTextContent( 'Show less' );
|
||||
expect( onExpand ).toHaveBeenCalledTimes( 1 );
|
||||
expect( onCollapse ).toHaveBeenCalledTimes( 1 );
|
||||
} );
|
||||
} );
|
||||
} );
|
|
@ -32,3 +32,7 @@ export const NavigationItem =
|
|||
NavigationItemComponent || __experimentalNavigationItem;
|
||||
export const Text = TextComponent || __experimentalText;
|
||||
export const useSlot = useSlotHook || __experimentalUseSlot;
|
||||
|
||||
export { ExperimentalListItem as ListItem } from './experimental-list/experimental-list-item';
|
||||
export { ExperimentalList as List } from './experimental-list/experimental-list';
|
||||
export { ExperimentalCollapsibleList as CollapsibleList } from './experimental-list/collapsible-list';
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
/**
|
||||
* Internal Dependencies
|
||||
*/
|
||||
@import 'experimental-list/style.scss';
|
||||
@import 'experimental-list/collapsible-list/style.scss';
|
|
@ -137,6 +137,7 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt
|
|||
- Update: UI updates to Payment Task screen #6766
|
||||
- Update: Adding setup required icon for non-configured payment methods #6811
|
||||
- Update: Task list component with new Experimental Task list. #6849
|
||||
- Update: Experimental task list import to the experimental package. #6950
|
||||
- Update: Redirect to WC Home after setting up a payment method #6891
|
||||
- Update: Replace marketing extension - Google Listings and Ads. #6939
|
||||
- Dev: Fix a bug where trying to load an asset registry causes a crash. #6951
|
||||
|
|
|
@ -431,6 +431,14 @@ class Loader {
|
|||
);
|
||||
wp_style_add_data( 'wc-customer-effort-score', 'rtl', 'replace' );
|
||||
|
||||
wp_register_style(
|
||||
'wc-experimental',
|
||||
self::get_url( 'experimental/style', 'css' ),
|
||||
array(),
|
||||
$css_file_version
|
||||
);
|
||||
wp_style_add_data( 'wc-experimental', 'rtl', 'replace' );
|
||||
|
||||
wp_localize_script(
|
||||
WC_ADMIN_APP,
|
||||
'wcAdminAssets',
|
||||
|
@ -446,7 +454,7 @@ class Loader {
|
|||
wp_register_style(
|
||||
WC_ADMIN_APP,
|
||||
self::get_url( "app/style{$rtl}", 'css' ),
|
||||
array( 'wc-components', 'wc-customer-effort-score', 'wp-components' ),
|
||||
array( 'wc-components', 'wc-customer-effort-score', 'wp-components', 'wc-experimental' ),
|
||||
$css_file_version
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue