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:
parent
36b58ff1be
commit
58cd36a35c
|
@ -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 );
|
||||
|
|
|
@ -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={
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
.wc-block-product-categories {
|
||||
margin-bottom: 1em;
|
||||
|
||||
&.is-dropdown {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
select {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue