Skip to content

Commit 99073cd

Browse files
committed
fix(stats): Move CSS classes definition to widget from component
We can now easily spot in default.css which widget are not yet BEMified (yeah, that's a verb now). - Moved the BEM definition to widget instead of component - Updated the tests - This widget is using the headerFooter decorator, I updated the docs - The initial root class was added twice because we already used it in the default template. I removed the wrapping div in the template. BREAKING CHANGE: `cssClasses.root` now applies to the main root element (above header and footer) and no longer to the template wrapper. To style the template wrapper, use `cssClasses.body`
1 parent 3f72635 commit 99073cd

File tree

7 files changed

+72
-36
lines changed

7 files changed

+72
-36
lines changed

README.md

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -352,26 +352,22 @@ search.addWidget(
352352
/**
353353
* Display various stats about the current search state
354354
* @param {String|DOMElement} options.container CSS Selector or DOMElement to insert the widget
355-
* @param {Object} [options.cssClasses] CSS classes to add to the default template
355+
* @param {Object} [options.cssClasses] CSS classes to add
356356
* @param {String} [options.cssClasses.root] CSS class to add to the root element
357+
* @param {String} [options.cssClasses.header] CSS class to add to the header element
358+
* @param {String} [options.cssClasses.body] CSS class to add to the body element
359+
* @param {String} [options.cssClasses.footer] CSS class to add to the footer element
357360
* @param {String} [options.cssClasses.time] CSS class to add to the element wrapping the time processingTimeMs
358361
* @param {Object} [options.templates] Templates to use for the widget
359362
* @param {String|Function} [options.templates.header=''] Header template
360-
* @param {String|Function} [options.templates.body='<div class="{{cssClasses.root}}">
361-
{{#hasNoResults}}No results{{/hasNoResults}}
362-
{{#hasOneResult}}1 result{{/hasOneResult}}
363-
{{#hasManyResults}}{{#helpers.formatNumber}}{{nbHits}}{{/helpers.formatNumber}} results{{/hasManyResults}}
364-
<span class="{{cssClasses.time}}">found in {{processingTimeMS}}ms</span>
365-
</div>'] Body template
363+
* @param {String|Function} [options.templates.body] Body template
366364
* @param {String|Function} [options.templates.footer=''] Footer template
367365
* @param {Function} [options.transformData] Function to change the object passed to the `body` template
368366
* @param {boolean} [hideWhenNoResults=true] Hide the container when there's no results
369367
* @return {Object}
370368
*/
371369
```
372370

373-
374-
375371
#### Usage
376372

377373
```html
@@ -389,6 +385,32 @@ search.addWidget(
389385
);
390386
```
391387

388+
### Styling
389+
390+
```html
391+
<div class="ais-stats">
392+
<div class="ais-stats--header ais-header">[custom header template]</div>
393+
<div class="ais-stats--body">
394+
42 results found in <span class="ais-stats--time">42ms</span>
395+
</div>
396+
<div class="ais-stats--footer ais-footer">[custom footer template]</div>
397+
</div>
398+
```
399+
400+
```css
401+
.ais-stats {
402+
}
403+
.ais-stats--header {
404+
}
405+
.ais-stats--body {
406+
}
407+
.ais-stats--time {
408+
font-size: small;
409+
}
410+
.ais-stats--footer {
411+
}
412+
```
413+
392414
### indexSelector
393415

394416
![Example of the indexSelector widget][indexSelector]
@@ -623,7 +645,7 @@ search.addWidget(
623645
* @param {String} [options.operator='or'] How to apply refinements. Possible values: `or`, `and`
624646
* @param {String[]} [options.sortBy=['count:desc']] How to sort refinements. Possible values: `count|isRefined|name:asc|desc`
625647
* @param {String} [options.limit=1000] How much facet values to get
626-
* @param {Object} [options.cssClasses] CSS classes to add to the wrapping elements: root, list, item
648+
* @param {Object} [options.cssClasses] CSS classes to add
627649
* @param {String|String[]} [options.cssClasses.root] CSS class to add to the root element
628650
* @param {String|String[]} [options.cssClasses.header] CSS class to add to the header element
629651
* @param {String|String[]} [options.cssClasses.body] CSS class to add to the body element

components/Stats/Stats.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
var React = require('react');
22

33
var Template = require('../Template');
4-
var bem = require('../../lib/utils').bemHelper('ais-stats');
5-
var cx = require('classnames');
64

75
class Stats extends React.Component {
86
render() {
@@ -16,10 +14,7 @@ class Stats extends React.Component {
1614
page: this.props.page,
1715
processingTimeMS: this.props.processingTimeMS,
1816
query: this.props.query,
19-
cssClasses: {
20-
root: cx(bem(null), this.props.cssClasses.root),
21-
time: cx(bem('time'), this.props.cssClasses.time)
22-
}
17+
cssClasses: this.props.cssClasses
2318
};
2419

2520
return (
@@ -29,6 +24,12 @@ class Stats extends React.Component {
2924
}
3025

3126
Stats.propTypes = {
27+
cssClasses: React.PropTypes.shape({
28+
time: React.PropTypes.oneOfType([
29+
React.PropTypes.string,
30+
React.PropTypes.arrayOf(React.PropTypes.string)
31+
])
32+
}),
3233
hitsPerPage: React.PropTypes.number,
3334
nbHits: React.PropTypes.number,
3435
nbPages: React.PropTypes.number,

components/Stats/__tests__/Stats-test.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ import TestUtils from 'react-addons-test-utils';
66
import Stats from '../Stats';
77
import Template from '../../Template';
88

9-
var bem = require('../../../lib/utils').bemHelper('ais-stats');
10-
var cx = require('classnames');
11-
129
describe('Stats', () => {
1310
var renderer;
1411

@@ -21,10 +18,7 @@ describe('Stats', () => {
2118
it('should render <Template data= />', () => {
2219
var out = render();
2320
var defaultProps = {
24-
cssClasses: {
25-
root: cx(bem(null)),
26-
time: cx(bem('time'))
27-
},
21+
cssClasses: {},
2822
hasManyResults: true,
2923
hasNoResults: false,
3024
hasOneResult: false

themes/default/default.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@
2727
/* STATS */
2828
.ais-stats {
2929
}
30+
.ais-stats--header {
31+
}
32+
.ais-stats--body {
33+
}
3034
.ais-stats--time {
3135
font-size: small;
3236
}
37+
.ais-stats--footer {
38+
}
3339

3440
/* INDEX SELECTOR */
3541
.ais-index-selector {
@@ -51,7 +57,7 @@
5157
}
5258
.ais-pagination--item-previous {
5359
}
54-
.ais-pagination--item-page {
60+
.ais-pagination--item-page {
5561
}
5662
.ais-pagination--item-page__active {
5763
}

widgets/stats/__tests__/stats-test.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ describe('stats()', () => {
5151
expect(headerFooter.calledOnce).toBe(true, 'headerFooter called once');
5252
expect(ReactDOM.render.firstCall.args[0]).toEqualJSX(
5353
<Stats
54-
cssClasses={{}}
54+
cssClasses={{
55+
body: 'ais-stats--body',
56+
header: 'ais-stats--header',
57+
footer: 'ais-stats--footer',
58+
root: 'ais-stats',
59+
time: 'ais-stats--time'
60+
}}
5561
hasResults={true}
5662
hideWhenNoResults={true}
5763
hitsPerPage={2}

widgets/stats/defaultTemplates.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
module.exports = {
22
header: '',
3-
body: `<div class="{{cssClasses.root}}">
4-
{{#hasNoResults}}No results{{/hasNoResults}}
3+
body: `{{#hasNoResults}}No results{{/hasNoResults}}
54
{{#hasOneResult}}1 result{{/hasOneResult}}
65
{{#hasManyResults}}{{#helpers.formatNumber}}{{nbHits}}{{/helpers.formatNumber}} results{{/hasManyResults}}
7-
<span class="{{cssClasses.time}}">found in {{processingTimeMS}}ms</span>
8-
</div>`,
6+
<span class="{{cssClasses.time}}">found in {{processingTimeMS}}ms</span>`,
97
footer: ''
108
};

widgets/stats/stats.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ var ReactDOM = require('react-dom');
44
var utils = require('../../lib/utils.js');
55
var autoHide = require('../../decorators/autoHide');
66
var headerFooter = require('../../decorators/headerFooter');
7+
var bem = require('../../lib/utils').bemHelper('ais-stats');
8+
var cx = require('classnames/dedupe');
79

810
var defaultTemplates = require('./defaultTemplates.js');
911

1012
/**
1113
* Display various stats about the current search state
1214
* @param {String|DOMElement} options.container CSS Selector or DOMElement to insert the widget
13-
* @param {Object} [options.cssClasses] CSS classes to add to the default template
15+
* @param {Object} [options.cssClasses] CSS classes to add
1416
* @param {String} [options.cssClasses.root] CSS class to add to the root element
17+
* @param {String} [options.cssClasses.header] CSS class to add to the header element
18+
* @param {String} [options.cssClasses.body] CSS class to add to the body element
19+
* @param {String} [options.cssClasses.footer] CSS class to add to the footer element
1520
* @param {String} [options.cssClasses.time] CSS class to add to the element wrapping the time processingTimeMs
1621
* @param {Object} [options.templates] Templates to use for the widget
1722
* @param {String|Function} [options.templates.header=''] Header template
18-
* @param {String|Function} [options.templates.body='<div class="{{cssClasses.root}}">
19-
{{#hasNoResults}}No results{{/hasNoResults}}
20-
{{#hasOneResult}}1 result{{/hasOneResult}}
21-
{{#hasManyResults}}{{#helpers.formatNumber}}{{nbHits}}{{/helpers.formatNumber}} results{{/hasManyResults}}
22-
<span class="{{cssClasses.time}}">found in {{processingTimeMS}}ms</span>
23-
</div>'] Body template
23+
* @param {String|Function} [options.templates.body] Body template
2424
* @param {String|Function} [options.templates.footer=''] Footer template
2525
* @param {Function} [options.transformData] Function to change the object passed to the `body` template
2626
* @param {boolean} [hideWhenNoResults=true] Hide the container when there's no results
@@ -49,6 +49,15 @@ function stats({
4949
});
5050

5151
var Stats = autoHide(headerFooter(require('../../components/Stats/Stats.js')));
52+
53+
cssClasses = {
54+
body: cx(bem('body'), cssClasses.body),
55+
footer: cx(bem('footer'), cssClasses.footer),
56+
header: cx(bem('header'), cssClasses.header),
57+
root: cx(bem(null), cssClasses.root),
58+
time: cx(bem('time'), cssClasses.time)
59+
};
60+
5261
ReactDOM.render(
5362
<Stats
5463
cssClasses={cssClasses}

0 commit comments

Comments
 (0)