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:
commit
5181982750
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}),
|
||||
" ",
|
||||
|
|
|
@ -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 &&
|
||||
|
|
Loading…
Reference in New Issue