Category Selection: Keep selected categories in the list (https://github.com/woocommerce/woocommerce-blocks/pull/182)

* Don’t hide selected elements, instead add selection toggle

* Add checked/unchecked icons next to each menu item

* Add icon to product category list

* Update snapshots with added icons
This commit is contained in:
Kelly Dwan 2018-12-03 11:27:35 -05:00 committed by GitHub
commit 063f38192f
5 changed files with 1575 additions and 13 deletions

View File

@ -13,6 +13,7 @@ import PropTypes from 'prop-types';
* Internal dependencies
*/
import './style.scss';
import { CheckedIcon, UncheckedIcon } from '../search-list-control/icons';
import SearchListControl from '../search-list-control';
class ProductCategoryControl extends Component {
@ -36,7 +37,7 @@ class ProductCategoryControl extends Component {
} );
}
renderItem( { getHighlightedName, item, onSelect, search, depth = 0 } ) {
renderItem( { getHighlightedName, isSelected, item, onSelect, search, depth = 0 } ) {
const classes = [
'woocommerce-search-list__item',
'woocommerce-product-categories__item',
@ -56,8 +57,10 @@ class ProductCategoryControl extends Component {
return (
<MenuItem
key={ item.id }
role="menuitemcheckbox"
className={ classes.join( ' ' ) }
onClick={ onSelect( item ) }
isSelected={ isSelected }
aria-label={ sprintf(
_n(
'%s, has %d product',
@ -69,6 +72,9 @@ class ProductCategoryControl extends Component {
item.count
) }
>
<span className="woocommerce-search-list__item-state">
{ isSelected ? <CheckedIcon /> : <UncheckedIcon /> }
</span>
<span className="woocommerce-product-categories__item-label">
{ !! item.breadcrumbs.length && (
<span className="woocommerce-product-categories__item-prefix">

View File

@ -0,0 +1,48 @@
/**
* External dependencies
*/
import { SVG } from '@wordpress/components';
export const CheckedIcon = () => (
<SVG
viewBox="0 0 16 16"
width="16"
height="16"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
id="checked"
d="M15.2222 1H2.7778C1.791 1 1 1.8 1 2.7778v12.4444C1 16.2 1.7911 17 2.7778 17h12.4444C16.209 17 17 16.2 17 15.2222V2.7778C17 1.8 16.2089 1 15.2222 1zm-8 12.4444L2.7778 9 4.031 7.7467l3.1911 3.1822 6.7467-6.7467 1.2533 1.2622-8 8z"
/>
</defs>
<g fill="none" fillRule="evenodd" transform="translate(-1 -1)">
<mask id="checked-mask" fill="#fff">
<use xlinkHref="#checked" />
</mask>
<path fill="#1E8CBE" d="M0 0h18v18H0z" mask="url(#checked-mask)" />
</g>
</SVG>
);
export const UncheckedIcon = () => (
<SVG
viewBox="0 0 16 16"
width="16"
height="16"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
id="unchecked"
d="M15.2222 2.7778v12.4444H2.7778V2.7778h12.4444zm0-1.7778H2.7778C1.8 1 1 1.8 1 2.7778v12.4444C1 16.2 1.8 17 2.7778 17h12.4444C16.2 17 17 16.2 17 15.2222V2.7778C17 1.8 16.2 1 15.2222 1z"
/>
</defs>
<g fill="none" fillRule="evenodd" transform="translate(-1 -1)">
<mask id="unchecked-mask" fill="#fff">
<use xlinkHref="#unchecked" />
</mask>
<path fill="#6C7781" d="M0 0h18v18H0z" mask="url(#unchecked-mask)" />
</g>
</SVG>
);

View File

@ -20,6 +20,7 @@ import { Tag } from '@woocommerce/components';
*/
import './style.scss';
import { buildTermsTree } from './hierarchy';
import { CheckedIcon, UncheckedIcon } from './icons';
const defaultMessages = {
clear: __( 'Clear all selected items', 'woocommerce' ),
@ -41,6 +42,7 @@ export class SearchListControl extends Component {
this.onSelect = this.onSelect.bind( this );
this.onRemove = this.onRemove.bind( this );
this.onClear = this.onClear.bind( this );
this.isSelected = this.isSelected.bind( this );
this.defaultRenderItem = this.defaultRenderItem.bind( this );
this.renderList = this.renderList.bind( this );
}
@ -56,6 +58,10 @@ export class SearchListControl extends Component {
onSelect( item ) {
const { selected, onChange } = this.props;
return () => {
if ( this.isSelected( item ) ) {
this.onRemove( item.id )();
return;
}
onChange( [ ...selected, item ] );
};
}
@ -70,20 +76,15 @@ export class SearchListControl extends Component {
getFilteredList( list, search ) {
const { isHierarchical } = this.props;
if ( ! search && isHierarchical ) {
return buildTermsTree(
list.filter( ( item ) => item && ! this.isSelected( item ) ),
list
);
} else if ( ! search ) {
return list.filter( ( item ) => item && ! this.isSelected( item ) );
if ( ! search ) {
return isHierarchical ? buildTermsTree( list ) : list;
}
const messages = { ...defaultMessages, ...this.props.messages };
const re = new RegExp( escapeRegExp( search ), 'i' );
this.props.debouncedSpeak( messages.updated );
const filteredList = list
.map( ( item ) => ( re.test( item.name ) ? item : false ) )
.filter( ( item ) => item && ! this.isSelected( item ) );
.filter( Boolean );
return isHierarchical ? buildTermsTree( filteredList, list ) : filteredList;
}
@ -95,10 +96,15 @@ export class SearchListControl extends Component {
return name.replace( re, '<strong>$&</strong>' );
}
defaultRenderItem( { depth = 0, getHighlightedName, item, onSelect, search = '' } ) {
const classes = [
'woocommerce-search-list__item',
];
defaultRenderItem( {
depth = 0,
getHighlightedName,
item,
isSelected,
onSelect,
search = '',
} ) {
const classes = [ 'woocommerce-search-list__item' ];
if ( this.props.isHierarchical ) {
classes.push( `depth-${ depth }` );
}
@ -106,9 +112,14 @@ export class SearchListControl extends Component {
return (
<MenuItem
key={ item.id }
role="menuitemcheckbox"
className={ classes.join( ' ' ) }
onClick={ onSelect( item ) }
isSelected={ isSelected }
>
<span className="woocommerce-search-list__item-state">
{ isSelected ? <CheckedIcon /> : <UncheckedIcon /> }
</span>
<span
className="woocommerce-search-list__item-name"
dangerouslySetInnerHTML={ {
@ -130,6 +141,7 @@ export class SearchListControl extends Component {
{ renderItem( {
getHighlightedName: this.getHighlightedName,
item,
isSelected: this.isSelected( item ),
onSelect: this.onSelect,
search,
depth,

View File

@ -49,6 +49,8 @@
}
.woocommerce-search-list__item {
display: flex;
align-items: center;
margin-bottom: 0;
padding: $gap;
background: $white;
@ -56,6 +58,15 @@
border-bottom: 1px solid $core-grey-light-500 !important;
color: $core-grey-dark-500;
.woocommerce-search-list__item-state {
flex: 0 0 16px;
margin-right: $gap-smaller;
}
.woocommerce-search-list__item-name {
flex: 1;
}
@include hover-state {
background: $core-grey-light-100;
}