Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion dev/app/builtin/stories/hits.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export default () => {
window.search.addWidget(
instantsearch.widgets.hits({
container,
escapeHits: true,
templates: {
item: `
<div class="hit" id="hit-{{objectID}}">
Expand Down
8 changes: 4 additions & 4 deletions dev/app/builtin/stories/infinite-hits.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default () => {
window.search.addWidget(
instantsearch.widgets.infiniteHits({
container,
showMoreLabel: 'Show more',
loadMoreLabel: 'Show more',
templates: {
item: '{{name}}',
},
Expand All @@ -34,9 +34,9 @@ export default () => {
window.search.addWidget(
instantsearch.widgets.infiniteHits({
container,
showMoreLabel: 'Show more',
loadMoreLabel: 'Show more',
cssClasses: {
showmore: 'button',
loadMore: 'button',
},
templates: {
item: '{{name}}',
Expand All @@ -51,7 +51,7 @@ export default () => {
window.search.addWidget(
instantsearch.widgets.infiniteHits({
container,
showMoreLabel: 'Show more',
loadMoreLabel: 'Show more',
templates: {
item: '{{name}}',
},
Expand Down
2 changes: 1 addition & 1 deletion dev/app/init-unmount-widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export default () => {
wrapWithUnmount(container =>
instantsearch.widgets.infiniteHits({
container,
showMoreLabel: 'Show more',
loadMoreLabel: 'Show more',
templates: {
item: '{{name}}',
},
Expand Down
110 changes: 110 additions & 0 deletions docgen/src/guides/v3-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,116 @@ InstantSearch 3 introduces some breaking changes in the widget's naming, options

## Widgets

### Hits

#### Options

| Before | After |
| --------------- | --------------- |
| `escapeHits` | `escapeHTML` |
| `showMoreLabel` | `loadMoreLabel` |

* `escapeHTML` becomes `true` by default.
* `allItems` template has been removed in favor of `connectHits`

#### CSS classes

| Before | After |
| ----------------- | ----------------- |
| `ais-hits` | `ais-Hits` |
| `ais-hits--empty` | `ais-Hits--empty` |
| | `ais-Hits--list` |
| `ais-hits--item` | `ais-Hits--item` |

#### Markup

```html
<div class="ais-Hits">
<ol class="ais-Hits-list">
<li class="ais-Hits-item">
Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black
</li>
<li class="ais-Hits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-Hits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-Hits-item">
Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black
</li>
<li class="ais-Hits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-Hits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-Hits-item">
Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black
</li>
<li class="ais-Hits-item">
Hit 4397400: Google - Chromecast - Black
</li>
</ol>
</div>
```

### InfiniteHits

#### Options

| Before | After |
| ------------ | ------------ |
| `escapeHits` | `escapeHTML` |

`escapeHTML` becomes `true` by default.

#### CSS classes

| Before | After |
| ----------------------------------- | ------------------------------------- |
| `ais-infinite-hits` | `ais-InfiniteHits` |
| `ais-infinite-hits--empty` | `ais-InfiniteHits--empty` |
| | `ais-InfiniteHits--list` |
| `ais-infinite-hits--item` | `ais-InfiniteHits--item` |
| `ais-infinite-hits--showmore` | |
| `ais-infinite-hits--showmoreButton` | `ais-InfiniteHits-loadMore` |
| | `ais-InfiniteHits-loadMore--disabled` |

#### Markup

```html
<div class="ais-InfiniteHits">
<ol class="ais-InfiniteHits-list">
<li class="ais-InfiniteHits-item">
Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 4397400: Google - Chromecast - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black
</li>
<li class="ais-InfiniteHits-item">
Hit 4397400: Google - Chromecast - Black
</li>
</ol>

<button class="ais-InfiniteHits-loadMore">Show more results</button>
```

### Stats

#### CSS classes
Expand Down
46 changes: 13 additions & 33 deletions src/components/Hits.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import PropTypes from 'prop-types';
import React, { Component } from 'preact-compat';
import map from 'lodash/map';
import Template from './Template.js';
import hasKey from 'lodash/has';
import cx from 'classnames';

class Hits extends Component {
renderWithResults() {
renderResults() {
const renderedHits = map(this.props.hits, (hit, position) => {
const data = {
...hit,
__hitIndex: position,
};

return (
<Template
rootTagName="li"
data={data}
key={data.objectID}
rootProps={{ className: this.props.cssClasses.item }}
Expand All @@ -23,30 +24,19 @@ class Hits extends Component {
);
});

return <div className={this.props.cssClasses.root}>{renderedHits}</div>;
}

renderAllResults() {
const className = cx(
this.props.cssClasses.root,
this.props.cssClasses.allItems
);

return (
<Template
data={this.props.results}
rootProps={{ className }}
templateKey="allItems"
{...this.props.templateProps}
/>
<div className={this.props.cssClasses.root}>
<ol className={this.props.cssClasses.list}>{renderedHits}</ol>
</div>
);
}

renderNoResults() {
renderEmpty() {
const className = cx(
this.props.cssClasses.root,
this.props.cssClasses.empty
this.props.cssClasses.emptyRoot
);

return (
<Template
data={this.props.results}
Expand All @@ -59,31 +49,21 @@ class Hits extends Component {

render() {
const hasResults = this.props.results.hits.length > 0;
const hasAllItemsTemplate = hasKey(
this.props,
'templateProps.templates.allItems'
);

if (!hasResults) {
return this.renderNoResults();
}

// If a allItems template is defined, it takes precedence over our looping
// through hits
if (hasAllItemsTemplate) {
return this.renderAllResults();
return this.renderEmpty();
}

return this.renderWithResults();
return this.renderResults();
}
}

Hits.propTypes = {
cssClasses: PropTypes.shape({
root: PropTypes.string,
emptyRoot: PropTypes.string,
item: PropTypes.string,
allItems: PropTypes.string,
empty: PropTypes.string,
list: PropTypes.string,
}),
hits: PropTypes.array,
results: PropTypes.object,
Expand Down
89 changes: 67 additions & 22 deletions src/components/InfiniteHits.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,81 @@
import PropTypes from 'prop-types';
import React, { Component } from 'preact-compat';
import Hits from './Hits.js';
import map from 'lodash/map';
import cx from 'classnames';
import Template from './Template.js';

class InfiniteHits extends Component {
renderResults() {
const renderedHits = map(this.props.hits, (hit, position) => {
const data = {
...hit,
__hitIndex: position,
};

return (
<Template
rootTagName="li"
data={data}
key={data.objectID}
rootProps={{ className: cx(this.props.cssClasses.item) }}
templateKey="item"
{...this.props.templateProps}
/>
);
});

return <ol className={cx(this.props.cssClasses.list)}>{renderedHits}</ol>;
}

renderEmpty() {
return (
<Template
data={this.props.results}
rootProps={{
className: cx(
this.props.cssClasses.root,
this.props.cssClasses.emptyRoot
),
}}
templateKey="empty"
{...this.props.templateProps}
/>
);
}

render() {
const {
cssClasses,
hits,
results,
showMore,
showMoreLabel,
templateProps,
loadMoreLabel,
isLastPage,
} = this.props;
const btn = this.props.isLastPage ? (
<button disabled className={cssClasses.showmoreButton}>
{showMoreLabel}

if (hits.length === 0) {
return this.renderEmpty();
}

const hitsList = this.renderResults();

const loadMoreButton = isLastPage ? (
<button disabled className={cx(cssClasses.loadMore)}>
{loadMoreLabel}
</button>
) : (
<button onClick={showMore} className={cssClasses.showmoreButton}>
{showMoreLabel}
<button
onClick={showMore}
className={cx(cssClasses.loadMore, cssClasses.disabledLoadMore)}
>
{loadMoreLabel}
</button>
);

return (
<div>
<Hits
cssClasses={cssClasses}
hits={hits}
results={results}
templateProps={templateProps}
/>
<div className={cssClasses.showmore}>{btn}</div>
<div className={cx(cssClasses.root)}>
{hitsList}

{loadMoreButton}
</div>
);
}
Expand All @@ -39,16 +84,16 @@ class InfiniteHits extends Component {
InfiniteHits.propTypes = {
cssClasses: PropTypes.shape({
root: PropTypes.string,
emptyRoot: PropTypes.string,
list: PropTypes.string,
item: PropTypes.string,
allItems: PropTypes.string,
empty: PropTypes.string,
showmore: PropTypes.string,
showmoreButton: PropTypes.string,
loadMore: PropTypes.string,
disabledLoadMore: PropTypes.string,
}),
hits: PropTypes.array,
results: PropTypes.object,
showMore: PropTypes.func,
showMoreLabel: PropTypes.string,
loadMoreLabel: PropTypes.string,
templateProps: PropTypes.object.isRequired,
isLastPage: PropTypes.bool.isRequired,
};
Expand Down
Loading