Merge branch 'master' into experiment/cancel-button

This commit is contained in:
Mike Jolley 2019-05-24 12:06:07 +01:00
commit a14ab46778
10 changed files with 3135 additions and 2381 deletions

View File

@ -13,7 +13,14 @@
fill: currentColor; fill: currentColor;
} }
.wc-block-products-grid { // Remove the list styling, which is added back by core GB styles.
.editor-styles-wrapper .wc-block-grid {
list-style: none;
margin-left: 0;
}
.wc-block-products-grid,
.wc-block-grid {
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -44,6 +51,43 @@
min-width: auto; min-width: auto;
} }
} }
.star-rating {
overflow: hidden;
position: relative;
width: 5.3em;
height: 1.618em;
line-height: 1.618;
font-size: 1em;
font-family: star; /* stylelint-disable-line */
font-weight: 400;
&::before {
content: "\53\53\53\53\53";
top: 0;
left: 0;
right: 0;
position: absolute;
opacity: 0.25;
}
span {
overflow: hidden;
top: 0;
left: 0;
right: 0;
position: absolute;
padding-top: 1.5em;
}
span::before {
content: "\53\53\53\53\53";
top: 0;
left: 0;
right: 0;
position: absolute;
}
}
} }
// @todo Remove this once all grid blocks are switched to dynamic. // @todo Remove this once all grid blocks are switched to dynamic.

View File

@ -1,32 +1,26 @@
/** /**
* External dependencies * External dependencies
*/ */
import { __, _n } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url'; import { BlockControls, InspectorControls, ServerSideRender } from '@wordpress/editor';
import apiFetch from '@wordpress/api-fetch';
import { BlockControls, InspectorControls } from '@wordpress/editor';
import { import {
Button, Button,
Disabled,
PanelBody, PanelBody,
Placeholder, Placeholder,
Spinner,
Toolbar, Toolbar,
withSpokenMessages, withSpokenMessages,
} from '@wordpress/components'; } from '@wordpress/components';
import classnames from 'classnames';
import { Component, Fragment } from '@wordpress/element'; import { Component, Fragment } from '@wordpress/element';
import { debounce } from 'lodash';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import getQuery from '../../utils/get-query';
import GridContentControl from '../../components/grid-content-control'; import GridContentControl from '../../components/grid-content-control';
import GridLayoutControl from '../../components/grid-layout-control'; import GridLayoutControl from '../../components/grid-layout-control';
import ProductCategoryControl from '../../components/product-category-control'; import ProductCategoryControl from '../../components/product-category-control';
import ProductOrderbyControl from '../../components/product-orderby-control'; import ProductOrderbyControl from '../../components/product-orderby-control';
import ProductPreview from '../../components/product-preview';
/** /**
* Component to handle edit mode of "Products by Category". * Component to handle edit mode of "Products by Category".
@ -35,8 +29,6 @@ class ProductByCategoryBlock extends Component {
constructor() { constructor() {
super( ...arguments ); super( ...arguments );
this.state = { this.state = {
products: [],
loaded: false,
changedAttributes: {}, changedAttributes: {},
isEditing: false, isEditing: false,
}; };
@ -44,13 +36,6 @@ class ProductByCategoryBlock extends Component {
this.stopEditing = this.stopEditing.bind( this ); this.stopEditing = this.stopEditing.bind( this );
this.setChangedAttributes = this.setChangedAttributes.bind( this ); this.setChangedAttributes = this.setChangedAttributes.bind( this );
this.save = this.save.bind( this ); this.save = this.save.bind( this );
this.debouncedGetProducts = debounce( this.getProducts.bind( this ), 200 );
}
componentDidMount() {
if ( this.props.attributes.categories ) {
this.getProducts();
}
} }
startEditing() { startEditing() {
@ -81,45 +66,16 @@ class ProductByCategoryBlock extends Component {
this.stopEditing(); this.stopEditing();
} }
componentDidUpdate( prevProps ) {
const hasChange = [
'categories',
'catOperator',
'columns',
'orderby',
'rows',
].reduce( ( acc, key ) => {
return acc || prevProps.attributes[ key ] !== this.props.attributes[ key ];
}, false );
if ( hasChange ) {
this.debouncedGetProducts();
}
}
getProducts() {
if ( ! this.props.attributes.categories.length ) {
// We've removed all selected categories, or no categories have been selected yet.
this.setState( { products: [], loaded: true, isEditing: true } );
return;
}
apiFetch( {
path: addQueryArgs(
'/wc-blocks/v1/products',
getQuery( this.props.attributes, this.props.name )
),
} )
.then( ( products ) => {
this.setState( { products, loaded: true } );
} )
.catch( () => {
this.setState( { products: [], loaded: true } );
} );
}
getInspectorControls() { getInspectorControls() {
const { attributes, setAttributes } = this.props; const { attributes, setAttributes } = this.props;
const { isEditing } = this.state; const { isEditing } = this.state;
const { columns, catOperator, contentVisibility, orderby, rows } = attributes; const {
columns,
catOperator,
contentVisibility,
orderby,
rows,
} = attributes;
return ( return (
<InspectorControls key="inspector"> <InspectorControls key="inspector">
@ -238,35 +194,8 @@ class ProductByCategoryBlock extends Component {
} }
render() { render() {
const { const { attributes } = this.props;
categories, const { isEditing } = this.state;
columns,
contentVisibility,
} = this.props.attributes;
const { loaded, products = [], isEditing } = this.state;
const classes = classnames( {
'wc-block-products-grid': true,
'wc-block-products-category': true,
[ `cols-${ columns }` ]: columns,
'is-loading': ! loaded,
'is-not-found': loaded && ! products.length,
'is-hidden-title': ! contentVisibility.title,
'is-hidden-price': ! contentVisibility.price,
'is-hidden-rating': ! contentVisibility.rating,
'is-hidden-button': ! contentVisibility.button,
} );
const nothingFound = ! categories.length ?
__(
'Select at least one category to display its products.',
'woo-gutenberg-products-block'
) :
_n(
'No products in this category.',
'No products in these categories.',
categories.length,
'woo-gutenberg-products-block'
);
return ( return (
<Fragment> <Fragment>
@ -286,23 +215,12 @@ class ProductByCategoryBlock extends Component {
{ isEditing ? ( { isEditing ? (
this.renderEditMode() this.renderEditMode()
) : ( ) : (
<div className={ classes }> <Disabled>
{ products.length ? ( <ServerSideRender
products.map( ( product ) => ( block="woocommerce/product-category"
<ProductPreview product={ product } key={ product.id } /> attributes={ attributes }
) ) />
) : ( </Disabled>
<Placeholder
icon="category"
label={ __(
'Products by Category',
'woo-gutenberg-products-block'
) }
>
{ ! loaded ? <Spinner /> : nothingFound }
</Placeholder>
) }
</div>
) } ) }
</Fragment> </Fragment>
); );

View File

@ -2,17 +2,15 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import classnames from 'classnames';
import { createBlock, registerBlockType } from '@wordpress/blocks'; import { createBlock, registerBlockType } from '@wordpress/blocks';
import { without } from 'lodash'; import { without } from 'lodash';
import { RawHTML } from '@wordpress/element';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import './editor.scss'; import './editor.scss';
import Block from './block'; import Block from './block';
import getShortcode from '../../utils/get-shortcode'; import { deprecatedConvertToShortcode } from '../../utils/deprecations';
import sharedAttributes, { sharedAttributeBlockTypes } from '../../utils/shared-attributes'; import sharedAttributes, { sharedAttributeBlockTypes } from '../../utils/shared-attributes';
/** /**
@ -49,6 +47,7 @@ registerBlockType( 'woocommerce/product-category', {
default: 'date', default: 'date',
}, },
}, },
transforms: { transforms: {
from: [ from: [
{ {
@ -62,6 +61,24 @@ registerBlockType( 'woocommerce/product-category', {
], ],
}, },
deprecated: [
{
// Deprecate shortcode save method in favor of dynamic rendering.
attributes: {
...sharedAttributes,
editMode: {
type: 'boolean',
default: true,
},
orderby: {
type: 'string',
default: 'date',
},
},
save: deprecatedConvertToShortcode( 'woocommerce/product-category' ),
},
],
/** /**
* Renders and manages the block. * Renders and manages the block.
*/ */
@ -69,29 +86,7 @@ registerBlockType( 'woocommerce/product-category', {
return <Block { ...props } />; return <Block { ...props } />;
}, },
/** save() {
* Save the block content in the post content. Block content is saved as a products shortcode. return null;
*
* @return string
*/
save( props ) {
const {
align,
contentVisibility,
} = props.attributes; /* eslint-disable-line react/prop-types */
const classes = classnames(
align ? `align${ align }` : '',
{
'is-hidden-title': ! contentVisibility.title,
'is-hidden-price': ! contentVisibility.price,
'is-hidden-rating': ! contentVisibility.rating,
'is-hidden-button': ! contentVisibility.button,
}
);
return (
<RawHTML className={ classes }>
{ getShortcode( props, 'woocommerce/product-category' ) }
</RawHTML>
);
}, },
} ); } );

View File

@ -2,72 +2,22 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import classnames from 'classnames';
import { Component, Fragment } from '@wordpress/element'; import { Component, Fragment } from '@wordpress/element';
import { debounce } from 'lodash'; import { Disabled, PanelBody } from '@wordpress/components';
import { InspectorControls } from '@wordpress/editor'; import { InspectorControls, ServerSideRender } from '@wordpress/editor';
import { PanelBody, Placeholder, Spinner } from '@wordpress/components';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import getQuery from '../../utils/get-query';
import GridContentControl from '../../components/grid-content-control'; import GridContentControl from '../../components/grid-content-control';
import GridLayoutControl from '../../components/grid-layout-control'; import GridLayoutControl from '../../components/grid-layout-control';
import { IconNewReleases } from '../../components/icons';
import ProductCategoryControl from '../../components/product-category-control'; import ProductCategoryControl from '../../components/product-category-control';
import ProductPreview from '../../components/product-preview';
/** /**
* Component to handle edit mode of "Newest Products". * Component to handle edit mode of "Newest Products".
*/ */
class ProductNewestBlock extends Component { class ProductNewestBlock extends Component {
constructor() {
super( ...arguments );
this.state = {
products: [],
loaded: false,
};
this.debouncedGetProducts = debounce( this.getProducts.bind( this ), 200 );
}
componentDidMount() {
if ( this.props.attributes.categories ) {
this.getProducts();
}
}
componentDidUpdate( prevProps ) {
const hasChange = [ 'rows', 'columns', 'categories', 'catOperator' ].reduce(
( acc, key ) => {
return acc || prevProps.attributes[ key ] !== this.props.attributes[ key ];
},
false
);
if ( hasChange ) {
this.debouncedGetProducts();
}
}
getProducts() {
apiFetch( {
path: addQueryArgs(
'/wc-blocks/v1/products',
getQuery( this.props.attributes, this.props.name )
),
} )
.then( ( products ) => {
this.setState( { products, loaded: true } );
} )
.catch( () => {
this.setState( { products: [], loaded: true } );
} );
}
getInspectorControls() { getInspectorControls() {
const { attributes, setAttributes } = this.props; const { attributes, setAttributes } = this.props;
const { const {
@ -123,42 +73,14 @@ class ProductNewestBlock extends Component {
} }
render() { render() {
const { columns, contentVisibility } = this.props.attributes; const { attributes } = this.props;
const { loaded, products = [] } = this.state;
const classes = classnames( {
'wc-block-products-grid': true,
'wc-block-grid': true,
'wc-block-newest-products': true,
[ `has-${ columns }-columns` ]: columns,
'is-loading': ! loaded,
'is-not-found': loaded && ! products.length,
'is-hidden-title': ! contentVisibility.title,
'is-hidden-price': ! contentVisibility.price,
'is-hidden-rating': ! contentVisibility.rating,
'is-hidden-button': ! contentVisibility.button,
} );
return ( return (
<Fragment> <Fragment>
{ this.getInspectorControls() } { this.getInspectorControls() }
<div className={ classes }> <Disabled>
{ products.length ? ( <ServerSideRender block="woocommerce/product-new" attributes={ attributes } />
products.map( ( product ) => ( </Disabled>
<ProductPreview product={ product } key={ product.id } />
) )
) : (
<Placeholder
icon={ <IconNewReleases /> }
label={ __( 'Newest Products', 'woo-gutenberg-products-block' ) }
>
{ ! loaded ? (
<Spinner />
) : (
__( 'No products found.', 'woo-gutenberg-products-block' )
) }
</Placeholder>
) }
</div>
</Fragment> </Fragment>
); );
} }

View File

@ -2,74 +2,23 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import classnames from 'classnames';
import { Component, Fragment } from '@wordpress/element'; import { Component, Fragment } from '@wordpress/element';
import { debounce } from 'lodash'; import { Disabled, PanelBody } from '@wordpress/components';
import Gridicon from 'gridicons'; import { InspectorControls, ServerSideRender } from '@wordpress/editor';
import { InspectorControls } from '@wordpress/editor';
import { PanelBody, Placeholder, Spinner } from '@wordpress/components';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import getQuery from '../../utils/get-query';
import GridContentControl from '../../components/grid-content-control'; import GridContentControl from '../../components/grid-content-control';
import GridLayoutControl from '../../components/grid-layout-control'; import GridLayoutControl from '../../components/grid-layout-control';
import ProductCategoryControl from '../../components/product-category-control'; import ProductCategoryControl from '../../components/product-category-control';
import ProductOrderbyControl from '../../components/product-orderby-control'; import ProductOrderbyControl from '../../components/product-orderby-control';
import ProductPreview from '../../components/product-preview';
/** /**
* Component to handle edit mode of "On Sale Products". * Component to handle edit mode of "On Sale Products".
*/ */
class ProductOnSaleBlock extends Component { class ProductOnSaleBlock extends Component {
constructor() {
super( ...arguments );
this.state = {
products: [],
loaded: false,
};
this.debouncedGetProducts = debounce( this.getProducts.bind( this ), 200 );
}
componentDidMount() {
this.getProducts();
}
componentDidUpdate( prevProps ) {
const hasChange = [
'categories',
'catOperator',
'columns',
'orderby',
'rows',
].reduce( ( acc, key ) => {
return acc || prevProps.attributes[ key ] !== this.props.attributes[ key ];
}, false );
if ( hasChange ) {
this.debouncedGetProducts();
}
}
getProducts() {
apiFetch( {
path: addQueryArgs(
'/wc-blocks/v1/products',
getQuery( this.props.attributes, this.props.name )
),
} )
.then( ( products ) => {
this.setState( { products, loaded: true } );
} )
.catch( () => {
this.setState( { products: [], loaded: true } );
} );
}
getInspectorControls() { getInspectorControls() {
const { attributes, setAttributes } = this.props; const { attributes, setAttributes } = this.props;
const { const {
@ -135,42 +84,14 @@ class ProductOnSaleBlock extends Component {
} }
render() { render() {
const { columns, contentVisibility } = this.props.attributes; const { attributes } = this.props;
const { loaded, products = [] } = this.state;
const classes = classnames( {
'wc-block-products-grid': true,
'wc-block-grid': true,
'wc-block-on-sale-products': true,
[ `has-${ columns }-columns` ]: columns,
'is-loading': ! loaded,
'is-not-found': loaded && ! products.length,
'is-hidden-title': ! contentVisibility.title,
'is-hidden-price': ! contentVisibility.price,
'is-hidden-rating': ! contentVisibility.rating,
'is-hidden-button': ! contentVisibility.button,
} );
return ( return (
<Fragment> <Fragment>
{ this.getInspectorControls() } { this.getInspectorControls() }
<div className={ classes }> <Disabled>
{ products.length ? ( <ServerSideRender block="woocommerce/product-on-sale" attributes={ attributes } />
products.map( ( product ) => ( </Disabled>
<ProductPreview product={ product } key={ product.id } />
) )
) : (
<Placeholder
icon={ <Gridicon icon="tag" /> }
label={ __( 'On Sale Products', 'woo-gutenberg-products-block' ) }
>
{ ! loaded ? (
<Spinner />
) : (
__( 'No products found.', 'woo-gutenberg-products-block' )
) }
</Placeholder>
) }
</div>
</Fragment> </Fragment>
); );
} }

View File

@ -5,45 +5,6 @@
margin-right: auto; margin-right: auto;
} }
.star-rating {
overflow: hidden;
position: relative;
margin-left: auto;
margin-right: auto;
width: 5.3em;
height: 1.618em;
line-height: 1.618;
font-size: 1em;
font-family: star;
font-weight: 400;
&::before {
content: '\53\53\53\53\53';
top: 0;
left: 0;
right: 0;
position: absolute;
opacity: 0.25;
}
span {
overflow: hidden;
top: 0;
left: 0;
right: 0;
position: absolute;
padding-top: 1.5em;
}
span::before {
content: '\53\53\53\53\53';
top: 0;
left: 0;
right: 0;
position: absolute;
}
}
.wp-block-button { .wp-block-button {
margin-bottom: 0; margin-bottom: 0;
} }

View File

@ -174,9 +174,24 @@ class WGPB_Block_Library {
register_block_type( register_block_type(
'woocommerce/product-category', 'woocommerce/product-category',
array( array(
'render_callback' => array( __CLASS__, 'render_product_category' ),
'editor_script' => 'wc-product-category', 'editor_script' => 'wc-product-category',
'editor_style' => 'wc-block-editor', 'editor_style' => 'wc-block-editor',
'style' => 'wc-block-style', 'style' => 'wc-block-style',
'attributes' => array_merge(
self::get_shared_attributes(),
array(
'orderby' => array(
'type' => 'string',
'enum' => array( 'date', 'popularity', 'price_asc', 'price_desc', 'rating', 'title' ),
'default' => 'date',
),
'editMode' => array(
'type' => 'boolean',
'default' => true,
),
)
),
) )
); );
register_block_type( register_block_type(
@ -186,6 +201,7 @@ class WGPB_Block_Library {
'editor_script' => 'wc-product-new', 'editor_script' => 'wc-product-new',
'editor_style' => 'wc-block-editor', 'editor_style' => 'wc-block-editor',
'style' => 'wc-block-style', 'style' => 'wc-block-style',
'attributes' => self::get_shared_attributes(),
) )
); );
register_block_type( register_block_type(
@ -195,6 +211,16 @@ class WGPB_Block_Library {
'editor_script' => 'wc-product-on-sale', 'editor_script' => 'wc-product-on-sale',
'editor_style' => 'wc-block-editor', 'editor_style' => 'wc-block-editor',
'style' => 'wc-block-style', 'style' => 'wc-block-style',
'attributes' => array_merge(
self::get_shared_attributes(),
array(
'orderby' => array(
'type' => 'string',
'enum' => array( 'date', 'popularity', 'price_asc', 'price_desc', 'rating', 'title' ),
'default' => 'date',
),
)
),
) )
); );
register_block_type( register_block_type(
@ -308,6 +334,56 @@ class WGPB_Block_Library {
<?php <?php
} }
/**
* Get a set of attributes shared across most of the grid blocks.
*
* @return array List of block attributes with type and defaults.
*/
public static function get_shared_attributes() {
return array(
'columns' => array(
'type' => 'number',
'default' => wc_get_theme_support( 'product_blocks::default_columns', 3 ),
),
'rows' => array(
'type' => 'number',
'default' => wc_get_theme_support( 'product_blocks::default_rows', 1 ),
),
'categories' => array(
'type' => 'array',
'items' => array(
'type' => 'number',
),
'default' => array(),
),
'catOperator' => array(
'type' => 'string',
'default' => 'any',
),
'contentVisibility' => array(
'type' => 'object',
'properties' => array(
'title' => array(
'type' => 'boolean',
'default' => true,
),
'price' => array(
'type' => 'boolean',
'default' => true,
),
'rating' => array(
'type' => 'boolean',
'default' => true,
),
'button' => array(
'type' => 'boolean',
'default' => true,
),
),
),
);
}
/** /**
* New products: Include and render the dynamic block. * New products: Include and render the dynamic block.
* *
@ -335,6 +411,20 @@ class WGPB_Block_Library {
$block = new WGPB_Block_Product_On_Sale( $attributes, $content ); $block = new WGPB_Block_Product_On_Sale( $attributes, $content );
return $block->render(); return $block->render();
} }
/**
* Products by category: Include and render the dynamic block.
*
* @param array $attributes Block attributes. Default empty array.
* @param string $content Block content. Default empty string.
* @return string Rendered block type output.
*/
public static function render_product_category( $attributes, $content ) {
require_once dirname( __FILE__ ) . '/class-wgpb-block-product-category.php';
$block = new WGPB_Block_Product_Category( $attributes, $content );
return $block->render();
}
} }
WGPB_Block_Library::get_instance(); WGPB_Block_Library::get_instance();

View File

@ -0,0 +1,31 @@
<?php
/**
* Display the Products by Category block in the post content.
* NOTE: DO NOT edit this file in WooCommerce core, this is generated from woocommerce-gutenberg-products-block.
*
* @package WooCommerce\Blocks
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handler for getting Products by Category for display.
*/
class WGPB_Block_Product_Category extends WGPB_Block_Grid_Base {
/**
* Block name.
*
* @var string
*/
protected $block_name = 'product-category';
/**
* This function is not necessary in this block.
*
* @param array $query_args Query args.
*/
protected function set_block_query_args( &$query_args ) {}
}

File diff suppressed because it is too large Load Diff

View File

@ -29,17 +29,17 @@
"test:watch": "npm run test -- --watch" "test:watch": "npm run test -- --watch"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.4.4", "@babel/core": "7.4.5",
"@wordpress/babel-preset-default": "4.1.0", "@wordpress/babel-preset-default": "4.2.0",
"@wordpress/blocks": "6.2.5", "@wordpress/blocks": "6.3.0",
"@wordpress/components": "7.3.2", "@wordpress/components": "7.4.0",
"@wordpress/date": "3.2.0", "@wordpress/date": "3.3.0",
"@wordpress/editor": "9.2.5", "@wordpress/editor": "9.3.0",
"@wordpress/element": "2.3.0", "@wordpress/element": "2.4.0",
"@wordpress/i18n": "3.3.0", "@wordpress/i18n": "3.4.0",
"@wordpress/jest-preset-default": "4.0.0", "@wordpress/jest-preset-default": "4.1.0",
"@wordpress/rich-text": "3.2.3", "@wordpress/rich-text": "3.3.0",
"@wordpress/scripts": "3.1.0", "@wordpress/scripts": "3.2.1",
"autoprefixer": "9.5.1", "autoprefixer": "9.5.1",
"babel-core": "7.0.0-bridge.0", "babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1", "babel-eslint": "10.0.1",
@ -47,13 +47,13 @@
"chalk": "2.4.2", "chalk": "2.4.2",
"classnames": "2.2.6", "classnames": "2.2.6",
"clean-webpack-plugin": "2.0.2", "clean-webpack-plugin": "2.0.2",
"core-js": "2.6.7", "core-js": "3.1.2",
"cross-env": "5.2.0", "cross-env": "5.2.0",
"css-loader": "2.1.1", "css-loader": "2.1.1",
"cssnano": "4.1.10", "cssnano": "4.1.10",
"eslint": "5.16.0", "eslint": "5.16.0",
"eslint-config-wordpress": "2.0.0", "eslint-config-wordpress": "2.0.0",
"eslint-plugin-jest": "22.5.1", "eslint-plugin-jest": "22.6.4",
"eslint-plugin-jsx-a11y": "6.2.1", "eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.13.0", "eslint-plugin-react": "7.13.0",
"eslint-plugin-wordpress": "git://github.com/WordPress-Coding-Standards/eslint-plugin-wordpress.git#1774343f6226052a46b081e01db3fca8793cc9f1", "eslint-plugin-wordpress": "git://github.com/WordPress-Coding-Standards/eslint-plugin-wordpress.git#1774343f6226052a46b081e01db3fca8793cc9f1",
@ -73,7 +73,7 @@
"style-loader": "0.23.1", "style-loader": "0.23.1",
"stylelint": "10.0.1", "stylelint": "10.0.1",
"stylelint-config-wordpress": "14.0.0", "stylelint-config-wordpress": "14.0.0",
"webpack": "4.32.0", "webpack": "4.32.2",
"webpack-cli": "3.3.2", "webpack-cli": "3.3.2",
"yargs": "13.2.4" "yargs": "13.2.4"
}, },