Merge pull request woocommerce/woocommerce-blocks#27 from woocommerce/category-select-indeterminate-first-load

Checkbox indeterminate state and reveal accordions on first load
This commit is contained in:
Claudiu Lodromanean 2018-02-21 09:17:18 -08:00 committed by GitHub
commit 5181982750
5 changed files with 198 additions and 20 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -208,6 +208,10 @@
li {
margin: 5px 0;
ul {
padding: 0px 0 0 25px;
}
}
}
}
@ -353,6 +357,19 @@
padding-top: 0;
border: 0;
}
input[type="checkbox"] {
&:indeterminate {
&:before {
content: '';
display: inline-block;
margin: 6px 0 0 0px;
width: 8px;
height: 2px;
background: #1e8cbe;
}
}
}
}
@media only screen and (min-width: 700px) {

View File

@ -1221,13 +1221,15 @@ var ProductsCategorySelect = exports.ProductsCategorySelect = function (_React$C
_this.state = {
selectedCategories: props.selected_display_setting,
openAccordion: null,
filterQuery: ''
openAccordion: [],
filterQuery: '',
firstLoad: true
};
_this.checkboxChange = _this.checkboxChange.bind(_this);
_this.accordionToggle = _this.accordionToggle.bind(_this);
_this.filterResults = _this.filterResults.bind(_this);
_this.setFirstLoad = _this.setFirstLoad.bind(_this);
return _this;
}
@ -1270,14 +1272,18 @@ var ProductsCategorySelect = exports.ProductsCategorySelect = function (_React$C
}, {
key: "accordionToggle",
value: function accordionToggle(category) {
var value = category;
var openAccordions = this.state.openAccordion;
if (value === this.state.openAccordion) {
value = null;
if (openAccordions.includes(category)) {
openAccordions = openAccordions.filter(function (c) {
return c !== category;
});
} else {
openAccordions.push(category);
}
this.setState({
openAccordion: value
openAccordion: openAccordions
});
}
@ -1295,6 +1301,20 @@ var ProductsCategorySelect = exports.ProductsCategorySelect = function (_React$C
});
}
/**
* Update firstLoad state.
*
* @param Booolean loaded
*/
}, {
key: "setFirstLoad",
value: function setFirstLoad(loaded) {
this.setState({
firstLoad: !!loaded
});
}
/**
* Render the list of categories and the search input.
*/
@ -1311,7 +1331,9 @@ var ProductsCategorySelect = exports.ProductsCategorySelect = function (_React$C
selectedCategories: this.state.selectedCategories,
checkboxChange: this.checkboxChange,
accordionToggle: this.accordionToggle,
openAccordion: this.state.openAccordion
openAccordion: this.state.openAccordion,
firstLoad: this.state.firstLoad,
setFirstLoad: this.setFirstLoad
})
);
}
@ -1348,7 +1370,9 @@ var ProductCategoryList = withAPIData(function (props) {
selectedCategories = _ref2.selectedCategories,
checkboxChange = _ref2.checkboxChange,
accordionToggle = _ref2.accordionToggle,
openAccordion = _ref2.openAccordion;
openAccordion = _ref2.openAccordion,
firstLoad = _ref2.firstLoad,
setFirstLoad = _ref2.setFirstLoad;
if (!categories.data) {
return __('Loading');
@ -1385,13 +1409,55 @@ var ProductCategoryList = withAPIData(function (props) {
return !!getCategoryChildren(parent, categories).length;
};
var isIndeterminate = function isIndeterminate(category, categories) {
// Currect category selected?
if (selectedCategories.includes(category.id)) {
return false;
}
// Has children?
var children = getCategoryChildren(category, categories).map(function (category) {
return category.id;
});
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var child = _step.value;
if (selectedCategories.includes(child)) {
return true;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return false;
};
var AccordionButton = function AccordionButton(_ref3) {
var category = _ref3.category,
categories = _ref3.categories;
var icon = 'arrow-down-alt2';
if (openAccordion === category.id) {
if (openAccordion.includes(category.id)) {
icon = 'arrow-up-alt2';
}
@ -1420,13 +1486,51 @@ var ProductCategoryList = withAPIData(function (props) {
return category.parent === parent;
});
if (firstLoad && selectedCategories.length > 0) {
categoriesData.filter(function (category) {
return category.parent === 0;
}).forEach(function (category) {
var children = getCategoryChildren(category, categoriesData);
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = children[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var child = _step2.value;
if (selectedCategories.includes(child.id) && !openAccordion.includes(category.id)) {
accordionToggle(category.id);
break;
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
});
setFirstLoad(false);
}
return filteredCategories.length > 0 && wp.element.createElement(
"ul",
null,
filteredCategories.map(function (category) {
return wp.element.createElement(
"li",
{ key: category.id, className: openAccordion === category.id ? 'product-category-accordion-open' : '' },
{ key: category.id, className: openAccordion.includes(category.id) ? 'product-category-accordion-open' : '' },
wp.element.createElement(
"label",
{ htmlFor: 'product-category-' + category.id },
@ -1436,6 +1540,9 @@ var ProductCategoryList = withAPIData(function (props) {
checked: selectedCategories.includes(category.id),
onChange: function onChange(evt) {
return handleCategoriesToCheck(evt, category, categories);
},
ref: function ref(el) {
return el && (el.indeterminate = isIndeterminate(category, categories));
}
}),
" ",

View File

@ -14,13 +14,15 @@ export class ProductsCategorySelect extends React.Component {
this.state = {
selectedCategories: props.selected_display_setting,
openAccordion: null,
openAccordion: [],
filterQuery: '',
firstLoad: true,
}
this.checkboxChange = this.checkboxChange.bind( this );
this.accordionToggle = this.accordionToggle.bind( this );
this.filterResults = this.filterResults.bind( this );
this.setFirstLoad = this.setFirstLoad.bind( this );
}
/**
@ -51,14 +53,16 @@ export class ProductsCategorySelect extends React.Component {
* @param Category ID category
*/
accordionToggle( category ) {
let value = category;
let openAccordions = this.state.openAccordion;
if ( value === this.state.openAccordion ) {
value = null;
if ( openAccordions.includes( category ) ) {
openAccordions = openAccordions.filter( c => c !== category );
} else {
openAccordions.push( category );
}
this.setState( {
openAccordion: value
openAccordion: openAccordions
} );
}
@ -73,6 +77,17 @@ export class ProductsCategorySelect extends React.Component {
} );
}
/**
* Update firstLoad state.
*
* @param Booolean loaded
*/
setFirstLoad( loaded ) {
this.setState( {
firstLoad: !! loaded
} );
}
/**
* Render the list of categories and the search input.
*/
@ -86,6 +101,8 @@ export class ProductsCategorySelect extends React.Component {
checkboxChange={ this.checkboxChange }
accordionToggle={ this.accordionToggle }
openAccordion={ this.state.openAccordion }
firstLoad={ this.state.firstLoad }
setFirstLoad={ this.setFirstLoad }
/>
</div>
);
@ -110,7 +127,7 @@ const ProductCategoryList = withAPIData( ( props ) => {
return {
categories: '/wc/v2/products/categories'
};
} )( ( { categories, filterQuery, selectedCategories, checkboxChange, accordionToggle, openAccordion } ) => {
} )( ( { categories, filterQuery, selectedCategories, checkboxChange, accordionToggle, openAccordion, firstLoad, setFirstLoad } ) => {
if ( ! categories.data ) {
return __( 'Loading' );
}
@ -144,10 +161,31 @@ const ProductCategoryList = withAPIData( ( props ) => {
return !! getCategoryChildren( parent, categories ).length;
};
const isIndeterminate = ( category, categories ) => {
// Currect category selected?
if ( selectedCategories.includes( category.id ) ) {
return false;
}
// Has children?
let children = getCategoryChildren( category, categories ).map( category => {
return category.id;
} );
for ( let child of children ) {
if ( selectedCategories.includes( child ) ) {
return true;
}
}
return false;
}
const AccordionButton = ( { category, categories } ) => {
let icon = 'arrow-down-alt2';
if ( openAccordion === category.id ) {
if ( openAccordion.includes( category.id ) ) {
icon = 'arrow-up-alt2';
}
@ -169,16 +207,32 @@ const ProductCategoryList = withAPIData( ( props ) => {
const CategoryTree = ( { categories, parent } ) => {
let filteredCategories = categories.filter( ( category ) => category.parent === parent );
if ( firstLoad && selectedCategories.length > 0 ) {
categoriesData.filter( ( category ) => category.parent === 0 ).forEach( function( category ) {
let children = getCategoryChildren( category, categoriesData );
for ( let child of children ) {
if ( selectedCategories.includes( child.id ) && ! openAccordion.includes( category.id ) ) {
accordionToggle( category.id );
break;
}
}
} );
setFirstLoad( false );
}
return ( filteredCategories.length > 0 ) && (
<ul>
{ filteredCategories.map( ( category ) => (
<li key={ category.id } className={ ( openAccordion === category.id ? 'product-category-accordion-open' : '' ) }>
<li key={ category.id } className={ ( openAccordion.includes( category.id ) ? 'product-category-accordion-open' : '' ) }>
<label htmlFor={ 'product-category-' + category.id }>
<input type="checkbox"
id={ 'product-category-' + category.id }
value={ category.id }
checked={ selectedCategories.includes( category.id ) }
onChange={ ( evt ) => handleCategoriesToCheck( evt, category, categories ) }
ref={ el => el && ( el.indeterminate = isIndeterminate( category, categories ) ) }
/> { category.name }
<span className="product-category-count">{ category.count }</span>
{ 0 === category.parent &&