vue-instantsearch 4.3.3 → 4.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +5 -5
  3. package/src/__tests__/index.js +133 -26
  4. package/src/components/Autocomplete.vue +8 -1
  5. package/src/components/Breadcrumb.vue +8 -1
  6. package/src/components/ClearRefinements.vue +8 -1
  7. package/src/components/Configure.js +8 -1
  8. package/src/components/ConfigureRelatedItems.js +8 -1
  9. package/src/components/CurrentRefinements.vue +8 -1
  10. package/src/components/DynamicWidgets.js +8 -1
  11. package/src/components/HierarchicalMenu.vue +8 -1
  12. package/src/components/Hits.vue +8 -1
  13. package/src/components/HitsPerPage.vue +8 -1
  14. package/src/components/Index.js +6 -1
  15. package/src/components/InfiniteHits.vue +8 -1
  16. package/src/components/Menu.vue +6 -1
  17. package/src/components/MenuSelect.vue +6 -1
  18. package/src/components/NumericMenu.vue +8 -1
  19. package/src/components/Pagination.vue +9 -1
  20. package/src/components/QueryRuleContext.js +8 -3
  21. package/src/components/QueryRuleCustomData.vue +8 -3
  22. package/src/components/RangeInput.vue +8 -1
  23. package/src/components/RatingMenu.vue +8 -1
  24. package/src/components/RefinementList.vue +8 -1
  25. package/src/components/RelevantSort.vue +8 -1
  26. package/src/components/SearchBox.vue +26 -1
  27. package/src/components/SearchInput.vue +3 -0
  28. package/src/components/SortBy.vue +6 -1
  29. package/src/components/StateResults.vue +8 -1
  30. package/src/components/Stats.vue +6 -1
  31. package/src/components/ToggleRefinement.vue +8 -1
  32. package/src/components/VoiceSearch.vue +18 -1
  33. package/src/components/__tests__/SearchBox.js +15 -0
  34. package/src/components/__tests__/__snapshots__/Pagination.js.snap +21 -21
  35. package/src/mixins/__tests__/widget.test.js +102 -0
  36. package/src/mixins/widget.js +13 -3
  37. package/src/util/__tests__/createServerRootMixin.test.js +3 -2
  38. package/src/util/createServerRootMixin.js +1 -1
  39. package/vue2/cjs/index.js +1 -1
  40. package/vue2/cjs/index.js.map +1 -1
  41. package/vue2/es/package.json.js +1 -1
  42. package/vue2/es/src/components/Autocomplete.vue.js +1 -1
  43. package/vue2/es/src/components/Autocomplete.vue.js.map +1 -1
  44. package/vue2/es/src/components/Breadcrumb.vue.js +1 -1
  45. package/vue2/es/src/components/Breadcrumb.vue.js.map +1 -1
  46. package/vue2/es/src/components/ClearRefinements.vue.js +1 -1
  47. package/vue2/es/src/components/ClearRefinements.vue.js.map +1 -1
  48. package/vue2/es/src/components/Configure.js +1 -1
  49. package/vue2/es/src/components/Configure.js.map +1 -1
  50. package/vue2/es/src/components/ConfigureRelatedItems.js +1 -1
  51. package/vue2/es/src/components/ConfigureRelatedItems.js.map +1 -1
  52. package/vue2/es/src/components/CurrentRefinements.vue.js +1 -1
  53. package/vue2/es/src/components/CurrentRefinements.vue.js.map +1 -1
  54. package/vue2/es/src/components/DynamicWidgets.js +1 -1
  55. package/vue2/es/src/components/DynamicWidgets.js.map +1 -1
  56. package/vue2/es/src/components/HierarchicalMenu.vue.js +1 -1
  57. package/vue2/es/src/components/HierarchicalMenu.vue.js.map +1 -1
  58. package/vue2/es/src/components/Hits.vue.js +1 -1
  59. package/vue2/es/src/components/Hits.vue.js.map +1 -1
  60. package/vue2/es/src/components/HitsPerPage.vue.js +1 -1
  61. package/vue2/es/src/components/HitsPerPage.vue.js.map +1 -1
  62. package/vue2/es/src/components/Index.js +1 -1
  63. package/vue2/es/src/components/Index.js.map +1 -1
  64. package/vue2/es/src/components/InfiniteHits.vue.js +1 -1
  65. package/vue2/es/src/components/InfiniteHits.vue.js.map +1 -1
  66. package/vue2/es/src/components/Menu.vue.js +1 -1
  67. package/vue2/es/src/components/Menu.vue.js.map +1 -1
  68. package/vue2/es/src/components/MenuSelect.vue.js +1 -1
  69. package/vue2/es/src/components/MenuSelect.vue.js.map +1 -1
  70. package/vue2/es/src/components/NumericMenu.vue.js +1 -1
  71. package/vue2/es/src/components/NumericMenu.vue.js.map +1 -1
  72. package/vue2/es/src/components/Pagination.vue.js +1 -1
  73. package/vue2/es/src/components/Pagination.vue.js.map +1 -1
  74. package/vue2/es/src/components/QueryRuleContext.js +1 -1
  75. package/vue2/es/src/components/QueryRuleContext.js.map +1 -1
  76. package/vue2/es/src/components/QueryRuleCustomData.vue.js +1 -1
  77. package/vue2/es/src/components/QueryRuleCustomData.vue.js.map +1 -1
  78. package/vue2/es/src/components/RangeInput.vue.js +1 -1
  79. package/vue2/es/src/components/RangeInput.vue.js.map +1 -1
  80. package/vue2/es/src/components/RatingMenu.vue.js +1 -1
  81. package/vue2/es/src/components/RatingMenu.vue.js.map +1 -1
  82. package/vue2/es/src/components/RefinementList.vue.js +1 -1
  83. package/vue2/es/src/components/RefinementList.vue.js.map +1 -1
  84. package/vue2/es/src/components/RelevantSort.vue.js +1 -1
  85. package/vue2/es/src/components/RelevantSort.vue.js.map +1 -1
  86. package/vue2/es/src/components/SearchBox.vue.js +1 -1
  87. package/vue2/es/src/components/SearchBox.vue.js.map +1 -1
  88. package/vue2/es/src/components/SearchInput.vue.js +1 -1
  89. package/vue2/es/src/components/SearchInput.vue.js.map +1 -1
  90. package/vue2/es/src/components/SortBy.vue.js +1 -1
  91. package/vue2/es/src/components/SortBy.vue.js.map +1 -1
  92. package/vue2/es/src/components/StateResults.vue.js +1 -1
  93. package/vue2/es/src/components/StateResults.vue.js.map +1 -1
  94. package/vue2/es/src/components/Stats.vue.js +1 -1
  95. package/vue2/es/src/components/Stats.vue.js.map +1 -1
  96. package/vue2/es/src/components/ToggleRefinement.vue.js +1 -1
  97. package/vue2/es/src/components/ToggleRefinement.vue.js.map +1 -1
  98. package/vue2/es/src/components/VoiceSearch.vue.js +1 -1
  99. package/vue2/es/src/components/VoiceSearch.vue.js.map +1 -1
  100. package/vue2/es/src/mixins/widget.js +1 -1
  101. package/vue2/es/src/mixins/widget.js.map +1 -1
  102. package/vue2/es/src/util/createInstantSearchComponent.js +1 -1
  103. package/vue2/es/src/util/createServerRootMixin.js.map +1 -1
  104. package/vue2/umd/index.js +1 -1
  105. package/vue2/umd/index.js.map +1 -1
  106. package/vue3/cjs/index.js +1 -1
  107. package/vue3/cjs/index.js.map +1 -1
  108. package/vue3/es/package.json.js +1 -1
  109. package/vue3/es/src/components/Autocomplete.vue_vue&type=script&lang.js +1 -1
  110. package/vue3/es/src/components/Autocomplete.vue_vue&type=script&lang.js.map +1 -1
  111. package/vue3/es/src/components/Autocomplete.vue_vue&type=template&id=e7c95fd0&lang.js.map +1 -1
  112. package/vue3/es/src/components/Breadcrumb.vue_vue&type=script&lang.js +1 -1
  113. package/vue3/es/src/components/Breadcrumb.vue_vue&type=script&lang.js.map +1 -1
  114. package/vue3/es/src/components/Breadcrumb.vue_vue&type=template&id=6f46de9a&lang.js.map +1 -1
  115. package/vue3/es/src/components/ClearRefinements.vue_vue&type=script&lang.js +1 -1
  116. package/vue3/es/src/components/ClearRefinements.vue_vue&type=script&lang.js.map +1 -1
  117. package/vue3/es/src/components/ClearRefinements.vue_vue&type=template&id=410a3aaa&lang.js.map +1 -1
  118. package/vue3/es/src/components/Configure.js +1 -1
  119. package/vue3/es/src/components/Configure.js.map +1 -1
  120. package/vue3/es/src/components/ConfigureRelatedItems.js +1 -1
  121. package/vue3/es/src/components/ConfigureRelatedItems.js.map +1 -1
  122. package/vue3/es/src/components/CurrentRefinements.vue_vue&type=script&lang.js +1 -1
  123. package/vue3/es/src/components/CurrentRefinements.vue_vue&type=script&lang.js.map +1 -1
  124. package/vue3/es/src/components/CurrentRefinements.vue_vue&type=template&id=4f1917ff&lang.js.map +1 -1
  125. package/vue3/es/src/components/DynamicWidgets.js +1 -1
  126. package/vue3/es/src/components/DynamicWidgets.js.map +1 -1
  127. package/vue3/es/src/components/HierarchicalMenu.vue_vue&type=script&lang.js +1 -1
  128. package/vue3/es/src/components/HierarchicalMenu.vue_vue&type=script&lang.js.map +1 -1
  129. package/vue3/es/src/components/HierarchicalMenu.vue_vue&type=template&id=4361a0b8&lang.js.map +1 -1
  130. package/vue3/es/src/components/Hits.vue_vue&type=script&lang.js +1 -1
  131. package/vue3/es/src/components/Hits.vue_vue&type=script&lang.js.map +1 -1
  132. package/vue3/es/src/components/Hits.vue_vue&type=template&id=ef242920&lang.js.map +1 -1
  133. package/vue3/es/src/components/HitsPerPage.vue_vue&type=script&lang.js +1 -1
  134. package/vue3/es/src/components/HitsPerPage.vue_vue&type=script&lang.js.map +1 -1
  135. package/vue3/es/src/components/HitsPerPage.vue_vue&type=template&id=74f3ac28&lang.js.map +1 -1
  136. package/vue3/es/src/components/Index.js +1 -1
  137. package/vue3/es/src/components/Index.js.map +1 -1
  138. package/vue3/es/src/components/InfiniteHits.vue_vue&type=script&lang.js +1 -1
  139. package/vue3/es/src/components/InfiniteHits.vue_vue&type=script&lang.js.map +1 -1
  140. package/vue3/es/src/components/InfiniteHits.vue_vue&type=template&id=dcfb64b8&lang.js.map +1 -1
  141. package/vue3/es/src/components/Menu.vue_vue&type=script&lang.js +1 -1
  142. package/vue3/es/src/components/Menu.vue_vue&type=script&lang.js.map +1 -1
  143. package/vue3/es/src/components/Menu.vue_vue&type=template&id=9bcc0be2&lang.js.map +1 -1
  144. package/vue3/es/src/components/MenuSelect.vue_vue&type=script&lang.js +1 -1
  145. package/vue3/es/src/components/MenuSelect.vue_vue&type=script&lang.js.map +1 -1
  146. package/vue3/es/src/components/MenuSelect.vue_vue&type=template&id=694477eb&lang.js.map +1 -1
  147. package/vue3/es/src/components/NumericMenu.vue_vue&type=script&lang.js +1 -1
  148. package/vue3/es/src/components/NumericMenu.vue_vue&type=script&lang.js.map +1 -1
  149. package/vue3/es/src/components/NumericMenu.vue_vue&type=template&id=160fae0c&lang.js.map +1 -1
  150. package/vue3/es/src/components/Pagination.vue_vue&type=script&lang.js +1 -1
  151. package/vue3/es/src/components/Pagination.vue_vue&type=script&lang.js.map +1 -1
  152. package/vue3/es/src/components/Pagination.vue_vue&type=template&id=849a166c&lang.js +1 -1
  153. package/vue3/es/src/components/Pagination.vue_vue&type=template&id=849a166c&lang.js.map +1 -1
  154. package/vue3/es/src/components/QueryRuleContext.js +1 -1
  155. package/vue3/es/src/components/QueryRuleContext.js.map +1 -1
  156. package/vue3/es/src/components/QueryRuleCustomData.vue_vue&type=script&lang.js +1 -1
  157. package/vue3/es/src/components/QueryRuleCustomData.vue_vue&type=script&lang.js.map +1 -1
  158. package/vue3/es/src/components/QueryRuleCustomData.vue_vue&type=template&id=e4da0782&lang.js.map +1 -1
  159. package/vue3/es/src/components/RangeInput.vue_vue&type=script&lang.js +1 -1
  160. package/vue3/es/src/components/RangeInput.vue_vue&type=script&lang.js.map +1 -1
  161. package/vue3/es/src/components/RangeInput.vue_vue&type=template&id=1e17783d&lang.js.map +1 -1
  162. package/vue3/es/src/components/RatingMenu.vue_vue&type=script&lang.js +1 -1
  163. package/vue3/es/src/components/RatingMenu.vue_vue&type=script&lang.js.map +1 -1
  164. package/vue3/es/src/components/RatingMenu.vue_vue&type=template&id=9254de68&lang.js.map +1 -1
  165. package/vue3/es/src/components/RefinementList.vue_vue&type=script&lang.js +1 -1
  166. package/vue3/es/src/components/RefinementList.vue_vue&type=script&lang.js.map +1 -1
  167. package/vue3/es/src/components/RefinementList.vue_vue&type=template&id=28927239&lang.js.map +1 -1
  168. package/vue3/es/src/components/RelevantSort.vue_vue&type=script&lang.js +1 -1
  169. package/vue3/es/src/components/RelevantSort.vue_vue&type=script&lang.js.map +1 -1
  170. package/vue3/es/src/components/RelevantSort.vue_vue&type=template&id=257b248b&lang.js.map +1 -1
  171. package/vue3/es/src/components/SearchBox.vue_vue&type=script&lang.js +1 -1
  172. package/vue3/es/src/components/SearchBox.vue_vue&type=script&lang.js.map +1 -1
  173. package/vue3/es/src/components/SearchBox.vue_vue&type=template&id=27029d83&lang.js +1 -1
  174. package/vue3/es/src/components/SearchBox.vue_vue&type=template&id=27029d83&lang.js.map +1 -1
  175. package/vue3/es/src/components/SearchInput.vue_vue&type=script&lang.js +1 -1
  176. package/vue3/es/src/components/SearchInput.vue_vue&type=script&lang.js.map +1 -1
  177. package/vue3/es/src/components/SearchInput.vue_vue&type=template&id=2eed8ffc&lang.js.map +1 -1
  178. package/vue3/es/src/components/SortBy.vue_vue&type=script&lang.js +1 -1
  179. package/vue3/es/src/components/SortBy.vue_vue&type=script&lang.js.map +1 -1
  180. package/vue3/es/src/components/SortBy.vue_vue&type=template&id=b69b3b76&lang.js.map +1 -1
  181. package/vue3/es/src/components/StateResults.vue_vue&type=script&lang.js +1 -1
  182. package/vue3/es/src/components/StateResults.vue_vue&type=script&lang.js.map +1 -1
  183. package/vue3/es/src/components/StateResults.vue_vue&type=template&id=5992f3d5&lang.js.map +1 -1
  184. package/vue3/es/src/components/Stats.vue_vue&type=script&lang.js +1 -1
  185. package/vue3/es/src/components/Stats.vue_vue&type=script&lang.js.map +1 -1
  186. package/vue3/es/src/components/Stats.vue_vue&type=template&id=7337491f&lang.js.map +1 -1
  187. package/vue3/es/src/components/ToggleRefinement.vue_vue&type=script&lang.js +1 -1
  188. package/vue3/es/src/components/ToggleRefinement.vue_vue&type=script&lang.js.map +1 -1
  189. package/vue3/es/src/components/ToggleRefinement.vue_vue&type=template&id=14e4586f&lang.js.map +1 -1
  190. package/vue3/es/src/components/VoiceSearch.vue_vue&type=script&lang.js +1 -1
  191. package/vue3/es/src/components/VoiceSearch.vue_vue&type=script&lang.js.map +1 -1
  192. package/vue3/es/src/components/VoiceSearch.vue_vue&type=template&id=24b0f67a&lang.js.map +1 -1
  193. package/vue3/es/src/mixins/widget.js +1 -1
  194. package/vue3/es/src/mixins/widget.js.map +1 -1
  195. package/vue3/es/src/util/createInstantSearchComponent.js +1 -1
  196. package/vue3/es/src/util/createServerRootMixin.js +1 -1
  197. package/vue3/es/src/util/createServerRootMixin.js.map +1 -1
  198. package/vue3/umd/index.js +1 -1
  199. package/vue3/umd/index.js.map +1 -1
@@ -20,6 +20,7 @@
20
20
  :reset-title="resetTitle"
21
21
  :class-names="classNames"
22
22
  v-model="currentRefinement"
23
+ ref="searchInput"
23
24
  >
24
25
  <template
25
26
  v-slot:loading-indicator
@@ -77,7 +78,14 @@ import SearchInput from './SearchInput.vue';
77
78
  export default {
78
79
  name: 'AisSearchBox',
79
80
  mixins: [
80
- createWidgetMixin({ connector: connectSearchBox }),
81
+ createWidgetMixin(
82
+ {
83
+ connector: connectSearchBox,
84
+ },
85
+ {
86
+ $$widgetType: 'ais.searchBox',
87
+ }
88
+ ),
81
89
  createSuitMixin({ name: 'SearchBox' }),
82
90
  ],
83
91
  components: {
@@ -112,6 +120,10 @@ export default {
112
120
  type: String,
113
121
  default: undefined,
114
122
  },
123
+ queryHook: {
124
+ type: Function,
125
+ default: undefined,
126
+ },
115
127
  },
116
128
  data() {
117
129
  return {
@@ -121,6 +133,11 @@ export default {
121
133
  };
122
134
  },
123
135
  computed: {
136
+ widgetParams() {
137
+ return {
138
+ queryHook: this.queryHook,
139
+ };
140
+ },
124
141
  isControlled() {
125
142
  return (
126
143
  typeof this.value !== 'undefined' ||
@@ -141,6 +158,14 @@ export default {
141
158
  this.$emit('update:modelValue', this.model);
142
159
  this.state.refine(this.model);
143
160
  }
161
+
162
+ // we return the local value if the input is focused to avoid
163
+ // concurrent updates when typing
164
+ const { searchInput } = this.$refs;
165
+ if (searchInput && searchInput.isFocused()) {
166
+ return this.localValue;
167
+ }
168
+
144
169
  return this.model || this.state.query || '';
145
170
  },
146
171
  set(val) {
@@ -170,6 +170,9 @@ export default {
170
170
  };
171
171
  },
172
172
  methods: {
173
+ isFocused() {
174
+ return document.activeElement === this.$refs.input;
175
+ },
173
176
  onFormSubmit() {
174
177
  const input = this.$refs.input;
175
178
  input.blur();
@@ -35,7 +35,12 @@ export default {
35
35
  name: 'AisSortBy',
36
36
  mixins: [
37
37
  createSuitMixin({ name: 'SortBy' }),
38
- createWidgetMixin({ connector: connectSortBy }),
38
+ createWidgetMixin(
39
+ { connector: connectSortBy },
40
+ {
41
+ $$widgetType: 'ais.sortBy',
42
+ }
43
+ ),
39
44
 
40
45
  createPanelConsumerMixin({
41
46
  mapStateToCanRefine: state => state.hasNoResults === false,
@@ -25,7 +25,14 @@ import connectStateResults from '../connectors/connectStateResults';
25
25
  export default {
26
26
  name: 'AisStateResults',
27
27
  mixins: [
28
- createWidgetMixin({ connector: connectStateResults }),
28
+ createWidgetMixin(
29
+ {
30
+ connector: connectStateResults,
31
+ },
32
+ {
33
+ $$widgetType: 'ais.stateResults',
34
+ }
35
+ ),
29
36
  createSuitMixin({ name: 'StateResults' }),
30
37
  ],
31
38
  computed: {
@@ -20,7 +20,12 @@ import { createSuitMixin } from '../mixins/suit';
20
20
  export default {
21
21
  name: 'AisStats',
22
22
  mixins: [
23
- createWidgetMixin({ connector: connectStats }),
23
+ createWidgetMixin(
24
+ { connector: connectStats },
25
+ {
26
+ $$widgetType: 'ais.stats',
27
+ }
28
+ ),
24
29
  createSuitMixin({ name: 'Stats' }),
25
30
  ],
26
31
  computed: {
@@ -41,7 +41,14 @@ export default {
41
41
  name: 'AisToggleRefinement',
42
42
  mixins: [
43
43
  createSuitMixin({ name: 'ToggleRefinement' }),
44
- createWidgetMixin({ connector: connectToggleRefinement }),
44
+ createWidgetMixin(
45
+ {
46
+ connector: connectToggleRefinement,
47
+ },
48
+ {
49
+ $$widgetType: 'ais.toggleRefinement',
50
+ }
51
+ ),
45
52
  createPanelConsumerMixin({
46
53
  mapStateToCanRefine,
47
54
  }),
@@ -84,7 +84,14 @@ import { createWidgetMixin } from '../mixins/widget';
84
84
  export default {
85
85
  name: 'AisVoiceSearch',
86
86
  mixins: [
87
- createWidgetMixin({ connector: connectVoiceSearch }),
87
+ createWidgetMixin(
88
+ {
89
+ connector: connectVoiceSearch,
90
+ },
91
+ {
92
+ $$widgetType: 'ais.voiceSearch',
93
+ }
94
+ ),
88
95
  createSuitMixin({ name: 'VoiceSearch' }),
89
96
  ],
90
97
  props: {
@@ -93,6 +100,14 @@ export default {
93
100
  required: false,
94
101
  default: undefined,
95
102
  },
103
+ language: {
104
+ type: String,
105
+ default: undefined,
106
+ },
107
+ additionalQueryParameters: {
108
+ type: Object,
109
+ default: undefined,
110
+ },
96
111
  buttonTitle: {
97
112
  type: String,
98
113
  required: false,
@@ -123,6 +138,8 @@ export default {
123
138
  widgetParams() {
124
139
  return {
125
140
  searchAsYouSpeak: this.searchAsYouSpeak,
141
+ language: this.language,
142
+ additionalQueryParameters: this.additionalQueryParameters,
126
143
  };
127
144
  },
128
145
  errorNotAllowed() {
@@ -147,6 +147,21 @@ test('refine on empty string on form reset', async () => {
147
147
  expect(state.refine).toHaveBeenCalledWith('');
148
148
  });
149
149
 
150
+ test('keep local query when out of sync and input is focused', async () => {
151
+ const state = { ...defaultState, refine: jest.fn() };
152
+ __setState(state);
153
+
154
+ const wrapper = mount(SearchBox, { attachTo: document.body });
155
+ const input = wrapper.find('.ais-SearchBox-input');
156
+ input.element.focus();
157
+ await input.setValue('hello');
158
+
159
+ await wrapper.setData({ state: { query: 'hel' } });
160
+
161
+ expect(input.element.value).toBe('hello');
162
+ expect(state.refine).toHaveBeenLastCalledWith('hello');
163
+ });
164
+
150
165
  test('overriding slots', () => {
151
166
  __setState({
152
167
  ...defaultState,
@@ -19,49 +19,49 @@ exports[`renders correctly another page 1`] = `
19
19
 
20
20
  </a>
21
21
  </li>
22
- <li class="ais-Pagination-item">
22
+ <li class="ais-Pagination-item ais-Pagination-item--page">
23
23
  <a class="ais-Pagination-link"
24
24
  href="#"
25
25
  >
26
26
  4
27
27
  </a>
28
28
  </li>
29
- <li class="ais-Pagination-item">
29
+ <li class="ais-Pagination-item ais-Pagination-item--page">
30
30
  <a class="ais-Pagination-link"
31
31
  href="#"
32
32
  >
33
33
  5
34
34
  </a>
35
35
  </li>
36
- <li class="ais-Pagination-item">
36
+ <li class="ais-Pagination-item ais-Pagination-item--page">
37
37
  <a class="ais-Pagination-link"
38
38
  href="#"
39
39
  >
40
40
  6
41
41
  </a>
42
42
  </li>
43
- <li class="ais-Pagination-item ais-Pagination-item--selected">
43
+ <li class="ais-Pagination-item ais-Pagination-item--page ais-Pagination-item--selected">
44
44
  <a class="ais-Pagination-link"
45
45
  href="#"
46
46
  >
47
47
  7
48
48
  </a>
49
49
  </li>
50
- <li class="ais-Pagination-item">
50
+ <li class="ais-Pagination-item ais-Pagination-item--page">
51
51
  <a class="ais-Pagination-link"
52
52
  href="#"
53
53
  >
54
54
  8
55
55
  </a>
56
56
  </li>
57
- <li class="ais-Pagination-item">
57
+ <li class="ais-Pagination-item ais-Pagination-item--page">
58
58
  <a class="ais-Pagination-link"
59
59
  href="#"
60
60
  >
61
61
  9
62
62
  </a>
63
63
  </li>
64
- <li class="ais-Pagination-item">
64
+ <li class="ais-Pagination-item ais-Pagination-item--page">
65
65
  <a class="ais-Pagination-link"
66
66
  href="#"
67
67
  >
@@ -105,49 +105,49 @@ exports[`renders correctly first page 1`] = `
105
105
 
106
106
  </span>
107
107
  </li>
108
- <li class="ais-Pagination-item ais-Pagination-item--selected">
108
+ <li class="ais-Pagination-item ais-Pagination-item--page ais-Pagination-item--selected">
109
109
  <a class="ais-Pagination-link"
110
110
  href="#"
111
111
  >
112
112
  1
113
113
  </a>
114
114
  </li>
115
- <li class="ais-Pagination-item">
115
+ <li class="ais-Pagination-item ais-Pagination-item--page">
116
116
  <a class="ais-Pagination-link"
117
117
  href="#"
118
118
  >
119
119
  2
120
120
  </a>
121
121
  </li>
122
- <li class="ais-Pagination-item">
122
+ <li class="ais-Pagination-item ais-Pagination-item--page">
123
123
  <a class="ais-Pagination-link"
124
124
  href="#"
125
125
  >
126
126
  3
127
127
  </a>
128
128
  </li>
129
- <li class="ais-Pagination-item">
129
+ <li class="ais-Pagination-item ais-Pagination-item--page">
130
130
  <a class="ais-Pagination-link"
131
131
  href="#"
132
132
  >
133
133
  4
134
134
  </a>
135
135
  </li>
136
- <li class="ais-Pagination-item">
136
+ <li class="ais-Pagination-item ais-Pagination-item--page">
137
137
  <a class="ais-Pagination-link"
138
138
  href="#"
139
139
  >
140
140
  5
141
141
  </a>
142
142
  </li>
143
- <li class="ais-Pagination-item">
143
+ <li class="ais-Pagination-item ais-Pagination-item--page">
144
144
  <a class="ais-Pagination-link"
145
145
  href="#"
146
146
  >
147
147
  6
148
148
  </a>
149
149
  </li>
150
- <li class="ais-Pagination-item">
150
+ <li class="ais-Pagination-item ais-Pagination-item--page">
151
151
  <a class="ais-Pagination-link"
152
152
  href="#"
153
153
  >
@@ -193,49 +193,49 @@ exports[`renders correctly last page 1`] = `
193
193
 
194
194
  </a>
195
195
  </li>
196
- <li class="ais-Pagination-item">
196
+ <li class="ais-Pagination-item ais-Pagination-item--page">
197
197
  <a class="ais-Pagination-link"
198
198
  href="#"
199
199
  >
200
200
  4
201
201
  </a>
202
202
  </li>
203
- <li class="ais-Pagination-item">
203
+ <li class="ais-Pagination-item ais-Pagination-item--page">
204
204
  <a class="ais-Pagination-link"
205
205
  href="#"
206
206
  >
207
207
  5
208
208
  </a>
209
209
  </li>
210
- <li class="ais-Pagination-item">
210
+ <li class="ais-Pagination-item ais-Pagination-item--page">
211
211
  <a class="ais-Pagination-link"
212
212
  href="#"
213
213
  >
214
214
  6
215
215
  </a>
216
216
  </li>
217
- <li class="ais-Pagination-item">
217
+ <li class="ais-Pagination-item ais-Pagination-item--page">
218
218
  <a class="ais-Pagination-link"
219
219
  href="#"
220
220
  >
221
221
  7
222
222
  </a>
223
223
  </li>
224
- <li class="ais-Pagination-item">
224
+ <li class="ais-Pagination-item ais-Pagination-item--page">
225
225
  <a class="ais-Pagination-link"
226
226
  href="#"
227
227
  >
228
228
  8
229
229
  </a>
230
230
  </li>
231
- <li class="ais-Pagination-item">
231
+ <li class="ais-Pagination-item ais-Pagination-item--page">
232
232
  <a class="ais-Pagination-link"
233
233
  href="#"
234
234
  >
235
235
  9
236
236
  </a>
237
237
  </li>
238
- <li class="ais-Pagination-item ais-Pagination-item--selected">
238
+ <li class="ais-Pagination-item ais-Pagination-item--page ais-Pagination-item--selected">
239
239
  <a class="ais-Pagination-link"
240
240
  href="#"
241
241
  >
@@ -333,3 +333,105 @@ describe('on child index', () => {
333
333
  expect(wrapper.vm.state).toEqual(state);
334
334
  });
335
335
  });
336
+
337
+ describe('general', () => {
338
+ it('sets additional properties to widget', () => {
339
+ const instance = createFakeInstance();
340
+ const widget = { render: () => {} };
341
+ const factory = jest.fn(() => widget);
342
+ const connector = jest.fn(() => factory);
343
+ const widgetParams = {
344
+ attribute: 'brand',
345
+ };
346
+ const additionalProperties = { $$widgetType: 'ais.fakeWidget' };
347
+ const Test = createFakeComponent({
348
+ mixins: [createWidgetMixin({ connector }, additionalProperties)],
349
+ computed: {
350
+ widgetParams() {
351
+ return widgetParams;
352
+ },
353
+ },
354
+ });
355
+
356
+ mount(Test, {
357
+ provide: {
358
+ $_ais_instantSearchInstance: instance,
359
+ },
360
+ });
361
+
362
+ expect(connector).toHaveBeenCalled();
363
+ expect(factory).toHaveBeenCalledWith(widgetParams);
364
+ expect(instance.mainIndex.addWidgets).toHaveBeenCalledTimes(1);
365
+ expect(instance.mainIndex.addWidgets.mock.calls[0][0]).toEqual([
366
+ {
367
+ ...widget,
368
+ ...additionalProperties,
369
+ },
370
+ ]);
371
+ });
372
+
373
+ it('sets additional properties to widget when it recreates', async () => {
374
+ const instance = createFakeInstance();
375
+ const widget = {
376
+ render: () => {},
377
+ dispose: () => {},
378
+ };
379
+ const factory = jest.fn(() => widget);
380
+ const connector = jest.fn(() => factory);
381
+ const widgetParams = {
382
+ attribute: 'brand',
383
+ };
384
+ const additionalProperties = { $$widgetType: 'ais.fakeWidget' };
385
+
386
+ const Test = createFakeComponent({
387
+ mixins: [createWidgetMixin({ connector }, additionalProperties)],
388
+ data: () => ({
389
+ widgetParams,
390
+ }),
391
+ });
392
+
393
+ const nextWidgetParams = {
394
+ attribute: 'price',
395
+ };
396
+
397
+ const wrapper = mount(Test, {
398
+ provide: {
399
+ $_ais_instantSearchInstance: instance,
400
+ },
401
+ });
402
+
403
+ // Simulate render
404
+ await wrapper.setData({
405
+ state: { items: [] },
406
+ });
407
+
408
+ expect(instance.mainIndex.addWidgets).toHaveBeenCalledTimes(1);
409
+ expect(instance.mainIndex.addWidgets.mock.calls[0][0]).toEqual([
410
+ {
411
+ ...widget,
412
+ ...additionalProperties,
413
+ },
414
+ ]);
415
+
416
+ // Simulate widget params update
417
+ await wrapper.setData({
418
+ widgetParams: nextWidgetParams,
419
+ });
420
+
421
+ expect(wrapper.vm.state).toBe(null);
422
+
423
+ expect(instance.mainIndex.removeWidgets).toHaveBeenCalledTimes(1);
424
+ expect(instance.mainIndex.removeWidgets).toHaveBeenCalledWith([widget]);
425
+
426
+ expect(factory).toHaveBeenCalledTimes(2);
427
+ expect(factory).toHaveBeenCalledWith(nextWidgetParams);
428
+
429
+ expect(instance.mainIndex.addWidgets).toHaveBeenCalledTimes(2);
430
+ expect(instance.mainIndex.addWidgets.mock.calls[1][0]).toEqual([
431
+ {
432
+ ...widget,
433
+ ...additionalProperties,
434
+ },
435
+ ]);
436
+ });
437
+ });
@@ -1,7 +1,11 @@
1
+ import { _objectSpread } from '../util/polyfills';
1
2
  import { isVue3 } from '../util/vue-compat';
2
3
  import { warn } from '../util/warn';
3
4
 
4
- export const createWidgetMixin = ({ connector } = {}) => ({
5
+ export const createWidgetMixin = (
6
+ { connector } = {},
7
+ additionalProperties = {}
8
+ ) => ({
5
9
  inject: {
6
10
  instantSearchInstance: {
7
11
  from: '$_ais_instantSearchInstance',
@@ -27,7 +31,10 @@ export const createWidgetMixin = ({ connector } = {}) => ({
27
31
  created() {
28
32
  if (typeof connector === 'function') {
29
33
  this.factory = connector(this.updateState, () => {});
30
- this.widget = this.factory(this.widgetParams);
34
+ this.widget = _objectSpread(
35
+ this.factory(this.widgetParams),
36
+ additionalProperties
37
+ );
31
38
  this.getParentIndex().addWidgets([this.widget]);
32
39
 
33
40
  if (
@@ -66,7 +73,10 @@ Read more on using connectors: https://alg.li/vue-custom`
66
73
  handler(nextWidgetParams) {
67
74
  this.state = null;
68
75
  this.getParentIndex().removeWidgets([this.widget]);
69
- this.widget = this.factory(nextWidgetParams);
76
+ this.widget = _objectSpread(
77
+ this.factory(nextWidgetParams),
78
+ additionalProperties
79
+ );
70
80
  this.getParentIndex().addWidgets([this.widget]);
71
81
  },
72
82
  deep: true,
@@ -933,8 +933,9 @@ Array [
933
933
  hello: serialized,
934
934
  });
935
935
 
936
- // TODO: assert that this is expect.any(AlgoliaSearchHelper), but test fails
937
- // even though it's an object with all the right properties (including constructor)
936
+ expect(instantsearch.mainIndex.getHelper()).toEqual(
937
+ expect.any(AlgoliaSearchHelper)
938
+ );
938
939
  expect(instantsearch.mainIndex.getHelper()).not.toBeNull();
939
940
  });
940
941
 
@@ -41,7 +41,7 @@ function defaultCloneComponent(componentInstance, { mixins = [] } = {}) {
41
41
 
42
42
  if (isVue3) {
43
43
  const appOptions = Object.assign({}, componentInstance.$options, options);
44
- appOptions.mixins = [...mixins, ...appOptions.mixins];
44
+ appOptions.mixins = [...mixins, ...(appOptions.mixins || [])];
45
45
  app = createSSRApp(appOptions);
46
46
  if (componentInstance.$router) {
47
47
  app.use(componentInstance.$router);