* Move heading toolbar component so it can be resused

* Add heading to attribute block

* Add heading to price filter block

* Fix missing loading state
This commit is contained in:
Mike Jolley 2019-11-13 16:15:20 +00:00 committed by GitHub
parent 9c9b248c6d
commit a84990d10f
10 changed files with 167 additions and 45 deletions

View File

@ -8,12 +8,12 @@ import { Disabled, PanelBody, ToggleControl } from '@wordpress/components';
import { InspectorControls } from '@wordpress/editor';
import { ProductTitle } from '@woocommerce/atomic-components/product';
import { previewProducts } from '@woocommerce/resource-previews';
import HeadingToolbar from '@woocommerce/block-components/heading-toolbar';
/**
* Internal dependencies
*/
import sharedConfig from '../shared-config';
import HeadingToolbar from './heading-toolbar';
const blockConfig = {
title: __( 'Product Title', 'woo-gutenberg-products-block' ),

View File

@ -25,7 +25,7 @@ import { getTaxonomyFromAttributeId } from '../../utils/attributes';
/**
* Component displaying an attribute filter.
*/
const AttributeFilterBlock = ( { attributes } ) => {
const AttributeFilterBlock = ( { attributes, isPreview = false } ) => {
const [ options, setOptions ] = useState( [] );
const [ checkedOptions, setCheckedOptions ] = useState( [] );
const { showCounts, attributeId, queryType } = attributes;
@ -168,19 +168,26 @@ const AttributeFilterBlock = ( { attributes } ) => {
setCheckedOptions( checked );
}, [] );
if ( ! taxonomy ) {
if ( ! taxonomy || ( options.length === 0 && ! attributeTermsLoading ) ) {
return null;
}
const TagName = `h${ attributes.headingLevel }`;
return (
<div className="wc-block-attribute-filter">
<CheckboxList
className={ 'wc-block-attribute-filter-list' }
options={ options }
onChange={ onChange }
isLoading={ attributeTermsLoading }
/>
</div>
<Fragment>
{ ! isPreview && attributes.heading && (
<TagName>{ attributes.heading }</TagName>
) }
<div className="wc-block-attribute-filter">
<CheckboxList
className={ 'wc-block-attribute-filter-list' }
options={ options }
onChange={ onChange }
isLoading={ attributeTermsLoading }
/>
</div>
</Fragment>
);
};

View File

@ -3,7 +3,7 @@
*/
import { __, sprintf, _n } from '@wordpress/i18n';
import { Fragment, useState, useCallback } from '@wordpress/element';
import { InspectorControls, BlockControls } from '@wordpress/editor';
import { InspectorControls, BlockControls, PlainText } from '@wordpress/editor';
import {
Placeholder,
Disabled,
@ -15,9 +15,10 @@ import {
} from '@wordpress/components';
import Gridicon from 'gridicons';
import { SearchListControl } from '@woocommerce/components';
import { mapValues, toArray, sortBy } from 'lodash';
import { mapValues, toArray, sortBy, find } from 'lodash';
import { ATTRIBUTES } from '@woocommerce/block-settings';
import { getAdminLink } from '@woocommerce/navigation';
import HeadingToolbar from '@woocommerce/block-components/heading-toolbar';
/**
* Internal dependencies
@ -78,6 +79,21 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak } ) => {
} )
}
/>
<p>
{ __(
'Heading Level',
'woo-gutenberg-products-block'
) }
</p>
<HeadingToolbar
isCollapsed={ false }
minLevel={ 2 }
maxLevel={ 7 }
selectedLevel={ attributes.headingLevel }
onChange={ ( newLevel ) =>
setAttributes( { headingLevel: newLevel } )
}
/>
</PanelBody>
<PanelBody
title={ __(
@ -190,8 +206,25 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak } ) => {
}, [] );
const onChange = useCallback( ( selected ) => {
const selectedId = selected[ 0 ].id;
const productAttribute = find( ATTRIBUTES, [
'attribute_id',
selectedId.toString(),
] );
if ( ! productAttribute || attributes.attributeId === selectedId ) {
return;
}
const attributeName = productAttribute.attribute_name;
setAttributes( {
attributeId: selected[ 0 ].id,
attributeId: selectedId,
heading: sprintf(
// Translators: %s attribute name.
__( 'Filter by %s', 'woo-gutenberg-products-block' ),
attributeName
),
} );
}, [] );
@ -276,6 +309,8 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak } ) => {
);
};
const TagName = `h${ attributes.headingLevel }`;
return Object.keys( ATTRIBUTES ).length === 0 ? (
noAttributesPlaceholder()
) : (
@ -285,9 +320,20 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak } ) => {
{ isEditing ? (
renderEditMode()
) : (
<Disabled>
<Block attributes={ attributes } isPreview />
</Disabled>
<Fragment>
<TagName>
<PlainText
className="wc-block-attribute-filter-heading"
value={ attributes.heading }
onChange={ ( value ) =>
setAttributes( { heading: value } )
}
/>
</TagName>
<Disabled>
<Block attributes={ attributes } isPreview />
</Disabled>
</Fragment>
) }
</Fragment>
);

View File

@ -10,6 +10,8 @@ const getProps = ( el ) => {
attributeId: parseInt( el.dataset.attributeId || 0, 10 ),
showCounts: el.dataset.showCounts === 'true',
queryType: el.dataset.queryType,
heading: el.dataset.heading,
headingLevel: el.dataset.headingLevel || 3,
},
};
};

View File

@ -22,9 +22,7 @@ registerBlockType( 'woocommerce/attribute-filter', {
'Display a list of filters based on a chosen product attribute.',
'woo-gutenberg-products-block'
),
supports: {
align: [ 'wide', 'full' ],
},
supports: {},
attributes: {
attributeId: {
type: 'number',
@ -38,18 +36,38 @@ registerBlockType( 'woocommerce/attribute-filter', {
type: 'string',
default: 'or',
},
heading: {
type: 'string',
default: __(
'Filter by attribute',
'woo-gutenberg-products-block'
),
},
headingLevel: {
type: 'number',
default: 3,
},
},
edit,
/**
* Save the props to post content.
*/
save( { attributes } ) {
const { showCounts, displayStyle, queryType, attributeId } = attributes;
const {
showCounts,
displayStyle,
queryType,
attributeId,
heading,
headingLevel,
} = attributes;
const data = {
'data-attribute-id': attributeId,
'data-show-counts': showCounts,
'data-display-style': displayStyle,
'data-query-type': queryType,
'data-heading': heading,
'data-heading-level': headingLevel,
};
return (
<div className="is-loading" { ...data }>

View File

@ -6,14 +6,14 @@ import {
useQueryStateByKey,
useQueryStateByContext,
} from '@woocommerce/base-hooks';
import { useCallback } from '@wordpress/element';
import { useCallback, Fragment } from '@wordpress/element';
import PriceSlider from '@woocommerce/base-components/price-slider';
import { CURRENCY } from '@woocommerce/settings';
/**
* Component displaying a price filter.
*/
const PriceFilterBlock = ( { attributes } ) => {
const PriceFilterBlock = ( { attributes, isPreview = false } ) => {
const [ minPrice, setMinPrice ] = useQueryStateByKey(
'product-grid',
'min_price'
@ -65,22 +65,29 @@ const PriceFilterBlock = ( { attributes } ) => {
[ minConstraint, maxConstraint, minPrice, maxPrice ]
);
const TagName = `h${ attributes.headingLevel }`;
return (
<div className="wc-block-price-slider">
<PriceSlider
minConstraint={ minConstraint }
maxConstraint={ maxConstraint }
initialMin={ undefined }
initialMax={ undefined }
step={ 10 }
currencySymbol={ CURRENCY.symbol }
priceFormat={ CURRENCY.price_format }
showInputFields={ showInputFields }
showFilterButton={ showFilterButton }
onChange={ onChange }
isLoading={ isLoading }
/>
</div>
<Fragment>
{ ! isPreview && attributes.heading && (
<TagName>{ attributes.heading }</TagName>
) }
<div className="wc-block-price-slider">
<PriceSlider
minConstraint={ minConstraint }
maxConstraint={ maxConstraint }
initialMin={ undefined }
initialMax={ undefined }
step={ 10 }
currencySymbol={ CURRENCY.symbol }
priceFormat={ CURRENCY.price_format }
showInputFields={ showInputFields }
showFilterButton={ showFilterButton }
onChange={ onChange }
isLoading={ isLoading }
/>
</div>
</Fragment>
);
};

View File

@ -3,7 +3,7 @@
*/
import { __ } from '@wordpress/i18n';
import { Fragment } from '@wordpress/element';
import { InspectorControls } from '@wordpress/editor';
import { InspectorControls, PlainText } from '@wordpress/editor';
import {
Placeholder,
Disabled,
@ -13,6 +13,7 @@ import {
} from '@wordpress/components';
import { PRODUCT_COUNT } from '@woocommerce/block-settings';
import { getAdminLink } from '@woocommerce/navigation';
import HeadingToolbar from '@woocommerce/block-components/heading-toolbar';
/**
* Internal dependencies
@ -85,6 +86,21 @@ export default function( { attributes, setAttributes } ) {
} )
}
/>
<p>
{ __(
'Heading Level',
'woo-gutenberg-products-block'
) }
</p>
<HeadingToolbar
isCollapsed={ false }
minLevel={ 2 }
maxLevel={ 7 }
selectedLevel={ attributes.headingLevel }
onChange={ ( newLevel ) =>
setAttributes( { headingLevel: newLevel } )
}
/>
</PanelBody>
</InspectorControls>
);
@ -129,6 +145,8 @@ export default function( { attributes, setAttributes } ) {
</Placeholder>
);
const TagName = `h${ attributes.headingLevel }`;
return (
<Fragment>
{ PRODUCT_COUNT === 0 ? (
@ -136,6 +154,15 @@ export default function( { attributes, setAttributes } ) {
) : (
<Fragment>
{ getInspectorControls() }
<TagName>
<PlainText
className="wc-block-attribute-filter-heading"
value={ attributes.heading }
onChange={ ( value ) =>
setAttributes( { heading: value } )
}
/>
</TagName>
<Disabled>
<Block attributes={ attributes } isPreview />
</Disabled>

View File

@ -22,10 +22,7 @@ registerBlockType( 'woocommerce/price-filter', {
'Display a slider to filter products in your store by price.',
'woo-gutenberg-products-block'
),
supports: {
align: [ 'wide', 'full' ],
},
supports: {},
attributes: {
showInputFields: {
type: 'boolean',
@ -35,6 +32,14 @@ registerBlockType( 'woocommerce/price-filter', {
type: 'boolean',
default: false,
},
heading: {
type: 'string',
default: __( 'Filter by price', 'woo-gutenberg-products-block' ),
},
headingLevel: {
type: 'number',
default: 3,
},
},
edit,
@ -43,14 +48,24 @@ registerBlockType( 'woocommerce/price-filter', {
* Save the props to post content.
*/
save( { attributes } ) {
const { showInputFields, showFilterButton } = attributes;
const {
showInputFields,
showFilterButton,
heading,
headingLevel,
} = attributes;
const data = {
'data-showinputfields': showInputFields,
'data-showfilterbutton': showFilterButton,
'data-heading': heading,
'data-heading-level': headingLevel,
};
return (
<div className="is-loading" { ...data }>
<span aria-hidden className="wc-block-product-categories__placeholder" />
<span
aria-hidden
className="wc-block-product-categories__placeholder"
/>
</div>
);
},