Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

feat(SearchBox): forward class-names & slots #553

Merged
merged 6 commits into from
Oct 22, 2018
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
38 changes: 38 additions & 0 deletions docs/src/components/RangeInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,44 @@ The range input widget allows a user to select a numeric range using a minimum a
<ais-range-input :attribute="attribute"></ais-range-input>
```

### Range slider

There's no built-in slider in Vue InstantSearch, but you can use third-party sliders that accepts two slider handles. An example is [vue-slider-component](https://github.com/NightCatSama/vue-slider-component). You would use that like this:

```vue
<template>
<ais-range-input attribute="price">
<template slot-scope="{ refine, currentRefinements, range }">
<vue-slider
:min="range.min"
:max="range.max"
:value="toValue(currentRefinements, range)"
@input="refine($event[0], $event[1])"
/>
</template>
</ais-range-input>
</template>

<script>
import VueSlider from 'vue-slider-component';
export default {
components: {
VueSlider,
},
methods: {
toValue([min, max], range) {
return [
min === -Infinity ? range.min : min,
max === Infinity ? range.max : max,
];
},
},
}:
</script>
```

<a class="btn btn-static-theme" href="stories/?selectedKind=RangeInput&selectedStory=with%20vue-slider-component">🕹 try out live</a>

## Props

Name | Type | Default | Description | Required
Expand Down
7 changes: 5 additions & 2 deletions docs/src/components/SearchBox.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ A search input with a clear and submit button.
Name | Type | Default | Description | Required
---|---|---|---|---
placeholder | String | `'Search here…'` | The input placeholder | no
submit-title | String | `'search'` | The submit button text | no
clear-title | String | `'clear'` | The clear button text | no
submit-title | String | `'search'` | The submit button's alternative text | no
reset-title | String | `'clear'` | The clear button's alternative text | no
autofocus | Boolean | `false` | Whether to automatically focus on the input when rendered | no
show-loading-indicator | Boolean | `false` | Show a spinner in the search box if a delay is passed and no results are returned yet | no
class-names | Object | | Override class names | no
Expand All @@ -35,6 +35,9 @@ class-names | Object | | Override class names | no
Name | Scope | Description
---|---|---
default | `{ currentRefinement: String, isSearchStalled: Boolean, refine: String => void }` | Slot to override the DOM output
loading-indicator | | Slot to override the loading indicator
reset-icon | | Slot to override the reset icon
submit-icon | | Slot to override the submit icon

## CSS classes

Expand Down
20 changes: 17 additions & 3 deletions src/components/SearchBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,23 @@
:show-loading-indicator="showLoadingIndicator"
:should-show-loading-indicator="state.isSearchStalled"
:submit-title="submitTitle"
:clear-title="clearTitle"
:reset-title="resetTitle"
:class-names="classNames"
v-model="currentRefinement"
/>
>
<slot
name="loading-indicator"
slot="loading-indicator"
/>
<slot
name="submit-icon"
slot="submit-icon"
/>
<slot
name="reset-icon"
slot="reset-icon"
/>
</search-input>
</slot>
</div>
</template>
Expand Down Expand Up @@ -53,7 +67,7 @@ export default {
type: String,
default: 'Search',
},
clearTitle: {
resetTitle: {
type: String,
default: 'Clear',
},
Expand Down
62 changes: 33 additions & 29 deletions src/components/SearchInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@submit.prevent="onFormSubmit"
@reset.prevent="onFormReset"
>
<!-- :value/@input allows us to pass v-model to the component -->
<input
type="search"
autocorrect="off"
Expand All @@ -23,47 +24,50 @@
@input="$emit('input', $event.target.value)"
ref="input"
>
<!-- value/input allows us to pass v-model to the component -->
<button
type="submit"
:title="submitTitle"
:class="suit('submit')"
:hidden="showLoadingIndicator && shouldShowLoadingIndicator"
>
<svg
role="img"
xmlns="http://www.w3.org/2000/svg"
width="10"
height="10"
viewBox="0 0 40 40"
:class="suit('submitIcon')"
>
<path
d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"
fillRule="evenodd"
/>
</svg>
<slot name="submit-icon">
<svg
role="img"
xmlns="http://www.w3.org/2000/svg"
width="10"
height="10"
viewBox="0 0 40 40"
:class="suit('submitIcon')"
>
<path
d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"
fillRule="evenodd"
/>
</svg>
</slot>
</button>

<button
type="reset"
:title="clearTitle"
:title="resetTitle"
:class="suit('reset')"
:hidden="!value || (showLoadingIndicator && shouldShowLoadingIndicator)"
>
<svg
role="img"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 20 20"
:class="suit('resetIcon')"
>
<path
d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"
fillRule="evenodd"
/>
</svg>
<slot name="reset-icon">
<svg
role="img"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 20 20"
:class="suit('resetIcon')"
>
<path
d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"
fillRule="evenodd"
/>
</svg>
</slot>
</button>

<span
Expand Down Expand Up @@ -141,7 +145,7 @@ export default {
type: String,
default: 'Search',
},
clearTitle: {
resetTitle: {
type: String,
default: 'Clear',
},
Expand Down
64 changes: 62 additions & 2 deletions src/components/__tests__/SearchBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ test('with submit title', () => {
);
});

test('with clear title', () => {
test('with reset title', () => {
__setState(defaultState);
const wrapper = mount(SearchBox, {
propsData: {
clearTitle: 'Clear Title',
resetTitle: 'Clear Title',
},
});

Expand Down Expand Up @@ -166,3 +166,63 @@ test('refine on empty string on form reset', () => {

expect(state.refine).toHaveBeenCalledWith('');
});

test('overriding slots', () => {
__setState({
...defaultState,
isSearchStalled: true,
});
const wrapper = mount(SearchBox, {
propsData: {
showLoadingIndicator: true,
},
slots: {
'submit-icon': '<span>SUBMIT</span>',
'reset-icon': '<span>RESET</span>',
'loading-indicator': '<span>LOADING...</span>',
},
});

expect(wrapper.find('.ais-SearchBox-submit').html()).toMatch(/SUBMIT/);
expect(wrapper.find('.ais-SearchBox-reset').html()).toMatch(/RESET/);
expect(wrapper.find('.ais-SearchBox-loadingIndicator').html()).toMatch(
/LOADING.../
);

expect(wrapper.find('.ais-SearchBox-submit').html()).toMatchInlineSnapshot(`

<button type="submit"
title="Search"
hidden="hidden"
class="ais-SearchBox-submit"
>
<span>
SUBMIT
</span>
</button>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For those snapshots we can use a dedicated file.


`);
expect(wrapper.find('.ais-SearchBox-reset').html()).toMatchInlineSnapshot(`

<button type="reset"
title="Clear"
hidden="hidden"
class="ais-SearchBox-reset"
>
<span>
RESET
</span>
</button>

`);
expect(wrapper.find('.ais-SearchBox-loadingIndicator').html())
.toMatchInlineSnapshot(`

<span class="ais-SearchBox-loadingIndicator">
<span>
LOADING...
</span>
</span>

`);
});
14 changes: 7 additions & 7 deletions stories/MenuSelect.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,37 @@ storiesOf('ais-menu-select', module)
.addDecorator(previewWrapper())
.add('default', () => ({
template: `
<ais-menu-select attribute="brand" />
<ais-menu-select attribute="categories" />
`,
}))
.add('with a limit', () => ({
template: `
<ais-menu-select
attribute="brand"
attribute="categories"
:limit="5"
/>
`,
}))
.add('with a custom sort', () => ({
template: `
<ais-menu-select
attribute="brand"
attribute="categories"
:sort-by="['name:desc']"
/>
`,
}))
.add('with a custom label', () => ({
template: `
<ais-menu-select
attribute="brand"
attribute="categories"
label="None"
/>
`,
}))
.add('with transform items', () => ({
template: `
<ais-menu-select
attribute="brand"
attribute="categories"
label="SEE ALL"
:transformItems="transformItems"
/>
Expand All @@ -52,7 +52,7 @@ storiesOf('ais-menu-select', module)
}))
.add('with a custom rendering', () => ({
template: `
<ais-menu-select attribute="brand">
<ais-menu-select attribute="categories">
<select
slot-scope="{ items, canRefine, refine }"
@change="refine($event.currentTarget.value)"
Expand All @@ -77,7 +77,7 @@ storiesOf('ais-menu-select', module)
template: `
<ais-panel>
<template slot="header">Menu Select</template>
<ais-menu-select attribute="brand" />
<ais-menu-select attribute="categories" />
<template slot="footer">Footer</template>
</ais-panel>
`,
Expand Down
17 changes: 16 additions & 1 deletion stories/SearchBox.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ storiesOf('ais-search-box', module)
template: '<ais-search-box></ais-search-box>',
}))
.add('with loading indicator', () => ({
template: '<ais-search-box showLoadingIndicator></ais-search-box>',
template: '<ais-search-box show-loading-indicator></ais-search-box>',
}))
.add('with autofocus', () => ({
template: '<ais-search-box autofocus></ais-search-box>',
Expand All @@ -24,6 +24,21 @@ storiesOf('ais-search-box', module)
</ais-search-box>
`,
}))
.add('with custom rendering of icons', () => ({
template: `
<ais-search-box show-loading-indicator>
<template slot="reset-icon">
</template>
<template slot="submit-icon">
🔎
</template>
<template slot="loading-indicator">
🔄
</template>
</ais-search-box>
`,
}))
.add('with a Panel', () => ({
template: `
<ais-panel>
Expand Down