Product Categories List: Update dropdown view (https://github.com/woocommerce/woocommerce-blocks/pull/647)

* Add the hierarchy display to the dropdown

* Add navigation for when a category is selected in the dropdown

* Use forEach from lodash for ie11 compat

* Switch to a button-click navigation pattern for better keyboard support

* Try the hidden attribute on option
This commit is contained in:
Kelly Dwan 2019-06-25 10:16:04 -04:00 committed by GitHub
parent 36b58ff1be
commit 58cd36a35c
6 changed files with 133 additions and 54 deletions

View File

@ -2,20 +2,23 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { noop } from 'lodash';
import { SelectControl } from '@wordpress/components';
import classnames from 'classnames';
import { Component, createRef, Fragment } from '@wordpress/element';
import { IconButton } from '@wordpress/components';
import { repeat } from 'lodash';
import PropTypes from 'prop-types';
import { withInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { buildTermsTree } from './hierarchy';
function getCategories( { hasEmpty, isDropdown, isHierarchical } ) {
function getCategories( { hasEmpty, isHierarchical } ) {
const categories = wc_product_block_data.productCategories.filter(
( cat ) => hasEmpty || !! cat.count
);
return ! isDropdown && isHierarchical ?
return isHierarchical ?
buildTermsTree( categories ) :
categories;
}
@ -23,52 +26,116 @@ function getCategories( { hasEmpty, isDropdown, isHierarchical } ) {
/**
* Component displaying the categories as dropdown or list.
*/
const ProductCategoriesBlock = ( { attributes, isPreview = false } ) => {
const { hasCount, isDropdown } = attributes;
const categories = getCategories( attributes );
const parentKey = 'parent-' + categories[ 0 ].term_id;
class ProductCategoriesBlock extends Component {
constructor() {
super( ...arguments );
this.select = createRef();
this.onNavigate = this.onNavigate.bind( this );
this.renderList = this.renderList.bind( this );
this.renderOptions = this.renderOptions.bind( this );
}
const renderList = ( items ) => (
<ul key={ parentKey }>
{ items.map( ( cat ) => {
const count = hasCount ? <span>({ cat.count })</span> : null;
return [
<li key={ cat.term_id }>
<a href={ isPreview ? null : cat.link }>{ cat.name }</a> { count } { /* eslint-disable-line */ }
</li>,
!! cat.children && !! cat.children.length && renderList( cat.children ),
];
} ) }
</ul>
);
onNavigate() {
const { isPreview = false } = this.props;
const url = this.select.current.value;
if ( 'false' === url ) {
return;
}
const home = wc_product_block_data.homeUrl;
return (
<div className="wc-block-product-categories">
{ isDropdown ? (
<SelectControl
label={ __( 'Select a category', 'woo-gutenberg-products-block' ) }
options={ categories.map( ( cat ) => ( {
label: hasCount ? `${ cat.name } (${ cat.count })` : cat.name,
value: cat.term_id,
} ) ) }
onChange={ noop }
/>
) : (
renderList( categories )
) }
</div>
);
};
if ( ! isPreview && 0 === url.indexOf( home ) ) {
document.location.href = url;
}
}
renderList( items, depth = 0 ) {
const { isPreview = false } = this.props;
const { hasCount } = this.props.attributes;
const parentKey = 'parent-' + items[ 0 ].term_id;
return (
<ul key={ parentKey }>
{ items.map( ( cat ) => {
const count = hasCount ? <span>({ cat.count })</span> : null;
return [
<li key={ cat.term_id }>
<a href={ isPreview ? null : cat.link }>{ cat.name }</a> { count } { /* eslint-disable-line */ }
</li>,
!! cat.children && !! cat.children.length && this.renderList( cat.children, depth + 1 ),
];
} ) }
</ul>
);
}
renderOptions( items, depth = 0 ) {
const { hasCount } = this.props.attributes;
return items.map( ( cat ) => {
const count = hasCount ? `(${ cat.count })` : null;
return [
<option key={ cat.term_id } value={ cat.link }>
{ repeat( '', depth ) } { cat.name } { count }
</option>,
!! cat.children && !! cat.children.length && this.renderOptions( cat.children, depth + 1 ),
];
} );
}
render() {
const { attributes, instanceId } = this.props;
const { isDropdown } = attributes;
const categories = getCategories( attributes );
const classes = classnames( {
'wc-block-product-categories': true,
'is-dropdown': isDropdown,
'is-list': ! isDropdown,
} );
const selectId = `prod-categories-${ instanceId }`;
return (
<div className={ classes }>
{ isDropdown ? (
<Fragment>
<div className="wc-block-product-categories__dropdown">
<label className="screen-reader-text" htmlFor={ selectId }>
{ __( 'Select a category', 'woo-gutenberg-products-block' ) }
</label>
<select id={ selectId } ref={ this.select }>
<option value="false" hidden>
{ __( 'Select a category', 'woo-gutenberg-products-block' ) }
</option>
{ this.renderOptions( categories ) }
</select>
</div>
<IconButton
icon="arrow-right-alt2"
label={ __( 'Go to category', 'woo-gutenberg-products-block' ) }
onClick={ this.onNavigate }
/>
</Fragment>
) : (
this.renderList( categories )
) }
</div>
);
}
}
ProductCategoriesBlock.propTypes = {
/**
* The attributes for this block
* The attributes for this block.
*/
attributes: PropTypes.object.isRequired,
/**
* A unique ID for identifying the label for the select dropdown.
*/
instanceId: PropTypes.number,
/**
* Whether this is the block preview or frontend display.
*/
isPreview: PropTypes.bool,
};
export default ProductCategoriesBlock;
export default withInstanceId( ProductCategoriesBlock );

View File

@ -42,18 +42,16 @@ export default function( { attributes, setAttributes } ) {
checked={ hasCount }
onChange={ () => setAttributes( { hasCount: ! hasCount } ) }
/>
{ ! isDropdown && (
<ToggleControl
label={ __( 'Show hierarchy', 'woo-gutenberg-products-block' ) }
help={
isHierarchical ?
__( 'Hierarchy is visible.', 'woo-gutenberg-products-block' ) :
__( 'Hierarchy is hidden.', 'woo-gutenberg-products-block' )
}
checked={ isHierarchical }
onChange={ () => setAttributes( { isHierarchical: ! isHierarchical } ) }
/>
) }
<ToggleControl
label={ __( 'Show hierarchy', 'woo-gutenberg-products-block' ) }
help={
isHierarchical ?
__( 'Hierarchy is visible.', 'woo-gutenberg-products-block' ) :
__( 'Hierarchy is hidden.', 'woo-gutenberg-products-block' )
}
checked={ isHierarchical }
onChange={ () => setAttributes( { isHierarchical: ! isHierarchical } ) }
/>
<ToggleControl
label={ __( 'Show empty categories', 'woo-gutenberg-products-block' ) }
help={

View File

@ -1,6 +1,7 @@
/**
* External dependencies
*/
import { forEach } from 'lodash';
import { render } from '@wordpress/element';
/**
@ -13,7 +14,7 @@ const containers = document.querySelectorAll(
);
if ( containers.length ) {
containers.forEach( ( el ) => {
forEach( containers, ( el ) => {
const data = JSON.parse( JSON.stringify( el.dataset ) );
const attributes = {
hasCount: data.hasCount === 'true',

View File

@ -8,6 +8,7 @@ import { registerBlockType } from '@wordpress/blocks';
* Internal dependencies
*/
import './editor.scss';
import './style.scss';
import edit from './edit.js';
import { IconFolder } from '../../components/icons';

View File

@ -0,0 +1,11 @@
.wc-block-product-categories {
margin-bottom: 1em;
&.is-dropdown {
display: flex;
}
select {
margin-right: 0.5em;
}
}

View File

@ -119,7 +119,7 @@ class WGPB_Block_Library {
*/
public static function register_assets() {
self::register_style( 'wc-block-editor', plugins_url( 'build/editor.css', WGPB_PLUGIN_FILE ), array( 'wp-edit-blocks' ) );
self::register_style( 'wc-block-style', plugins_url( 'build/style.css', WGPB_PLUGIN_FILE ), array() );
self::register_style( 'wc-block-style', plugins_url( 'build/style.css', WGPB_PLUGIN_FILE ), array( 'wp-components' ) );
// Shared libraries and components across all blocks.
self::register_script( 'wc-blocks', plugins_url( 'build/blocks.js', WGPB_PLUGIN_FILE ), array(), false );
@ -215,6 +215,7 @@ class WGPB_Block_Library {
'default_height' => wc_get_theme_support( 'featured_block::default_height', 500 ),
'isLargeCatalog' => $product_counts->publish > 200,
'productCategories' => $product_categories,
'homeUrl' => esc_js( home_url( '/' ) ),
);
?>
<script type="text/javascript">