vue-instantsearch 4.3.2 → 4.4.1

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 (260) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +9 -9
  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 +17 -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 +8 -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 +57 -2
  38. package/src/util/createInstantSearchComponent.js +1 -1
  39. package/src/util/createServerRootMixin.js +9 -2
  40. package/src/util/vue-compat/{index-2.js → index-vue2.js} +0 -0
  41. package/src/util/vue-compat/{index-3.js → index-vue3.js} +0 -0
  42. package/src/util/vue-compat/index.js +3 -3
  43. package/vue2/cjs/index.js +1 -1
  44. package/vue2/cjs/index.js.map +1 -1
  45. package/vue2/cjs/package.json +1 -0
  46. package/vue2/es/index.js +1 -1
  47. package/vue2/es/package.json +1 -0
  48. package/vue2/es/package.json.js +1 -1
  49. package/vue2/es/src/components/Autocomplete.vue.js +1 -1
  50. package/vue2/es/src/components/Autocomplete.vue.js.map +1 -1
  51. package/vue2/es/src/components/Breadcrumb.vue.js +1 -1
  52. package/vue2/es/src/components/Breadcrumb.vue.js.map +1 -1
  53. package/vue2/es/src/components/ClearRefinements.vue.js +1 -1
  54. package/vue2/es/src/components/ClearRefinements.vue.js.map +1 -1
  55. package/vue2/es/src/components/Configure.js +1 -1
  56. package/vue2/es/src/components/Configure.js.map +1 -1
  57. package/vue2/es/src/components/ConfigureRelatedItems.js +1 -1
  58. package/vue2/es/src/components/ConfigureRelatedItems.js.map +1 -1
  59. package/vue2/es/src/components/CurrentRefinements.vue.js +1 -1
  60. package/vue2/es/src/components/CurrentRefinements.vue.js.map +1 -1
  61. package/vue2/es/src/components/DynamicWidgets.js +1 -1
  62. package/vue2/es/src/components/DynamicWidgets.js.map +1 -1
  63. package/vue2/es/src/components/HierarchicalMenu.vue.js +1 -1
  64. package/vue2/es/src/components/HierarchicalMenu.vue.js.map +1 -1
  65. package/vue2/es/src/components/Highlighter.vue.js +1 -1
  66. package/vue2/es/src/components/Highlighter.vue.js.map +1 -1
  67. package/vue2/es/src/components/Hits.vue.js +1 -1
  68. package/vue2/es/src/components/Hits.vue.js.map +1 -1
  69. package/vue2/es/src/components/HitsPerPage.vue.js +1 -1
  70. package/vue2/es/src/components/HitsPerPage.vue.js.map +1 -1
  71. package/vue2/es/src/components/Index.js +1 -1
  72. package/vue2/es/src/components/Index.js.map +1 -1
  73. package/vue2/es/src/components/InfiniteHits.vue.js +1 -1
  74. package/vue2/es/src/components/InfiniteHits.vue.js.map +1 -1
  75. package/vue2/es/src/components/InstantSearch.js +1 -1
  76. package/vue2/es/src/components/InstantSearch.js.map +1 -1
  77. package/vue2/es/src/components/InstantSearchSsr.js +1 -1
  78. package/vue2/es/src/components/InstantSearchSsr.js.map +1 -1
  79. package/vue2/es/src/components/Menu.vue.js +1 -1
  80. package/vue2/es/src/components/Menu.vue.js.map +1 -1
  81. package/vue2/es/src/components/MenuSelect.vue.js +1 -1
  82. package/vue2/es/src/components/MenuSelect.vue.js.map +1 -1
  83. package/vue2/es/src/components/NumericMenu.vue.js +1 -1
  84. package/vue2/es/src/components/NumericMenu.vue.js.map +1 -1
  85. package/vue2/es/src/components/Pagination.vue.js +1 -1
  86. package/vue2/es/src/components/Pagination.vue.js.map +1 -1
  87. package/vue2/es/src/components/Panel.vue.js +1 -1
  88. package/vue2/es/src/components/Panel.vue.js.map +1 -1
  89. package/vue2/es/src/components/PoweredBy.vue.js.map +1 -1
  90. package/vue2/es/src/components/QueryRuleContext.js +1 -1
  91. package/vue2/es/src/components/QueryRuleContext.js.map +1 -1
  92. package/vue2/es/src/components/QueryRuleCustomData.vue.js +1 -1
  93. package/vue2/es/src/components/QueryRuleCustomData.vue.js.map +1 -1
  94. package/vue2/es/src/components/RangeInput.vue.js +1 -1
  95. package/vue2/es/src/components/RangeInput.vue.js.map +1 -1
  96. package/vue2/es/src/components/RatingMenu.vue.js +1 -1
  97. package/vue2/es/src/components/RatingMenu.vue.js.map +1 -1
  98. package/vue2/es/src/components/RefinementList.vue.js +1 -1
  99. package/vue2/es/src/components/RefinementList.vue.js.map +1 -1
  100. package/vue2/es/src/components/RelevantSort.vue.js +1 -1
  101. package/vue2/es/src/components/RelevantSort.vue.js.map +1 -1
  102. package/vue2/es/src/components/SearchBox.vue.js +1 -1
  103. package/vue2/es/src/components/SearchBox.vue.js.map +1 -1
  104. package/vue2/es/src/components/SearchInput.vue.js +1 -1
  105. package/vue2/es/src/components/SearchInput.vue.js.map +1 -1
  106. package/vue2/es/src/components/SortBy.vue.js +1 -1
  107. package/vue2/es/src/components/SortBy.vue.js.map +1 -1
  108. package/vue2/es/src/components/StateResults.vue.js +1 -1
  109. package/vue2/es/src/components/StateResults.vue.js.map +1 -1
  110. package/vue2/es/src/components/Stats.vue.js +1 -1
  111. package/vue2/es/src/components/Stats.vue.js.map +1 -1
  112. package/vue2/es/src/components/ToggleRefinement.vue.js +1 -1
  113. package/vue2/es/src/components/ToggleRefinement.vue.js.map +1 -1
  114. package/vue2/es/src/components/VoiceSearch.vue.js +1 -1
  115. package/vue2/es/src/components/VoiceSearch.vue.js.map +1 -1
  116. package/vue2/es/src/connectors/connectStateResults.js.map +1 -1
  117. package/vue2/es/src/mixins/panel.js +1 -1
  118. package/vue2/es/src/mixins/panel.js.map +1 -1
  119. package/vue2/es/src/mixins/suit.js.map +1 -1
  120. package/vue2/es/src/mixins/widget.js +1 -1
  121. package/vue2/es/src/mixins/widget.js.map +1 -1
  122. package/vue2/es/src/plugin.js.map +1 -1
  123. package/vue2/es/src/util/createInstantSearchComponent.js +1 -1
  124. package/vue2/es/src/util/createInstantSearchComponent.js.map +1 -1
  125. package/vue2/es/src/util/createServerRootMixin.js +1 -1
  126. package/vue2/es/src/util/createServerRootMixin.js.map +1 -1
  127. package/vue2/es/src/util/parseAlgoliaHit.js +1 -1
  128. package/vue2/es/src/util/parseAlgoliaHit.js.map +1 -1
  129. package/vue2/es/src/util/polyfills.js.map +1 -1
  130. package/vue2/es/src/util/suit.js.map +1 -1
  131. package/vue2/es/src/util/unescape.js.map +1 -1
  132. package/vue2/es/src/util/vue-compat/{index-2.js → index-vue2.js} +1 -1
  133. package/vue2/es/src/util/vue-compat/index-vue2.js.map +1 -0
  134. package/vue2/umd/index.js +1 -1
  135. package/vue2/umd/index.js.map +1 -1
  136. package/vue3/cjs/index.js +1 -1
  137. package/vue3/cjs/index.js.map +1 -1
  138. package/vue3/cjs/package.json +1 -0
  139. package/vue3/es/index.js +1 -1
  140. package/vue3/es/package.json +1 -0
  141. package/vue3/es/package.json.js +1 -1
  142. package/vue3/es/src/components/Autocomplete.vue_vue&type=script&lang.js +1 -1
  143. package/vue3/es/src/components/Autocomplete.vue_vue&type=script&lang.js.map +1 -1
  144. package/vue3/es/src/components/Autocomplete.vue_vue&type=template&id=e7c95fd0&lang.js.map +1 -1
  145. package/vue3/es/src/components/Breadcrumb.vue_vue&type=script&lang.js +1 -1
  146. package/vue3/es/src/components/Breadcrumb.vue_vue&type=script&lang.js.map +1 -1
  147. package/vue3/es/src/components/Breadcrumb.vue_vue&type=template&id=6f46de9a&lang.js.map +1 -1
  148. package/vue3/es/src/components/ClearRefinements.vue_vue&type=script&lang.js +1 -1
  149. package/vue3/es/src/components/ClearRefinements.vue_vue&type=script&lang.js.map +1 -1
  150. package/vue3/es/src/components/ClearRefinements.vue_vue&type=template&id=410a3aaa&lang.js.map +1 -1
  151. package/vue3/es/src/components/Configure.js +1 -1
  152. package/vue3/es/src/components/Configure.js.map +1 -1
  153. package/vue3/es/src/components/ConfigureRelatedItems.js +1 -1
  154. package/vue3/es/src/components/ConfigureRelatedItems.js.map +1 -1
  155. package/vue3/es/src/components/CurrentRefinements.vue_vue&type=script&lang.js +1 -1
  156. package/vue3/es/src/components/CurrentRefinements.vue_vue&type=script&lang.js.map +1 -1
  157. package/vue3/es/src/components/CurrentRefinements.vue_vue&type=template&id=4f1917ff&lang.js.map +1 -1
  158. package/vue3/es/src/components/DynamicWidgets.js +1 -1
  159. package/vue3/es/src/components/DynamicWidgets.js.map +1 -1
  160. package/vue3/es/src/components/HierarchicalMenu.vue_vue&type=script&lang.js +1 -1
  161. package/vue3/es/src/components/HierarchicalMenu.vue_vue&type=script&lang.js.map +1 -1
  162. package/vue3/es/src/components/HierarchicalMenu.vue_vue&type=template&id=4361a0b8&lang.js.map +1 -1
  163. package/vue3/es/src/components/HierarchicalMenuList.vue_vue&type=template&id=0435b314&lang.js.map +1 -1
  164. package/vue3/es/src/components/Highlight.vue_vue&type=template&id=300b0ab4&lang.js.map +1 -1
  165. package/vue3/es/src/components/Highlighter.vue_vue&type=script&lang.js +1 -1
  166. package/vue3/es/src/components/Highlighter.vue_vue&type=script&lang.js.map +1 -1
  167. package/vue3/es/src/components/Hits.vue_vue&type=script&lang.js +1 -1
  168. package/vue3/es/src/components/Hits.vue_vue&type=script&lang.js.map +1 -1
  169. package/vue3/es/src/components/Hits.vue_vue&type=template&id=ef242920&lang.js.map +1 -1
  170. package/vue3/es/src/components/HitsPerPage.vue_vue&type=script&lang.js +1 -1
  171. package/vue3/es/src/components/HitsPerPage.vue_vue&type=script&lang.js.map +1 -1
  172. package/vue3/es/src/components/HitsPerPage.vue_vue&type=template&id=74f3ac28&lang.js.map +1 -1
  173. package/vue3/es/src/components/Index.js +1 -1
  174. package/vue3/es/src/components/Index.js.map +1 -1
  175. package/vue3/es/src/components/InfiniteHits.vue_vue&type=script&lang.js +1 -1
  176. package/vue3/es/src/components/InfiniteHits.vue_vue&type=script&lang.js.map +1 -1
  177. package/vue3/es/src/components/InfiniteHits.vue_vue&type=template&id=dcfb64b8&lang.js.map +1 -1
  178. package/vue3/es/src/components/InstantSearch.js +1 -1
  179. package/vue3/es/src/components/InstantSearch.js.map +1 -1
  180. package/vue3/es/src/components/InstantSearchSsr.js +1 -1
  181. package/vue3/es/src/components/InstantSearchSsr.js.map +1 -1
  182. package/vue3/es/src/components/Menu.vue_vue&type=script&lang.js +1 -1
  183. package/vue3/es/src/components/Menu.vue_vue&type=script&lang.js.map +1 -1
  184. package/vue3/es/src/components/Menu.vue_vue&type=template&id=9bcc0be2&lang.js.map +1 -1
  185. package/vue3/es/src/components/MenuSelect.vue_vue&type=script&lang.js +1 -1
  186. package/vue3/es/src/components/MenuSelect.vue_vue&type=script&lang.js.map +1 -1
  187. package/vue3/es/src/components/MenuSelect.vue_vue&type=template&id=694477eb&lang.js.map +1 -1
  188. package/vue3/es/src/components/NumericMenu.vue_vue&type=script&lang.js +1 -1
  189. package/vue3/es/src/components/NumericMenu.vue_vue&type=script&lang.js.map +1 -1
  190. package/vue3/es/src/components/NumericMenu.vue_vue&type=template&id=160fae0c&lang.js.map +1 -1
  191. package/vue3/es/src/components/Pagination.vue_vue&type=script&lang.js +1 -1
  192. package/vue3/es/src/components/Pagination.vue_vue&type=script&lang.js.map +1 -1
  193. package/vue3/es/src/components/Pagination.vue_vue&type=template&id=849a166c&lang.js +1 -1
  194. package/vue3/es/src/components/Pagination.vue_vue&type=template&id=849a166c&lang.js.map +1 -1
  195. package/vue3/es/src/components/Panel.vue_vue&type=script&lang.js +1 -1
  196. package/vue3/es/src/components/Panel.vue_vue&type=script&lang.js.map +1 -1
  197. package/vue3/es/src/components/PoweredBy.vue_vue&type=script&lang.js.map +1 -1
  198. package/vue3/es/src/components/PoweredBy.vue_vue&type=template&id=3e8d7a5b&lang.js.map +1 -1
  199. package/vue3/es/src/components/QueryRuleContext.js +1 -1
  200. package/vue3/es/src/components/QueryRuleContext.js.map +1 -1
  201. package/vue3/es/src/components/QueryRuleCustomData.vue_vue&type=script&lang.js +1 -1
  202. package/vue3/es/src/components/QueryRuleCustomData.vue_vue&type=script&lang.js.map +1 -1
  203. package/vue3/es/src/components/QueryRuleCustomData.vue_vue&type=template&id=e4da0782&lang.js.map +1 -1
  204. package/vue3/es/src/components/RangeInput.vue_vue&type=script&lang.js +1 -1
  205. package/vue3/es/src/components/RangeInput.vue_vue&type=script&lang.js.map +1 -1
  206. package/vue3/es/src/components/RangeInput.vue_vue&type=template&id=1e17783d&lang.js.map +1 -1
  207. package/vue3/es/src/components/RatingMenu.vue_vue&type=script&lang.js +1 -1
  208. package/vue3/es/src/components/RatingMenu.vue_vue&type=script&lang.js.map +1 -1
  209. package/vue3/es/src/components/RatingMenu.vue_vue&type=template&id=9254de68&lang.js.map +1 -1
  210. package/vue3/es/src/components/RefinementList.vue_vue&type=script&lang.js +1 -1
  211. package/vue3/es/src/components/RefinementList.vue_vue&type=script&lang.js.map +1 -1
  212. package/vue3/es/src/components/RefinementList.vue_vue&type=template&id=28927239&lang.js.map +1 -1
  213. package/vue3/es/src/components/RelevantSort.vue_vue&type=script&lang.js +1 -1
  214. package/vue3/es/src/components/RelevantSort.vue_vue&type=script&lang.js.map +1 -1
  215. package/vue3/es/src/components/RelevantSort.vue_vue&type=template&id=257b248b&lang.js.map +1 -1
  216. package/vue3/es/src/components/SearchBox.vue_vue&type=script&lang.js +1 -1
  217. package/vue3/es/src/components/SearchBox.vue_vue&type=script&lang.js.map +1 -1
  218. package/vue3/es/src/components/SearchBox.vue_vue&type=template&id=27029d83&lang.js +1 -1
  219. package/vue3/es/src/components/SearchBox.vue_vue&type=template&id=27029d83&lang.js.map +1 -1
  220. package/vue3/es/src/components/SearchInput.vue_vue&type=script&lang.js +1 -1
  221. package/vue3/es/src/components/SearchInput.vue_vue&type=script&lang.js.map +1 -1
  222. package/vue3/es/src/components/SearchInput.vue_vue&type=template&id=2eed8ffc&lang.js.map +1 -1
  223. package/vue3/es/src/components/Snippet.vue_vue&type=template&id=eb4966c6&lang.js.map +1 -1
  224. package/vue3/es/src/components/SortBy.vue_vue&type=script&lang.js +1 -1
  225. package/vue3/es/src/components/SortBy.vue_vue&type=script&lang.js.map +1 -1
  226. package/vue3/es/src/components/SortBy.vue_vue&type=template&id=b69b3b76&lang.js.map +1 -1
  227. package/vue3/es/src/components/StateResults.vue_vue&type=script&lang.js +1 -1
  228. package/vue3/es/src/components/StateResults.vue_vue&type=script&lang.js.map +1 -1
  229. package/vue3/es/src/components/StateResults.vue_vue&type=template&id=5992f3d5&lang.js.map +1 -1
  230. package/vue3/es/src/components/Stats.vue_vue&type=script&lang.js +1 -1
  231. package/vue3/es/src/components/Stats.vue_vue&type=script&lang.js.map +1 -1
  232. package/vue3/es/src/components/Stats.vue_vue&type=template&id=7337491f&lang.js.map +1 -1
  233. package/vue3/es/src/components/ToggleRefinement.vue_vue&type=script&lang.js +1 -1
  234. package/vue3/es/src/components/ToggleRefinement.vue_vue&type=script&lang.js.map +1 -1
  235. package/vue3/es/src/components/ToggleRefinement.vue_vue&type=template&id=14e4586f&lang.js.map +1 -1
  236. package/vue3/es/src/components/VoiceSearch.vue_vue&type=script&lang.js +1 -1
  237. package/vue3/es/src/components/VoiceSearch.vue_vue&type=script&lang.js.map +1 -1
  238. package/vue3/es/src/components/VoiceSearch.vue_vue&type=template&id=24b0f67a&lang.js.map +1 -1
  239. package/vue3/es/src/connectors/connectStateResults.js.map +1 -1
  240. package/vue3/es/src/mixins/panel.js +1 -1
  241. package/vue3/es/src/mixins/panel.js.map +1 -1
  242. package/vue3/es/src/mixins/suit.js.map +1 -1
  243. package/vue3/es/src/mixins/widget.js +1 -1
  244. package/vue3/es/src/mixins/widget.js.map +1 -1
  245. package/vue3/es/src/plugin.js.map +1 -1
  246. package/vue3/es/src/util/createInstantSearchComponent.js +1 -1
  247. package/vue3/es/src/util/createInstantSearchComponent.js.map +1 -1
  248. package/vue3/es/src/util/createServerRootMixin.js +1 -1
  249. package/vue3/es/src/util/createServerRootMixin.js.map +1 -1
  250. package/vue3/es/src/util/parseAlgoliaHit.js +1 -1
  251. package/vue3/es/src/util/parseAlgoliaHit.js.map +1 -1
  252. package/vue3/es/src/util/polyfills.js.map +1 -1
  253. package/vue3/es/src/util/suit.js.map +1 -1
  254. package/vue3/es/src/util/unescape.js.map +1 -1
  255. package/vue3/es/src/util/vue-compat/{index-3.js → index-vue3.js} +1 -1
  256. package/vue3/es/src/util/vue-compat/index-vue3.js.map +1 -0
  257. package/vue3/umd/index.js +1 -1
  258. package/vue3/umd/index.js.map +1 -1
  259. package/vue2/es/src/util/vue-compat/index-2.js.map +0 -1
  260. package/vue3/es/src/util/vue-compat/index-3.js.map +0 -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: {
@@ -141,6 +149,14 @@ export default {
141
149
  this.$emit('update:modelValue', this.model);
142
150
  this.state.refine(this.model);
143
151
  }
152
+
153
+ // we return the local value if the input is focused to avoid
154
+ // concurrent updates when typing
155
+ const { searchInput } = this.$refs;
156
+ if (searchInput && searchInput.isFocused()) {
157
+ return this.localValue;
158
+ }
159
+
144
160
  return this.model || this.state.query || '';
145
161
  },
146
162
  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: {
@@ -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,
@@ -660,6 +660,60 @@ Array [
660
660
  await renderToString(wrapper);
661
661
  });
662
662
 
663
+ it('forwards nuxt', async () => {
664
+ const searchClient = createFakeClient();
665
+
666
+ let nuxt = 0;
667
+ // every time the function gets called, we get a different "nuxt"
668
+ // this can be used to assert both "nuxt" objects are equal
669
+ const getNuxtCounter = () => ++nuxt;
670
+
671
+ // there are two renders of App, each with an assertion
672
+ expect.assertions(2);
673
+
674
+ const App = {
675
+ mixins: [
676
+ {
677
+ beforeCreate() {
678
+ this.$nuxt = getNuxtCounter();
679
+ },
680
+ },
681
+ forceIsServerMixin,
682
+ createServerRootMixin({
683
+ searchClient,
684
+ indexName: 'hello',
685
+ }),
686
+ ],
687
+ data() {
688
+ expect(this.$nuxt).toEqual(1);
689
+ return {};
690
+ },
691
+ render: renderCompat(h =>
692
+ h(InstantSearchSsr, {}, [
693
+ h(Configure, {
694
+ attrs: {
695
+ hitsPerPage: 100,
696
+ },
697
+ }),
698
+ h(SearchBox),
699
+ ])
700
+ ),
701
+ serverPrefetch() {
702
+ return this.instantsearch.findResultsState({
703
+ component: this,
704
+ renderToString,
705
+ });
706
+ },
707
+ };
708
+
709
+ const wrapper = createSSRApp({
710
+ mixins: [forceIsServerMixin],
711
+ render: renderCompat(h => h(App)),
712
+ });
713
+
714
+ await renderToString(wrapper);
715
+ });
716
+
663
717
  it('searches only once', async () => {
664
718
  const searchClient = createFakeClient();
665
719
  const app = {
@@ -879,8 +933,9 @@ Array [
879
933
  hello: serialized,
880
934
  });
881
935
 
882
- // TODO: assert that this is expect.any(AlgoliaSearchHelper), but test fails
883
- // even though it's an object with all the right properties (including constructor)
936
+ expect(instantsearch.mainIndex.getHelper()).toEqual(
937
+ expect.any(AlgoliaSearchHelper)
938
+ );
884
939
  expect(instantsearch.mainIndex.getHelper()).not.toBeNull();
885
940
  });
886
941
 
@@ -1,7 +1,7 @@
1
1
  import { createSuitMixin } from '../mixins/suit';
2
2
  import { version } from '../../package.json'; // rollup does pick only what needed from json
3
3
  import { _objectSpread } from './polyfills';
4
- import { isVue3, version as vueVersion } from '../util/vue-compat';
4
+ import { isVue3, version as vueVersion } from './vue-compat';
5
5
 
6
6
  export const createInstantSearchComponent = component =>
7
7
  _objectSpread(
@@ -1,5 +1,5 @@
1
1
  import instantsearch from 'instantsearch.js/es';
2
- import { isVue3, isVue2, Vue2, createSSRApp } from '../util/vue-compat';
2
+ import { isVue3, isVue2, Vue2, createSSRApp } from './vue-compat';
3
3
  import { warn } from './warn';
4
4
 
5
5
  function walkIndex(indexWidget, visit) {
@@ -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 = [...appOptions.mixins, ...mixins];
44
+ appOptions.mixins = [...mixins, ...(appOptions.mixins || [])];
45
45
  app = createSSRApp(appOptions);
46
46
  if (componentInstance.$router) {
47
47
  app.use(componentInstance.$router);
@@ -104,6 +104,13 @@ function augmentInstantSearch(instantSearchOptions, cloneComponent) {
104
104
  app = cloneComponent(component, {
105
105
  mixins: [
106
106
  {
107
+ beforeCreate() {
108
+ if (component.$nuxt) {
109
+ // In case of Nuxt (3), we ensure the context is shared between
110
+ // the real and cloned component
111
+ this.$nuxt = component.$nuxt;
112
+ }
113
+ },
107
114
  created() {
108
115
  instance = this.instantsearch;
109
116
 
@@ -1,9 +1,9 @@
1
1
  /*
2
2
  By default, we maintain this repository based on Vue 2.
3
- That's why this file is exporting from `index-2`,
3
+ That's why this file is exporting from `index-vue2`,
4
4
  which includes all the variables and methods for Vue 2.
5
5
  When `scripts/build-vue3.sh` runs, it will replace with
6
- > export * from './index-3';
6
+ > export * from './index-vue3';
7
7
  and revert it back after finished.
8
8
  */
9
- export * from './index-2';
9
+ export * from './index-vue2';