Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Reduce number of dependencies for the product categories list block (#…
Browse files Browse the repository at this point in the history
…771)

* unqiueID helper to replace compose

* move get categories function to own file

* fix svg styling

* remove lodash dependency

* Refactor block/edit to use less dependencies

* Babel config to skip wp.element

* update comments

* Update assets/js/blocks/product-categories/frontend.js

ie11 compatible for each on nodelist

Co-Authored-By: Albert Juhé Lluveras <[email protected]>

* move id generation to constructor

* simplify webpack config

* Remove components CSS dependency

* use HOC for component ID

* Correct case on ComponentId
  • Loading branch information
mikejolley authored Jul 29, 2019
1 parent 2cf01d3 commit 254d7ad
Show file tree
Hide file tree
Showing 13 changed files with 1,394 additions and 438 deletions.
64 changes: 16 additions & 48 deletions assets/js/blocks/product-categories/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,13 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, createRef, Fragment } from 'react';
import classnames from 'classnames';
import { Component, createRef, Fragment } from '@wordpress/element';
import { IconButton, Placeholder } from '@wordpress/components';
import { repeat } from 'lodash';
import PropTypes from 'prop-types';
import { withInstanceId } from '@wordpress/compose';

/**
* Internal dependencies
*/
import { buildTermsTree } from './hierarchy';
import { IconFolder } from '../../components/icons';

function getCategories( { hasEmpty, isHierarchical } ) {
const categories = wc_product_block_data.productCategories.filter(
( cat ) => hasEmpty || !! cat.count
);
return isHierarchical ?
buildTermsTree( categories ) :
categories;
}
import withComponentId from '../../utils/with-component-id';

/**
* Component displaying the categories as dropdown or list.
Expand Down Expand Up @@ -76,17 +62,16 @@ class ProductCategoriesBlock extends Component {
const count = hasCount ? `(${ cat.count })` : null;
return [
<option key={ cat.term_id } value={ cat.link }>
{ repeat( '–', depth ) } { cat.name } { count }
{ '–'.repeat( depth ) } { cat.name } { count }
</option>,
!! cat.children && !! cat.children.length && this.renderOptions( cat.children, depth + 1 ),
];
} );
}

render() {
const { attributes, instanceId } = this.props;
const { attributes, categories, ComponentId } = this.props;
const { className, isDropdown } = attributes;
const categories = getCategories( attributes );
const classes = classnames(
'wc-block-product-categories',
className,
Expand All @@ -96,11 +81,11 @@ class ProductCategoriesBlock extends Component {
}
);

const selectId = `prod-categories-${ instanceId }`;
const selectId = `prod-categories-${ ComponentId }`;

return (
<Fragment>
{ categories.length > 0 ? (
{ categories.length > 0 && (
<div className={ classes }>
{ isDropdown ? (
<Fragment>
Expand All @@ -115,43 +100,26 @@ class ProductCategoriesBlock extends Component {
{ this.renderOptions( categories ) }
</select>
</div>
<IconButton
<button
type="button"
className="wc-block-product-categories__button"
aria-label={ __( 'Go to category', 'woo-gutenberg-products-block' ) }
icon="arrow-right-alt2"
label={ __( 'Go to category', 'woo-gutenberg-products-block' ) }
onClick={ this.onNavigate }
/>
>
<svg aria-hidden="true" role="img" focusable="false" className="dashicon dashicons-arrow-right-alt2" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<path d="M6 15l5-5-5-5 1-2 7 7-7 7z"></path>
</svg>
</button>
</Fragment>
) : (
this.renderList( categories )
) }
</div>
) : (
<Placeholder
className="wc-block-product-categories"
icon={ <IconFolder /> }
label={ __( 'Product Categories List', 'woo-gutenberg-products-block' ) }
>
{ __( "This block shows product categories for your store. In order to preview this you'll first need to create a product and assign it to a category.", 'woo-gutenberg-products-block' ) }
</Placeholder>
) }
</Fragment>
);
}
}

ProductCategoriesBlock.propTypes = {
/**
* 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 withInstanceId( ProductCategoriesBlock );
export default withComponentId( ProductCategoriesBlock );
17 changes: 15 additions & 2 deletions assets/js/blocks/product-categories/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
import { __ } from '@wordpress/i18n';
import { Fragment } from '@wordpress/element';
import { InspectorControls } from '@wordpress/editor';
import { PanelBody, ToggleControl } from '@wordpress/components';
import { PanelBody, ToggleControl, Placeholder } from '@wordpress/components';

/**
* Internal dependencies
*/
import './editor.scss';
import Block from './block.js';
import ToggleButtonControl from '../../components/toggle-button-control';
import getCategories from './get-categories';
import { IconFolder } from '../../components/icons';

export default function( { attributes, setAttributes } ) {
const { hasCount, hasEmpty, isDropdown, isHierarchical } = attributes;
const categories = getCategories( attributes );

return (
<Fragment>
Expand Down Expand Up @@ -69,7 +72,17 @@ export default function( { attributes, setAttributes } ) {
/>
</PanelBody>
</InspectorControls>
<Block attributes={ attributes } isPreview />
{ categories.length > 0 ? (
<Block attributes={ attributes } categories={ categories } isPreview />
) : (
<Placeholder
className="wc-block-product-categories"
icon={ <IconFolder /> }
label={ __( 'Product Categories List', 'woo-gutenberg-products-block' ) }
>
{ __( "This block shows product categories for your store. In order to preview this you'll first need to create a product and assign it to a category.", 'woo-gutenberg-products-block' ) }
</Placeholder>
) }
</Fragment>
);
}
2 changes: 1 addition & 1 deletion assets/js/blocks/product-categories/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
margin-left: 20px;
}
.wc-block-product-categories {
svg {
.components-placeholder__label svg {
margin-right: 1ch;
fill: currentColor;
}
Expand Down
10 changes: 6 additions & 4 deletions assets/js/blocks/product-categories/frontend.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
/**
* External dependencies
*/
import { forEach } from 'lodash';
import { render } from '@wordpress/element';
import { render } from 'react-dom';

/**
* Internal dependencies
*/
import Block from './block.js';
import getCategories from './get-categories';

const containers = document.querySelectorAll(
'.wp-block-woocommerce-product-categories'
);

if ( containers.length ) {
forEach( containers, ( el ) => {
Array.prototype.forEach.call( containers, ( el ) => {
const data = JSON.parse( JSON.stringify( el.dataset ) );
const attributes = {
hasCount: data.hasCount === 'true',
hasEmpty: data.hasEmpty === 'true',
isDropdown: data.isDropdown === 'true',
isHierarchical: data.isHierarchical === 'true',
};
const categories = getCategories( attributes );

el.classList.remove( 'is-loading' );

render( <Block attributes={ attributes } />, el );
render( <Block attributes={ attributes } categories={ categories } />, el );
} );
}
16 changes: 16 additions & 0 deletions assets/js/blocks/product-categories/get-categories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Internal dependencies
*/
import { buildTermsTree } from './hierarchy';

/**
* Returns categories in tree form.
*/
export default function( { hasEmpty, isHierarchical } ) {
const categories = wc_product_block_data.productCategories.filter(
( cat ) => hasEmpty || !! cat.count
);
return isHierarchical ?
buildTermsTree( categories ) :
categories;
}
11 changes: 3 additions & 8 deletions assets/js/blocks/product-categories/hierarchy.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/**
* External dependencies
*/
import { forEach, groupBy } from 'lodash';

/**
* Returns terms in a tree form.
*
Expand All @@ -11,7 +6,8 @@ import { forEach, groupBy } from 'lodash';
* @return {Array} Array of terms in tree format.
*/
export function buildTermsTree( list = [] ) {
const termsByParent = groupBy( list, 'parent' );
// Group terms by the parent ID.
const termsByParent = list.reduce( ( r, v, i, a, k = v.parent ) => ( ( r[ k ] || ( r[ k ] = [] ) ).push( v ), r ), {} );

const fillWithChildren = ( terms ) => {
return terms.map( ( term ) => {
Expand All @@ -27,8 +23,7 @@ export function buildTermsTree( list = [] ) {
const tree = fillWithChildren( termsByParent[ '0' ] || [] );
delete termsByParent[ '0' ];

// anything left in termsByParent has no visible parent
forEach( termsByParent, ( terms ) => {
Object.keys( termsByParent ).forEach( function( terms ) {
tree.push( ...fillWithChildren( terms || [] ) );
} );

Expand Down
54 changes: 54 additions & 0 deletions assets/js/blocks/product-categories/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,57 @@
background: currentColor;
opacity: 0.2;
}

.wc-block-product-categories__button {
display: flex;
align-items: center;
text-decoration: none;
font-size: 13px;
margin: 0;
border: none;
cursor: pointer;
-webkit-appearance: none;
background: none;
padding: 8px;
color: #555d66;
position: relative;
overflow: hidden;
border-radius: 4px;
svg {
fill: currentColor;
outline: none;
}
.screen-reader-text {
height: auto;
}
&:active {
color: currentColor;
}
&:disabled,
&[aria-disabled="true"] {
cursor: default;
opacity: 0.3;
}
&:focus:enabled {
background-color: #fff;
color: #191e23;
box-shadow: inset 0 0 0 1px #6c7781, inset 0 0 0 2px #fff;
outline: 2px solid transparent;
outline-offset: -2px;
}
&:not(:disabled):not([aria-disabled="true"]):hover {
background-color: #fff;
color: #191e23;
box-shadow: inset 0 0 0 1px #e2e4e7, inset 0 0 0 2px #fff, 0 1px 1px rgba(25, 30, 35, 0.2);
}
&:not(:disabled):not([aria-disabled="true"]):active {
outline: none;
background-color: #fff;
color: #191e23;
box-shadow: inset 0 0 0 1px #ccd0d4, inset 0 0 0 2px #fff;
}
&[aria-disabled="true"]:focus,
&:disabled:focus {
box-shadow: none;
}
}
35 changes: 35 additions & 0 deletions assets/js/utils/with-component-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Component } from 'react';

const ids = [];

/**
* HOC that gives a component a unique ID.
*
* This is an alternative for withInstanceId from @wordpress/compose to avoid using that dependency on the frontend.
*/
const withComponentId = ( OriginalComponent ) => {
return class WrappedComponent extends Component {
generateUniqueID() {
const group = WrappedComponent.name;

if ( ! ids[ group ] ) {
ids[ group ] = 0;
}

ids[ group ]++;

return ids[ group ];
}

render() {
const ComponentId = this.generateUniqueID();

return <OriginalComponent
{ ...this.props }
ComponentId={ ComponentId }
/>;
}
};
};

export default withComponentId;
3 changes: 0 additions & 3 deletions babel.config.js

This file was deleted.

Loading

0 comments on commit 254d7ad

Please sign in to comment.