@empathyco/x-components 3.0.0-alpha.145 → 3.0.0-alpha.148

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 (124) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/core/index.js +1 -1
  3. package/core/index.js.map +1 -1
  4. package/design-system/full-theme.css +59 -58
  5. package/docs/API-reference/api/x-adapter-platform.md +0 -1
  6. package/docs/API-reference/api/x-adapter-platform.searchresponsemapper.md +1 -11
  7. package/docs/API-reference/api/x-components.facetsmutations.md +1 -1
  8. package/docs/API-reference/api/x-components.facetsmutations.mutatefilter.md +24 -0
  9. package/docs/API-reference/api/x-components.flathierarchicalfilters.md +26 -0
  10. package/docs/API-reference/api/x-components.md +3 -0
  11. package/docs/API-reference/api/x-components.mutatefilterpayload.filter.md +13 -0
  12. package/docs/API-reference/api/x-components.mutatefilterpayload.md +21 -0
  13. package/docs/API-reference/api/x-components.mutatefilterpayload.newfilterstate.md +13 -0
  14. package/docs/API-reference/api/x-components.nextquerieslist.injectedquery.md +13 -0
  15. package/docs/API-reference/api/x-components.nextquerieslist.md +1 -0
  16. package/docs/API-reference/api/x-components.nextquerypreview.md +29 -0
  17. package/docs/API-reference/api/x-components.nextquerypreview.mounted.md +17 -0
  18. package/docs/API-reference/api/x-components.nextquerypreview.previewresults.md +13 -0
  19. package/docs/API-reference/api/x-components.nextquerypreview.suggestion.md +13 -0
  20. package/docs/API-reference/api/x-components.nextquerypreview.suggestionresults.md +13 -0
  21. package/docs/API-reference/api/x-components.resultslist.md +9 -0
  22. package/docs/API-reference/api/x-components.resultslist.providedquery.md +13 -0
  23. package/docs/API-reference/api/x-components.resultslist.searchquery.md +13 -0
  24. package/docs/API-reference/api/x-components.resultslist.searchstatus.md +13 -0
  25. package/docs/API-reference/api/x-components.resultslist.updatequery.md +24 -0
  26. package/docs/API-reference/api/x-types.hierarchicalfilter.children.md +2 -2
  27. package/docs/API-reference/api/x-types.hierarchicalfilter.md +2 -2
  28. package/docs/API-reference/api/x-types.hierarchicalfilter.parentid.md +1 -1
  29. package/docs/API-reference/components/next-queries/x-components.next-query-preview.md +155 -0
  30. package/docs/experience-search-&-discovery/README.md +119 -0
  31. package/docs/experience-search-&-discovery/empathize.md +102 -0
  32. package/docs/experience-search-&-discovery/facets-and-filters.md +138 -0
  33. package/docs/experience-search-&-discovery/history-queries.md +56 -0
  34. package/docs/experience-search-&-discovery/id-results.md +40 -0
  35. package/docs/experience-search-&-discovery/next-queries.md +52 -0
  36. package/docs/experience-search-&-discovery/popular-searches.md +32 -0
  37. package/docs/experience-search-&-discovery/product-results-ui.md +68 -0
  38. package/docs/experience-search-&-discovery/query-suggestions.md +32 -0
  39. package/docs/experience-search-&-discovery/recommendations.md +32 -0
  40. package/docs/experience-search-&-discovery/related-tags.md +41 -0
  41. package/docs/experience-search-&-discovery/search-box.md +81 -0
  42. package/docs/experience-search-&-discovery/serp-ui.md +109 -0
  43. package/docs/experience-search-&-discovery/web-local-storage.md +25 -0
  44. package/facets/index.js +1 -1
  45. package/js/components/base-grid.vue.js +2 -2
  46. package/js/components/base-grid.vue.js.map +1 -1
  47. package/js/components/decorators/injection.consts.js +8 -2
  48. package/js/components/decorators/injection.consts.js.map +1 -1
  49. package/js/index.js +4 -3
  50. package/js/index.js.map +1 -1
  51. package/js/x-modules/facets/components/facets/facets-provider.vue.js +2 -2
  52. package/js/x-modules/facets/components/facets/facets-provider.vue.js.map +1 -1
  53. package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js +7 -2
  54. package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  55. package/js/x-modules/facets/components/filters/hierarchical-filter.vue.js.map +1 -1
  56. package/js/x-modules/facets/components/filters/hierarchical-filter.vue_rollup-plugin-vue_script.vue.js +2 -130
  57. package/js/x-modules/facets/components/filters/hierarchical-filter.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  58. package/js/x-modules/facets/entities/editable-number-range-filter.entity.js +11 -10
  59. package/js/x-modules/facets/entities/editable-number-range-filter.entity.js.map +1 -1
  60. package/js/x-modules/facets/entities/hierarchical-filter.entity.js +9 -11
  61. package/js/x-modules/facets/entities/hierarchical-filter.entity.js.map +1 -1
  62. package/js/x-modules/facets/entities/number-range-filter.entity.js +2 -2
  63. package/js/x-modules/facets/entities/number-range-filter.entity.js.map +1 -1
  64. package/js/x-modules/facets/entities/raw-filter.entity.js +1 -1
  65. package/js/x-modules/facets/entities/raw-filter.entity.js.map +1 -1
  66. package/js/x-modules/facets/entities/simple-filter.entity.js +2 -2
  67. package/js/x-modules/facets/entities/simple-filter.entity.js.map +1 -1
  68. package/js/x-modules/facets/entities/single-select.modifier.js +1 -1
  69. package/js/x-modules/facets/entities/single-select.modifier.js.map +1 -1
  70. package/js/x-modules/facets/service/facets.service.js +18 -2
  71. package/js/x-modules/facets/service/facets.service.js.map +1 -1
  72. package/js/x-modules/facets/store/module.js +4 -3
  73. package/js/x-modules/facets/store/module.js.map +1 -1
  74. package/js/x-modules/facets/utils.js +16 -1
  75. package/js/x-modules/facets/utils.js.map +1 -1
  76. package/js/x-modules/next-queries/components/next-queries-list.vue.js.map +1 -1
  77. package/js/x-modules/next-queries/components/next-queries-list.vue_rollup-plugin-vue_script.vue.js +19 -0
  78. package/js/x-modules/next-queries/components/next-queries-list.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  79. package/js/x-modules/next-queries/components/next-query-preview.vue.js +94 -0
  80. package/js/x-modules/next-queries/components/next-query-preview.vue.js.map +1 -0
  81. package/js/x-modules/next-queries/components/next-query-preview.vue_rollup-plugin-vue_script.vue.js +48 -0
  82. package/js/x-modules/next-queries/components/next-query-preview.vue_rollup-plugin-vue_script.vue.js.map +1 -0
  83. package/js/x-modules/next-queries/store/actions/fetch-and-save-next-query-preview.action.js.map +1 -1
  84. package/js/x-modules/search/components/results-list.vue.js.map +1 -1
  85. package/js/x-modules/search/components/results-list.vue_rollup-plugin-vue_script.vue.js +33 -2
  86. package/js/x-modules/search/components/results-list.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  87. package/js/x-modules/search-box/components/search-input.vue.js +54 -45
  88. package/js/x-modules/search-box/components/search-input.vue.js.map +1 -1
  89. package/js/x-modules/search-box/components/search-input.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  90. package/next-queries/index.js +2 -1
  91. package/package.json +4 -4
  92. package/report/x-adapter-platform.api.json +5 -133
  93. package/report/x-components.api.json +491 -45
  94. package/report/x-components.api.md +32 -5
  95. package/report/x-types.api.json +5 -5
  96. package/types/components/decorators/injection.consts.d.ts +6 -0
  97. package/types/components/decorators/injection.consts.d.ts.map +1 -1
  98. package/types/x-modules/facets/components/facets/facets-provider.vue.d.ts.map +1 -1
  99. package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts +0 -6
  100. package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts.map +1 -1
  101. package/types/x-modules/facets/entities/editable-number-range-filter.entity.d.ts +1 -1
  102. package/types/x-modules/facets/entities/editable-number-range-filter.entity.d.ts.map +1 -1
  103. package/types/x-modules/facets/entities/hierarchical-filter.entity.d.ts +2 -1
  104. package/types/x-modules/facets/entities/hierarchical-filter.entity.d.ts.map +1 -1
  105. package/types/x-modules/facets/entities/single-select.modifier.d.ts.map +1 -1
  106. package/types/x-modules/facets/service/facets.service.d.ts +13 -0
  107. package/types/x-modules/facets/service/facets.service.d.ts.map +1 -1
  108. package/types/x-modules/facets/store/module.d.ts.map +1 -1
  109. package/types/x-modules/facets/store/types.d.ts +22 -6
  110. package/types/x-modules/facets/store/types.d.ts.map +1 -1
  111. package/types/x-modules/facets/utils.d.ts +11 -0
  112. package/types/x-modules/facets/utils.d.ts.map +1 -1
  113. package/types/x-modules/next-queries/components/index.d.ts +2 -1
  114. package/types/x-modules/next-queries/components/index.d.ts.map +1 -1
  115. package/types/x-modules/next-queries/components/next-queries-list.vue.d.ts +11 -0
  116. package/types/x-modules/next-queries/components/next-queries-list.vue.d.ts.map +1 -1
  117. package/types/x-modules/next-queries/components/next-query-preview.vue.d.ts +35 -0
  118. package/types/x-modules/next-queries/components/next-query-preview.vue.d.ts.map +1 -0
  119. package/types/x-modules/search/components/results-list.vue.d.ts +21 -0
  120. package/types/x-modules/search/components/results-list.vue.d.ts.map +1 -1
  121. package/types/x-modules/search-box/components/search-input.vue.d.ts.map +1 -1
  122. package/docs/API-reference/api/x-adapter-platform.searchresponsefacetsmapper.md +0 -27
  123. package/docs/API-reference/api/x-components.facetsmutations.setfilter.md +0 -24
  124. package/docs/functional-doc/web-local-storage.md +0 -22
@@ -1,9 +1,10 @@
1
- import { isFacetFilter } from '@empathyco/x-types';
1
+ import { isFacetFilter, isHierarchicalFacet } from '@empathyco/x-types';
2
2
  import '../../../plugins/x-bus.js';
3
3
  import { XPlugin } from '../../../plugins/x-plugin.js';
4
4
  import { isArrayEmpty, arrayToObject, groupItemsBy } from '../../../utils/array.js';
5
5
  import '../../../utils/storage.js';
6
6
  import { FilterEntityFactory } from '../entities/filter-entity.factory.js';
7
+ import { flatHierarchicalFilters } from '../utils.js';
7
8
 
8
9
  /**
9
10
  * Default implementation for the {@link FacetsService}.
@@ -85,10 +86,25 @@ class DefaultFacetsService {
85
86
  this.setFacetGroup({ facetId: facet.id, groupId: facetsGroup.id });
86
87
  this.setFacet(facet);
87
88
  });
88
- const newFilters = facetsGroup.facets.flatMap(facet => facet.filters);
89
+ const newFilters = this.flatFilters(facetsGroup);
89
90
  this.setFilters(newFilters);
90
91
  return newFilters;
91
92
  }
93
+ /**
94
+ * This function returns the filters of the facets group flattened in an array. It keeps the
95
+ * relations between the filters (parent--children).
96
+ *
97
+ * @privateRemarks If it is necessary to deal with more cases than the hierarchical, we need to
98
+ * refactor this logic and maybe move it to the entities, to not make this service dependant of
99
+ * the facet type. At the moment it is only one `if`, and is ok as long as no more `if`s are
100
+ * needed.
101
+ * @param facetsGroup - The facets group from where extract the filters to flat.
102
+ * @returns An array with the filters flattened.
103
+ * @internal
104
+ */
105
+ flatFilters(facetsGroup) {
106
+ return facetsGroup.facets.flatMap(facet => isHierarchicalFacet(facet) ? flatHierarchicalFilters(facet.filters) : facet.filters);
107
+ }
92
108
  /**
93
109
  * Retrieves the selected filters from the store.
94
110
  *
@@ -1 +1 @@
1
- {"version":3,"file":"facets.service.js","sources":["../../../../../src/x-modules/facets/service/facets.service.ts"],"sourcesContent":["import { Facet, Filter, isFacetFilter } from '@empathyco/x-types';\nimport { Store } from 'vuex';\nimport { XPlugin } from '../../../plugins/index';\nimport { RootXStoreState } from '../../../store/index';\nimport { arrayToObject, groupItemsBy, isArrayEmpty } from '../../../utils/index';\nimport { FilterEntityFactory } from '../entities/filter-entity.factory';\nimport { FilterEntity } from '../entities/types';\nimport { FacetGroupEntry, FacetsGetters } from '../store/types';\nimport { FacetsGroup, FacetsService } from './types';\n\n/**\n * Default implementation for the {@link FacetsService}.\n *\n * @public\n */\nexport class DefaultFacetsService implements FacetsService {\n /**\n * Global instance of the {@link FacetsService}.\n */\n public static instance: FacetsService = new DefaultFacetsService();\n\n public constructor(\n protected filterEntityFactory: FilterEntityFactory = FilterEntityFactory.instance\n ) {}\n\n /**\n * The {@link https://vuex.vuejs.org/ | Vuex} store to use in the service.\n *\n * @returns The store.\n * @internal\n */\n protected get store(): Store<RootXStoreState> {\n return XPlugin.store;\n }\n\n setFacets(facetsGroup: FacetsGroup): void {\n const newFilters = this.updateStore(facetsGroup);\n /* Ensures that filters are selected with valid values. For example, you can't set a single\n select facet with 2 or more selected filters */\n this.updateFiltersSelectedState(newFilters);\n }\n\n updateFacets(facetsGroup: FacetsGroup): void {\n const selectedFilters = this.getSelectedFilters();\n const newFilters = this.updateStore(facetsGroup);\n this.updateFiltersSelectedState(newFilters, selectedFilters);\n }\n\n updatePreselectedFilters(filters: Filter[]): void {\n this.setPreselectedFilter(filters);\n }\n\n selectPreselectedFilters(): void {\n this.select(this.store.state.x.facets.preselectedFilters);\n }\n\n clearFilters(facetIds?: Array<Facet['id']>): void {\n this.getSelectedFilters()\n .filter(filter => !facetIds || (isFacetFilter(filter) && facetIds.includes(filter.facetId)))\n .forEach(this.deselect.bind(this));\n }\n\n deselect(filter: Filter): void {\n this.getFilterEntity(filter).deselect(filter);\n }\n\n select(filterOrFilters: Filter | Filter[]): void {\n const filters = Array.isArray(filterOrFilters) ? filterOrFilters : [filterOrFilters];\n filters.forEach(filter => this.getFilterEntity(filter).select(filter));\n }\n\n toggle(filter: Filter): void {\n if (filter.selected) {\n this.deselect(filter);\n } else {\n this.select(filter);\n }\n }\n\n /**\n * Creates an entity from a filter DTO.\n *\n * @param filter - The filter to create an entity from.\n * @returns The filter entity.\n * @internal\n */\n protected getFilterEntity(filter: Filter): FilterEntity {\n return this.filterEntityFactory.getFilterEntity(this.store, filter);\n }\n\n /**\n * Sets in the store the Facets, the Filters and the FacetsGroup, without applying any logic\n * to the selected state.\n *\n * @param facetsGroup - The {@link FacetsGroup} to set into the store state.\n * @returns An array with the new filters.\n * @internal\n */\n protected updateStore(facetsGroup: FacetsGroup): Filter[] {\n this.removeGroupFacets(facetsGroup.id);\n this.removeGroupFilters(facetsGroup.id);\n facetsGroup.facets.forEach(facet => {\n this.setFacetGroup({ facetId: facet.id, groupId: facetsGroup.id });\n this.setFacet(facet);\n });\n const newFilters = facetsGroup.facets.flatMap(facet => facet.filters);\n this.setFilters(newFilters);\n return newFilters;\n }\n\n /**\n * Retrieves the selected filters from the store.\n *\n * @returns The list of selected filters of the store.\n * @internal\n */\n protected getSelectedFilters(): FacetsGetters['selectedFilters'] {\n return this.store.getters['x/facets/selectedFilters'];\n }\n\n /**\n * Changes the filters selection state to match the store.\n *\n * @param newFilters - The list of filters to save.\n * @param previousFilters - (Optional) The list of old filters, used to set the `newFilters`\n * selected state.\n */\n protected updateFiltersSelectedState(newFilters: Filter[], previousFilters?: Filter[]): void {\n if (!isArrayEmpty(newFilters)) {\n const newStateFiltersMap = arrayToObject(previousFilters ?? newFilters, 'id');\n newFilters.forEach(filter => {\n const filterEntity = this.getFilterEntity(filter);\n if (newStateFiltersMap[filter.id]?.selected) {\n filterEntity.select(filter);\n } else {\n filterEntity.deselect(filter);\n }\n });\n }\n }\n\n /**\n * Removes the filters that belong to the given group.\n *\n * @param groupId - The id of the group from whom remove the filters that are in the store.\n *\n * @returns The removed filters.\n *\n * @internal\n */\n protected removeGroupFilters(groupId: FacetsGroup['id']): Filter[] {\n const filtersToRemove =\n groupItemsBy(Object.values(this.store.state.x.facets.filters), filter =>\n isFacetFilter(filter)\n ? this.store.state.x.facets.groups[filter.facetId]\n : '__unknown-group__'\n )[groupId] ?? [];\n this.removeFilters(filtersToRemove);\n return filtersToRemove;\n }\n /**\n * Removes the facets that belong to the given group.\n *\n * @param groupId - The id of the group from whom remove the facets that are in the store.\n * @returns The removed facets.\n * @internal\n */\n protected removeGroupFacets(groupId: FacetsGroup['id']): Omit<Facet, 'filters'>[] {\n const facetsToRemove = Object.values(this.store.state.x.facets.facets).filter(\n facet => this.store.state.x.facets.groups[facet.id] === groupId\n );\n facetsToRemove.forEach(this.removeFacet.bind(this));\n return facetsToRemove;\n }\n\n /**\n * Sets the group that a facet belongs to.\n *\n * @param facetGroup - The id of the facet, and the group it belongs to.\n * @internal\n */\n protected setFacetGroup(facetGroup: FacetGroupEntry): void {\n this.store.commit('x/facets/setFacetGroup', facetGroup);\n }\n\n /**\n * Sets the Facet to the store facets record.\n *\n * @param facet - The facet to store.\n *\n * @internal\n */\n protected setFacet({ filters, ...restFacet }: Facet): void {\n this.store.commit('x/facets/setFacet', restFacet);\n }\n\n /**\n * Removes a facet from the store.\n *\n * @param facet - The facet to remove.\n * @internal\n */\n protected removeFacet(facet: Omit<Facet, 'filters'>): void {\n this.store.commit('x/facets/removeFacet', facet);\n }\n\n /**\n * Saves a list of filters to the store without any state change logic applied.\n *\n * @param filters - The filters to save.\n * @internal\n */\n protected setFilters(filters: Filter[]): void {\n this.store.commit('x/facets/setFilters', filters);\n }\n\n /**\n * Saves a list of preselected filters to the store without any state change logic applied.\n *\n * @param filters - The filters to save.\n * @internal\n */\n protected setPreselectedFilter(filters: Filter[]): void {\n this.store.commit('x/facets/setPreselectedFilters', filters);\n }\n\n /**\n * Removes a list of filters from the store.\n *\n * @param filters - The filters to remove.\n * @internal\n */\n protected removeFilters(filters: Filter[]): void {\n this.store.commit('x/facets/removeFilters', filters);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"facets.service.js","sources":["../../../../../src/x-modules/facets/service/facets.service.ts"],"sourcesContent":["import { Facet, Filter, isFacetFilter, isHierarchicalFacet } from '@empathyco/x-types';\nimport { Store } from 'vuex';\nimport { XPlugin } from '../../../plugins/index';\nimport { RootXStoreState } from '../../../store/index';\nimport { arrayToObject, groupItemsBy, isArrayEmpty } from '../../../utils/index';\nimport { FilterEntityFactory } from '../entities/filter-entity.factory';\nimport { FilterEntity } from '../entities/types';\nimport { FacetGroupEntry, FacetsGetters } from '../store/types';\nimport { flatHierarchicalFilters } from '../utils';\nimport { FacetsGroup, FacetsService } from './types';\n\n/**\n * Default implementation for the {@link FacetsService}.\n *\n * @public\n */\nexport class DefaultFacetsService implements FacetsService {\n /**\n * Global instance of the {@link FacetsService}.\n */\n public static instance: FacetsService = new DefaultFacetsService();\n\n public constructor(\n protected filterEntityFactory: FilterEntityFactory = FilterEntityFactory.instance\n ) {}\n\n /**\n * The {@link https://vuex.vuejs.org/ | Vuex} store to use in the service.\n *\n * @returns The store.\n * @internal\n */\n protected get store(): Store<RootXStoreState> {\n return XPlugin.store;\n }\n\n setFacets(facetsGroup: FacetsGroup): void {\n const newFilters = this.updateStore(facetsGroup);\n /* Ensures that filters are selected with valid values. For example, you can't set a single\n select facet with 2 or more selected filters */\n this.updateFiltersSelectedState(newFilters);\n }\n\n updateFacets(facetsGroup: FacetsGroup): void {\n const selectedFilters = this.getSelectedFilters();\n const newFilters = this.updateStore(facetsGroup);\n this.updateFiltersSelectedState(newFilters, selectedFilters);\n }\n\n updatePreselectedFilters(filters: Filter[]): void {\n this.setPreselectedFilter(filters);\n }\n\n selectPreselectedFilters(): void {\n this.select(this.store.state.x.facets.preselectedFilters);\n }\n\n clearFilters(facetIds?: Array<Facet['id']>): void {\n this.getSelectedFilters()\n .filter(filter => !facetIds || (isFacetFilter(filter) && facetIds.includes(filter.facetId)))\n .forEach(this.deselect.bind(this));\n }\n\n deselect(filter: Filter): void {\n this.getFilterEntity(filter).deselect(filter);\n }\n\n select(filterOrFilters: Filter | Filter[]): void {\n const filters = Array.isArray(filterOrFilters) ? filterOrFilters : [filterOrFilters];\n filters.forEach(filter => this.getFilterEntity(filter).select(filter));\n }\n\n toggle(filter: Filter): void {\n if (filter.selected) {\n this.deselect(filter);\n } else {\n this.select(filter);\n }\n }\n\n /**\n * Creates an entity from a filter DTO.\n *\n * @param filter - The filter to create an entity from.\n * @returns The filter entity.\n * @internal\n */\n protected getFilterEntity(filter: Filter): FilterEntity {\n return this.filterEntityFactory.getFilterEntity(this.store, filter);\n }\n\n /**\n * Sets in the store the Facets, the Filters and the FacetsGroup, without applying any logic\n * to the selected state.\n *\n * @param facetsGroup - The {@link FacetsGroup} to set into the store state.\n * @returns An array with the new filters.\n * @internal\n */\n protected updateStore(facetsGroup: FacetsGroup): Filter[] {\n this.removeGroupFacets(facetsGroup.id);\n this.removeGroupFilters(facetsGroup.id);\n facetsGroup.facets.forEach(facet => {\n this.setFacetGroup({ facetId: facet.id, groupId: facetsGroup.id });\n this.setFacet(facet);\n });\n const newFilters = this.flatFilters(facetsGroup);\n this.setFilters(newFilters);\n return newFilters;\n }\n\n /**\n * This function returns the filters of the facets group flattened in an array. It keeps the\n * relations between the filters (parent--children).\n *\n * @privateRemarks If it is necessary to deal with more cases than the hierarchical, we need to\n * refactor this logic and maybe move it to the entities, to not make this service dependant of\n * the facet type. At the moment it is only one `if`, and is ok as long as no more `if`s are\n * needed.\n * @param facetsGroup - The facets group from where extract the filters to flat.\n * @returns An array with the filters flattened.\n * @internal\n */\n protected flatFilters(facetsGroup: FacetsGroup): Filter[] {\n return facetsGroup.facets.flatMap(facet =>\n isHierarchicalFacet(facet) ? flatHierarchicalFilters(facet.filters) : facet.filters\n );\n }\n\n /**\n * Retrieves the selected filters from the store.\n *\n * @returns The list of selected filters of the store.\n * @internal\n */\n protected getSelectedFilters(): FacetsGetters['selectedFilters'] {\n return this.store.getters['x/facets/selectedFilters'];\n }\n\n /**\n * Changes the filters selection state to match the store.\n *\n * @param newFilters - The list of filters to save.\n * @param previousFilters - (Optional) The list of old filters, used to set the `newFilters`\n * selected state.\n */\n protected updateFiltersSelectedState(newFilters: Filter[], previousFilters?: Filter[]): void {\n if (!isArrayEmpty(newFilters)) {\n const newStateFiltersMap = arrayToObject(previousFilters ?? newFilters, 'id');\n newFilters.forEach(filter => {\n const filterEntity = this.getFilterEntity(filter);\n if (newStateFiltersMap[filter.id]?.selected) {\n filterEntity.select(filter);\n } else {\n filterEntity.deselect(filter);\n }\n });\n }\n }\n\n /**\n * Removes the filters that belong to the given group.\n *\n * @param groupId - The id of the group from whom remove the filters that are in the store.\n *\n * @returns The removed filters.\n *\n * @internal\n */\n protected removeGroupFilters(groupId: FacetsGroup['id']): Filter[] {\n const filtersToRemove =\n groupItemsBy(Object.values(this.store.state.x.facets.filters), filter =>\n isFacetFilter(filter)\n ? this.store.state.x.facets.groups[filter.facetId]\n : '__unknown-group__'\n )[groupId] ?? [];\n this.removeFilters(filtersToRemove);\n return filtersToRemove;\n }\n\n /**\n * Removes the facets that belong to the given group.\n *\n * @param groupId - The id of the group from whom remove the facets that are in the store.\n * @returns The removed facets.\n * @internal\n */\n protected removeGroupFacets(groupId: FacetsGroup['id']): Omit<Facet, 'filters'>[] {\n const facetsToRemove = Object.values(this.store.state.x.facets.facets).filter(\n facet => this.store.state.x.facets.groups[facet.id] === groupId\n );\n facetsToRemove.forEach(this.removeFacet.bind(this));\n return facetsToRemove;\n }\n\n /**\n * Sets the group that a facet belongs to.\n *\n * @param facetGroup - The id of the facet, and the group it belongs to.\n * @internal\n */\n protected setFacetGroup(facetGroup: FacetGroupEntry): void {\n this.store.commit('x/facets/setFacetGroup', facetGroup);\n }\n\n /**\n * Sets the Facet to the store facets record.\n *\n * @param facet - The facet to store.\n *\n * @internal\n */\n protected setFacet({ filters, ...restFacet }: Facet): void {\n this.store.commit('x/facets/setFacet', restFacet);\n }\n\n /**\n * Removes a facet from the store.\n *\n * @param facet - The facet to remove.\n * @internal\n */\n protected removeFacet(facet: Omit<Facet, 'filters'>): void {\n this.store.commit('x/facets/removeFacet', facet);\n }\n\n /**\n * Saves a list of filters to the store without any state change logic applied.\n *\n * @param filters - The filters to save.\n * @internal\n */\n protected setFilters(filters: Filter[]): void {\n this.store.commit('x/facets/setFilters', filters);\n }\n\n /**\n * Saves a list of preselected filters to the store without any state change logic applied.\n *\n * @param filters - The filters to save.\n * @internal\n */\n protected setPreselectedFilter(filters: Filter[]): void {\n this.store.commit('x/facets/setPreselectedFilters', filters);\n }\n\n /**\n * Removes a list of filters from the store.\n *\n * @param filters - The filters to remove.\n * @internal\n */\n protected removeFilters(filters: Filter[]): void {\n this.store.commit('x/facets/removeFilters', filters);\n }\n}\n"],"names":[],"mappings":";;;;;;;;AAWA;;;;;MAKa,oBAAoB;IAM/B,YACY,sBAA2C,mBAAmB,CAAC,QAAQ;QAAvE,wBAAmB,GAAnB,mBAAmB,CAAoD;KAC/E;;;;;;;IAQJ,IAAc,KAAK;QACjB,OAAO,OAAO,CAAC,KAAK,CAAC;KACtB;IAED,SAAS,CAAC,WAAwB;QAChC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;;;QAGjD,IAAI,CAAC,0BAA0B,CAAC,UAAU,CAAC,CAAC;KAC7C;IAED,YAAY,CAAC,WAAwB;QACnC,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QACjD,IAAI,CAAC,0BAA0B,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;KAC9D;IAED,wBAAwB,CAAC,OAAiB;QACxC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;KACpC;IAED,wBAAwB;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;KAC3D;IAED,YAAY,CAAC,QAA6B;QACxC,IAAI,CAAC,kBAAkB,EAAE;aACtB,MAAM,CAAC,MAAM,IAAI,CAAC,QAAQ,KAAK,aAAa,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;aAC3F,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;KACtC;IAED,QAAQ,CAAC,MAAc;QACrB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;KAC/C;IAED,MAAM,CAAC,eAAkC;QACvC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,GAAG,CAAC,eAAe,CAAC,CAAC;QACrF,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;KACxE;IAED,MAAM,CAAC,MAAc;QACnB,IAAI,MAAM,CAAC,QAAQ,EAAE;YACnB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;SACvB;aAAM;YACL,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SACrB;KACF;;;;;;;;IASS,eAAe,CAAC,MAAc;QACtC,OAAO,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;KACrE;;;;;;;;;IAUS,WAAW,CAAC,WAAwB;QAC5C,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK;YAC9B,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SACtB,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC5B,OAAO,UAAU,CAAC;KACnB;;;;;;;;;;;;;IAcS,WAAW,CAAC,WAAwB;QAC5C,OAAO,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IACrC,mBAAmB,CAAC,KAAK,CAAC,GAAG,uBAAuB,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,OAAO,CACpF,CAAC;KACH;;;;;;;IAQS,kBAAkB;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;KACvD;;;;;;;;IASS,0BAA0B,CAAC,UAAoB,EAAE,eAA0B;QACnF,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE;YAC7B,MAAM,kBAAkB,GAAG,aAAa,CAAC,eAAe,IAAI,UAAU,EAAE,IAAI,CAAC,CAAC;YAC9E,UAAU,CAAC,OAAO,CAAC,MAAM;gBACvB,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;gBAClD,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE;oBAC3C,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;iBAC7B;qBAAM;oBACL,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;iBAC/B;aACF,CAAC,CAAC;SACJ;KACF;;;;;;;;;;IAWS,kBAAkB,CAAC,OAA0B;QACrD,MAAM,eAAe,GACnB,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IACnE,aAAa,CAAC,MAAM,CAAC;cACjB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;cAChD,mBAAmB,CACxB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;QACpC,OAAO,eAAe,CAAC;KACxB;;;;;;;;IASS,iBAAiB,CAAC,OAA0B;QACpD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAC3E,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,OAAO,CAChE,CAAC;QACF,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,OAAO,cAAc,CAAC;KACvB;;;;;;;IAQS,aAAa,CAAC,UAA2B;QACjD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,EAAE,UAAU,CAAC,CAAC;KACzD;;;;;;;;IASS,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,EAAS;QACjD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;KACnD;;;;;;;IAQS,WAAW,CAAC,KAA6B;QACjD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;KAClD;;;;;;;IAQS,UAAU,CAAC,OAAiB;QACpC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;KACnD;;;;;;;IAQS,oBAAoB,CAAC,OAAiB;QAC9C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,gCAAgC,EAAE,OAAO,CAAC,CAAC;KAC9D;;;;;;;IAQS,aAAa,CAAC,OAAiB;QACvC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;KACtD;;AA7OD;;;AAGc,6BAAQ,GAAkB,IAAI,oBAAoB,EAAE;;;;"}
@@ -21,11 +21,12 @@ const facetsXStoreModule = {
21
21
  facets
22
22
  },
23
23
  mutations: {
24
- setFilter(state, filter) {
25
- Vue.set(state.filters, filter.id, Object.freeze(filter));
24
+ mutateFilter(state, { filter, newFilterState }) {
25
+ const newFilter = Object.assign(filter, newFilterState);
26
+ Vue.set(state.filters, newFilter.id, newFilter);
26
27
  },
27
28
  setFilters(state, filters) {
28
- filters.forEach(filter => Vue.set(state.filters, filter.id, Object.freeze(filter)));
29
+ filters.forEach(filter => Vue.set(state.filters, filter.id, filter));
29
30
  },
30
31
  setPreselectedFilters(state, filters) {
31
32
  state.preselectedFilters = filters;
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sources":["../../../../../src/x-modules/facets/store/module.ts"],"sourcesContent":["import { Facet } from '@empathyco/x-types';\nimport Vue from 'vue';\nimport { facets } from './getters/facets.getter';\nimport { selectedFiltersByFacet } from './getters/selected-filters-by-facet.getter';\nimport { selectedFilters } from './getters/selected-filters.getter';\nimport { FacetGroupEntry, FacetsXStoreModule } from './types';\n\n/**\n * {@link XStoreModule} For the facets module.\n *\n * @internal\n */\nexport const facetsXStoreModule: FacetsXStoreModule = {\n state: () => ({\n filters: {},\n groups: {},\n facets: {},\n preselectedFilters: []\n }),\n getters: {\n selectedFilters,\n selectedFiltersByFacet,\n facets\n },\n mutations: {\n setFilter(state, filter) {\n Vue.set(state.filters, filter.id, Object.freeze(filter));\n },\n setFilters(state, filters) {\n filters.forEach(filter => Vue.set(state.filters, filter.id, Object.freeze(filter)));\n },\n setPreselectedFilters(state, filters) {\n state.preselectedFilters = filters;\n },\n removeFilter(state, { id }) {\n Vue.delete(state.filters, id);\n },\n removeFilters(state, filters) {\n filters.forEach(({ id }) => Vue.delete(state.filters, id));\n },\n setFacetGroup(state, { facetId, groupId }: FacetGroupEntry) {\n Vue.set(state.groups, facetId, groupId);\n },\n removeFacet(state, { id }) {\n Vue.delete(state.facets, id);\n },\n setFacet(state, facet: Facet) {\n Vue.set(state.facets, facet.id, facet);\n }\n },\n actions: {}\n};\n"],"names":[],"mappings":";;;;;AAOA;;;;;MAKa,kBAAkB,GAAuB;IACpD,KAAK,EAAE,OAAO;QACZ,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,EAAE;QACV,kBAAkB,EAAE,EAAE;KACvB,CAAC;IACF,OAAO,EAAE;QACP,eAAe;QACf,sBAAsB;QACtB,MAAM;KACP;IACD,SAAS,EAAE;QACT,SAAS,CAAC,KAAK,EAAE,MAAM;YACrB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;SAC1D;QACD,UAAU,CAAC,KAAK,EAAE,OAAO;YACvB,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;SACrF;QACD,qBAAqB,CAAC,KAAK,EAAE,OAAO;YAClC,KAAK,CAAC,kBAAkB,GAAG,OAAO,CAAC;SACpC;QACD,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACxB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;SAC/B;QACD,aAAa,CAAC,KAAK,EAAE,OAAO;YAC1B,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;SAC5D;QACD,aAAa,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAmB;YACxD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;QACD,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACvB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;SAC9B;QACD,QAAQ,CAAC,KAAK,EAAE,KAAY;YAC1B,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;SACxC;KACF;IACD,OAAO,EAAE,EAAE;;;;;"}
1
+ {"version":3,"file":"module.js","sources":["../../../../../src/x-modules/facets/store/module.ts"],"sourcesContent":["import { Facet } from '@empathyco/x-types';\nimport Vue from 'vue';\nimport { facets } from './getters/facets.getter';\nimport { selectedFiltersByFacet } from './getters/selected-filters-by-facet.getter';\nimport { selectedFilters } from './getters/selected-filters.getter';\nimport { FacetGroupEntry, FacetsXStoreModule } from './types';\n\n/**\n * {@link XStoreModule} For the facets module.\n *\n * @internal\n */\nexport const facetsXStoreModule: FacetsXStoreModule = {\n state: () => ({\n filters: {},\n groups: {},\n facets: {},\n preselectedFilters: []\n }),\n getters: {\n selectedFilters,\n selectedFiltersByFacet,\n facets\n },\n mutations: {\n mutateFilter(state, { filter, newFilterState }) {\n const newFilter = Object.assign(filter, newFilterState);\n Vue.set(state.filters, newFilter.id, newFilter);\n },\n setFilters(state, filters) {\n filters.forEach(filter => Vue.set(state.filters, filter.id, filter));\n },\n setPreselectedFilters(state, filters) {\n state.preselectedFilters = filters;\n },\n removeFilter(state, { id }) {\n Vue.delete(state.filters, id);\n },\n removeFilters(state, filters) {\n filters.forEach(({ id }) => Vue.delete(state.filters, id));\n },\n setFacetGroup(state, { facetId, groupId }: FacetGroupEntry) {\n Vue.set(state.groups, facetId, groupId);\n },\n removeFacet(state, { id }) {\n Vue.delete(state.facets, id);\n },\n setFacet(state, facet: Facet) {\n Vue.set(state.facets, facet.id, facet);\n }\n },\n actions: {}\n};\n"],"names":[],"mappings":";;;;;AAOA;;;;;MAKa,kBAAkB,GAAuB;IACpD,KAAK,EAAE,OAAO;QACZ,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,EAAE;QACV,kBAAkB,EAAE,EAAE;KACvB,CAAC;IACF,OAAO,EAAE;QACP,eAAe;QACf,sBAAsB;QACtB,MAAM;KACP;IACD,SAAS,EAAE;QACT,YAAY,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE;YAC5C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;YACxD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;SACjD;QACD,UAAU,CAAC,KAAK,EAAE,OAAO;YACvB,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;SACtE;QACD,qBAAqB,CAAC,KAAK,EAAE,OAAO;YAClC,KAAK,CAAC,kBAAkB,GAAG,OAAO,CAAC;SACpC;QACD,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACxB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;SAC/B;QACD,aAAa,CAAC,KAAK,EAAE,OAAO;YAC1B,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;SAC5D;QACD,aAAa,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAmB;YACxD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;SACzC;QACD,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACvB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;SAC9B;QACD,QAAQ,CAAC,KAAK,EAAE,KAAY;YAC1B,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;SACxC;KACF;IACD,OAAO,EAAE,EAAE;;;;;"}
@@ -36,7 +36,22 @@ function isNewQuery(newQuery, previousQuery) {
36
36
  return (!previousQueryWords.every(previousQueryWord => newQueryWords.some(newQueryWord => newQueryWord.includes(previousQueryWord) || previousQueryWord.includes(newQueryWord))) ||
37
37
  (isNewQueryEmpty && !isPreviousQueryEmpty) ||
38
38
  (!isNewQueryEmpty && isPreviousQueryEmpty));
39
+ }
40
+ /**
41
+ * This function flattens the Hierarchical Filters, returning an array with all filters including
42
+ * the children.
43
+ *
44
+ * @param hierarchicalFilters - The list of Hierarchical Filters to flatten.
45
+ * @returns An array with all the Hierarchical filters.
46
+ *
47
+ * @public
48
+ */
49
+ function flatHierarchicalFilters(hierarchicalFilters) {
50
+ return hierarchicalFilters.reduce(function flat(flattenedFilters, filter) {
51
+ flattenedFilters.push(filter);
52
+ return filter?.children?.reduce(flat, flattenedFilters) ?? flattenedFilters;
53
+ }, []);
39
54
  }
40
55
 
41
- export { isNewQuery };
56
+ export { flatHierarchicalFilters, isNewQuery };
42
57
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../src/x-modules/facets/utils.ts"],"sourcesContent":["import { isStringEmpty } from '../../utils/string';\n\n/**\n * Compares two queries to know if the new one is a refined query from the previous one or a new\n * one.\n *\n * A refined query is a query which has the previous query or part of it.\n * Example:\n * - previousQuery = 'lego star'.\n * - newQuery = 'lego star wars'.\n *\n * Example:\n * - previousQuery = 'lego star wars'.\n * - newQuery = 'lego star'.\n *\n * A new query is a query which has not the previous query.\n * Example:\n * - previousQuery = 'lego star'.\n * - newQuery = 'lego wars'.\n *\n * In this case, it is changing the word set, because a word is changed by another one, so\n * this is changing the search intention.\n *\n * @param newQuery - The new query.\n * @param previousQuery - The previous query.\n *\n * @returns A boolean which flags if the query is refined or not.\n *\n * @public\n */\nexport function isNewQuery(newQuery: string, previousQuery: string): boolean {\n const isNewQueryEmpty = isStringEmpty(newQuery);\n const isPreviousQueryEmpty = isStringEmpty(previousQuery);\n const previousQueryWords = previousQuery.split(' ');\n const newQueryWords = newQuery.split(' ');\n return (\n !previousQueryWords.every(previousQueryWord =>\n newQueryWords.some(\n newQueryWord =>\n newQueryWord.includes(previousQueryWord) || previousQueryWord.includes(newQueryWord)\n )\n ) ||\n (isNewQueryEmpty && !isPreviousQueryEmpty) ||\n (!isNewQueryEmpty && isPreviousQueryEmpty)\n );\n}\n"],"names":[],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA4BgB,UAAU,CAAC,QAAgB,EAAE,aAAqB;IAChE,MAAM,eAAe,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,oBAAoB,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAC1D,MAAM,kBAAkB,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,QACE,CAAC,kBAAkB,CAAC,KAAK,CAAC,iBAAiB,IACzC,aAAa,CAAC,IAAI,CAChB,YAAY,IACV,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,YAAY,CAAC,CACvF,CACF;SACA,eAAe,IAAI,CAAC,oBAAoB,CAAC;SACzC,CAAC,eAAe,IAAI,oBAAoB,CAAC,EAC1C;AACJ;;;;"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/x-modules/facets/utils.ts"],"sourcesContent":["import { HierarchicalFilter } from '@empathyco/x-types';\nimport { isStringEmpty } from '../../utils/string';\n\n/**\n * Compares two queries to know if the new one is a refined query from the previous one or a new\n * one.\n *\n * A refined query is a query which has the previous query or part of it.\n * Example:\n * - previousQuery = 'lego star'.\n * - newQuery = 'lego star wars'.\n *\n * Example:\n * - previousQuery = 'lego star wars'.\n * - newQuery = 'lego star'.\n *\n * A new query is a query which has not the previous query.\n * Example:\n * - previousQuery = 'lego star'.\n * - newQuery = 'lego wars'.\n *\n * In this case, it is changing the word set, because a word is changed by another one, so\n * this is changing the search intention.\n *\n * @param newQuery - The new query.\n * @param previousQuery - The previous query.\n *\n * @returns A boolean which flags if the query is refined or not.\n *\n * @public\n */\nexport function isNewQuery(newQuery: string, previousQuery: string): boolean {\n const isNewQueryEmpty = isStringEmpty(newQuery);\n const isPreviousQueryEmpty = isStringEmpty(previousQuery);\n const previousQueryWords = previousQuery.split(' ');\n const newQueryWords = newQuery.split(' ');\n return (\n !previousQueryWords.every(previousQueryWord =>\n newQueryWords.some(\n newQueryWord =>\n newQueryWord.includes(previousQueryWord) || previousQueryWord.includes(newQueryWord)\n )\n ) ||\n (isNewQueryEmpty && !isPreviousQueryEmpty) ||\n (!isNewQueryEmpty && isPreviousQueryEmpty)\n );\n}\n\n/**\n * This function flattens the Hierarchical Filters, returning an array with all filters including\n * the children.\n *\n * @param hierarchicalFilters - The list of Hierarchical Filters to flatten.\n * @returns An array with all the Hierarchical filters.\n *\n * @public\n */\nexport function flatHierarchicalFilters(\n hierarchicalFilters: HierarchicalFilter[]\n): HierarchicalFilter[] {\n return hierarchicalFilters.reduce(function flat(flattenedFilters, filter): HierarchicalFilter[] {\n flattenedFilters.push(filter);\n return filter?.children?.reduce(flat, flattenedFilters) ?? flattenedFilters;\n }, [] as HierarchicalFilter[]);\n}\n"],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA4BgB,UAAU,CAAC,QAAgB,EAAE,aAAqB;IAChE,MAAM,eAAe,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,oBAAoB,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAC1D,MAAM,kBAAkB,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,QACE,CAAC,kBAAkB,CAAC,KAAK,CAAC,iBAAiB,IACzC,aAAa,CAAC,IAAI,CAChB,YAAY,IACV,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,CAAC,QAAQ,CAAC,YAAY,CAAC,CACvF,CACF;SACA,eAAe,IAAI,CAAC,oBAAoB,CAAC;SACzC,CAAC,eAAe,IAAI,oBAAoB,CAAC,EAC1C;AACJ,CAAC;AAED;;;;;;;;;SASgB,uBAAuB,CACrC,mBAAyC;IAEzC,OAAO,mBAAmB,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,gBAAgB,EAAE,MAAM;QACtE,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,IAAI,gBAAgB,CAAC;KAC7E,EAAE,EAA0B,CAAC,CAAC;AACjC;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"next-queries-list.vue.js","sources":["../../../../../src/x-modules/next-queries/components/next-queries-list.vue"],"sourcesContent":["<template>\n <NoElement>\n <!--\n @slot Next queries list layout.\n @binding {SearchItem[]} items - Next queries groups plus the injected list items to\n render.\n @binding {Vue | string} animation - Animation to animate the elements.\n -->\n <slot v-bind=\"{ items, animation }\">\n <ItemsList :animation=\"animation\" :items=\"items\">\n <template v-for=\"(_, slotName) in $scopedSlots\" v-slot:[slotName]=\"{ item }\">\n <slot :name=\"slotName\" :item=\"item\" />\n </template>\n </ItemsList>\n </slot>\n </NoElement>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { NextQuery } from '@empathyco/x-types';\n import { mixins } from 'vue-class-component';\n import { Component, Prop } from 'vue-property-decorator';\n import { Getter } from '../../../components/decorators/store.decorators';\n import { NoElement } from '../../../components/no-element';\n import { ItemsListInjectionMixin } from '../../../components/items-list-injection.mixin';\n import ItemsList from '../../../components/items-list.vue';\n import { xComponentMixin } from '../../../components/x-component.mixin';\n import { groupItemsBy } from '../../../utils/array';\n import { ListItem } from '../../../utils/types';\n import ResultsList from '../../search/components/results-list.vue';\n import { NextQueriesGroup } from '../types';\n import { nextQueriesXModule } from '../x-module';\n\n /**\n * Component that inserts groups of next queries in different positions of the injected search\n * items list, based on the provided configuration.\n *\n * @public\n */\n @Component({\n components: {\n ResultsList,\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(nextQueriesXModule)]\n })\n export default class NextQueriesList extends mixins(ItemsListInjectionMixin) {\n /**\n * Animation component that will be used to animate the next queries groups.\n *\n * @public\n */\n @Prop()\n protected animation?: Vue | string;\n\n /**\n * The first index to insert a group of next queries at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public offset!: number;\n\n /**\n * The items cycle size to keep inserting next queries groups at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public frequency!: number;\n\n /**\n * The maximum amount of next queries to add in a single group.\n *\n * @public\n */\n @Prop({ default: 4 })\n public maxNextQueriesPerGroup!: number;\n\n /**\n * The maximum number of groups to insert into the injected list items list.\n *\n * @public\n */\n @Prop()\n public maxGroups!: number;\n\n /**\n * The state next queries.\n *\n * @internal\n */\n @Getter('nextQueries', 'nextQueries')\n public nextQueries!: NextQuery[];\n\n /**\n * The grouped next queries based on the given config.\n *\n * @returns A list of next queries groups.\n * @internal\n */\n protected get nextQueriesGroups(): NextQueriesGroup[] {\n return Object.values(\n groupItemsBy(this.nextQueries, (_, index) =>\n Math.floor(index / this.maxNextQueriesPerGroup)\n )\n )\n .slice(0, this.maxGroups)\n .map(nextQueries => ({\n modelName: 'NextQueriesGroup' as const,\n id: nextQueries.map(nextQuery => nextQuery.query).join(','),\n nextQueries\n }));\n }\n\n /**\n * New list of {@link ListItem}s to render.\n *\n * @returns The new list of {@link ListItem}s with the next queries groups inserted.\n * @internal\n */\n public override get items(): ListItem[] {\n if (!this.injectedListItems) {\n return this.nextQueriesGroups;\n }\n\n return this.nextQueriesGroups.reduce(\n (items, nextQueriesGroup, index) => {\n const targetIndex = this.offset + this.frequency * index;\n if (targetIndex <= items.length) {\n items.splice(targetIndex, 0, nextQueriesGroup);\n }\n return items;\n },\n [...this.injectedListItems]\n );\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits no events.\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend microservice required\nTo use this component, the <b>QuerySignals</b> microservice must be\nimplemented.\n:::\n<!-- prettier-ignore-end -->\n\nUsually, this component is going to be used together with the `ResultsList` one. Next queries groups\nwill be inserted between the results, guiding users to discover new searches directly from the\nresults list.\n\n```vue live\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <NextQueriesList />\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { NextQueriesList } from '@empathyco/x-components/next-queries';\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'NextQueriesListDemo',\n components: {\n NextQueriesList,\n ResultsList,\n SearchInput\n }\n };\n</script>\n```\n\n### Play with the index that next queries groups are inserted at\n\nThe component allows to customise where are the next queries groups inserted. In the following\nexample, the first group of next queries will be inserted at the index `48` (`offset`), and then a\nsecond group will be inserted at index `120` because of the `frequency` prop configured to `72`.\nFinally, a third group will be inserted at index `192`. Because `maxGroups` is configured to `3`, no\nmore groups will be inserted. Each one of this groups will have up to `6` next queries\n(`maxNextQueriesPerGroup`).\n\n```vue live\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <NextQueriesList :offset=\"48\" :frequency=\"72\" :maxNextQueriesPerGroup=\"6\" :maxGroups=\"3\" />\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { NextQueriesList } from '@empathyco/x-components/next-queries';\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'NextQueriesListDemo',\n components: {\n NextQueriesList,\n ResultsList,\n SearchInput\n }\n };\n</script>\n```\n\n### Customise the layout of the component\n\nThis component will render by default the `id` of each search item, both the injected, and for the\ngroups of next queries generated, but the common case is to integrate it with another layout\ncomponent, for example the `BaseGrid`. To do so, you can use the `default` slot\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <NextQueriesList\n :offset=\"48\"\n :frequency=\"72\"\n :maxNextQueriesPerGroup=\"6\"\n :maxGroups=\"3\"\n #default=\"{ items }\"\n >\n <BaseGrid :items=\"items\" :animation=\"animation\">\n <template #next-queries-group=\"{ item }\">\n <span>NextQueriesGroup: {{ item.queries.join(', ') }}</span>\n </template>\n <template #result=\"{ item }\">\n <span>Result: {{ item.name }}</span>\n </template>\n <template #default=\"{ item }\">\n <span>Default: {{ item }}</span>\n </template>\n </BaseGrid>\n </NextQueriesList>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { NextQueriesList } from '@empathyco/x-components/next-queries';\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n import { BaseGrid } from '@empathyco/x-components';\n\n export default {\n name: 'NextQueriesListDemo',\n components: {\n NextQueriesList,\n ResultsList,\n BaseGrid,\n SearchInput\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"next-queries-list.vue.js","sources":["../../../../../src/x-modules/next-queries/components/next-queries-list.vue"],"sourcesContent":["<template>\n <NoElement>\n <!--\n @slot Next queries list layout.\n @binding {SearchItem[]} items - Next queries groups plus the injected list items to\n render.\n @binding {Vue | string} animation - Animation to animate the elements.\n -->\n <slot v-bind=\"{ items, animation }\">\n <ItemsList :animation=\"animation\" :items=\"items\">\n <template v-for=\"(_, slotName) in $scopedSlots\" v-slot:[slotName]=\"{ item }\">\n <slot :name=\"slotName\" :item=\"item\" />\n </template>\n </ItemsList>\n </slot>\n </NoElement>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { NextQuery } from '@empathyco/x-types';\n import { mixins } from 'vue-class-component';\n import { Component, Prop } from 'vue-property-decorator';\n import { Getter } from '../../../components/decorators/store.decorators';\n import { NoElement } from '../../../components/no-element';\n import { ItemsListInjectionMixin } from '../../../components/items-list-injection.mixin';\n import ItemsList from '../../../components/items-list.vue';\n import { xComponentMixin } from '../../../components/x-component.mixin';\n import { groupItemsBy } from '../../../utils/array';\n import { ListItem } from '../../../utils/types';\n import ResultsList from '../../search/components/results-list.vue';\n import { NextQueriesGroup } from '../types';\n import { nextQueriesXModule } from '../x-module';\n import { XInject } from '../../../components/decorators/injection.decorators';\n import { QUERY_KEY } from '../../../components/decorators/injection.consts';\n\n /**\n * Component that inserts groups of next queries in different positions of the injected search\n * items list, based on the provided configuration.\n *\n * @public\n */\n @Component({\n components: {\n ResultsList,\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(nextQueriesXModule)]\n })\n export default class NextQueriesList extends mixins(ItemsListInjectionMixin) {\n /**\n * Animation component that will be used to animate the next queries groups.\n *\n * @public\n */\n @Prop()\n protected animation?: Vue | string;\n\n /**\n * The first index to insert a group of next queries at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public offset!: number;\n\n /**\n * The items cycle size to keep inserting next queries groups at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public frequency!: number;\n\n /**\n * The maximum amount of next queries to add in a single group.\n *\n * @public\n */\n @Prop({ default: 4 })\n public maxNextQueriesPerGroup!: number;\n\n /**\n * The maximum number of groups to insert into the injected list items list.\n *\n * @public\n */\n @Prop()\n public maxGroups!: number;\n\n /**\n * The state next queries.\n *\n * @internal\n */\n @Getter('nextQueries', 'nextQueries')\n public nextQueries!: NextQuery[];\n\n /**\n * Injected query, updated when the related request(s) have succeeded.\n */\n @XInject(QUERY_KEY)\n public injectedQuery!: string | undefined;\n\n /**\n * The grouped next queries based on the given config.\n *\n * @returns A list of next queries groups.\n * @internal\n */\n protected get nextQueriesGroups(): NextQueriesGroup[] {\n return Object.values(\n groupItemsBy(this.nextQueries, (_, index) =>\n Math.floor(index / this.maxNextQueriesPerGroup)\n )\n )\n .slice(0, this.maxGroups)\n .map(nextQueries => ({\n modelName: 'NextQueriesGroup' as const,\n id: nextQueries.map(nextQuery => nextQuery.query).join(','),\n nextQueries\n }));\n }\n\n /**\n * New list of {@link ListItem}s to render.\n *\n * @returns The new list of {@link ListItem}s with the next queries groups inserted.\n * @internal\n */\n public override get items(): ListItem[] {\n if (!this.injectedListItems) {\n return this.nextQueriesGroups;\n }\n if (this.nextQueriesAreOutdated) {\n return this.injectedListItems;\n }\n return this.nextQueriesGroups.reduce(\n (items, nextQueriesGroup, index) => {\n const targetIndex = this.offset + this.frequency * index;\n if (targetIndex <= items.length) {\n items.splice(targetIndex, 0, nextQueriesGroup);\n }\n return items;\n },\n [...this.injectedListItems]\n );\n }\n\n /**\n * Checks if the next queries are outdated taking into account the injected query.\n *\n * @returns True if the next queries are outdated, false if not.\n * @internal\n */\n protected get nextQueriesAreOutdated(): boolean {\n return (\n !!this.injectedQuery &&\n (this.$x.query.nextQueries !== this.injectedQuery ||\n this.$x.status.nextQueries !== 'success')\n );\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits no events.\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend microservice required\nTo use this component, the <b>QuerySignals</b> microservice must be\nimplemented.\n:::\n<!-- prettier-ignore-end -->\n\nUsually, this component is going to be used together with the `ResultsList` one. Next queries groups\nwill be inserted between the results, guiding users to discover new searches directly from the\nresults list.\n\n```vue live\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <NextQueriesList />\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { NextQueriesList } from '@empathyco/x-components/next-queries';\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'NextQueriesListDemo',\n components: {\n NextQueriesList,\n ResultsList,\n SearchInput\n }\n };\n</script>\n```\n\n### Play with the index that next queries groups are inserted at\n\nThe component allows to customise where are the next queries groups inserted. In the following\nexample, the first group of next queries will be inserted at the index `48` (`offset`), and then a\nsecond group will be inserted at index `120` because of the `frequency` prop configured to `72`.\nFinally, a third group will be inserted at index `192`. Because `maxGroups` is configured to `3`, no\nmore groups will be inserted. Each one of this groups will have up to `6` next queries\n(`maxNextQueriesPerGroup`).\n\n```vue live\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <NextQueriesList :offset=\"48\" :frequency=\"72\" :maxNextQueriesPerGroup=\"6\" :maxGroups=\"3\" />\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { NextQueriesList } from '@empathyco/x-components/next-queries';\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'NextQueriesListDemo',\n components: {\n NextQueriesList,\n ResultsList,\n SearchInput\n }\n };\n</script>\n```\n\n### Customise the layout of the component\n\nThis component will render by default the `id` of each search item, both the injected, and for the\ngroups of next queries generated, but the common case is to integrate it with another layout\ncomponent, for example the `BaseGrid`. To do so, you can use the `default` slot\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <NextQueriesList\n :offset=\"48\"\n :frequency=\"72\"\n :maxNextQueriesPerGroup=\"6\"\n :maxGroups=\"3\"\n #default=\"{ items }\"\n >\n <BaseGrid :items=\"items\" :animation=\"animation\">\n <template #next-queries-group=\"{ item }\">\n <span>NextQueriesGroup: {{ item.queries.join(', ') }}</span>\n </template>\n <template #result=\"{ item }\">\n <span>Result: {{ item.name }}</span>\n </template>\n <template #default=\"{ item }\">\n <span>Default: {{ item }}</span>\n </template>\n </BaseGrid>\n </NextQueriesList>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { NextQueriesList } from '@empathyco/x-components/next-queries';\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n import { BaseGrid } from '@empathyco/x-components';\n\n export default {\n name: 'NextQueriesListDemo',\n components: {\n NextQueriesList,\n ResultsList,\n BaseGrid,\n SearchInput\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -9,6 +9,8 @@ import { xComponentMixin } from '../../../components/x-component.mixin.js';
9
9
  import { groupItemsBy } from '../../../utils/array.js';
10
10
  import __vue_component__ from '../../search/components/results-list.vue.js';
11
11
  import { nextQueriesXModule } from '../x-module.js';
12
+ import { XInject } from '../../../components/decorators/injection.decorators.js';
13
+ import { QUERY_KEY } from '../../../components/decorators/injection.consts.js';
12
14
 
13
15
  /**
14
16
  * Component that inserts groups of next queries in different positions of the injected search
@@ -42,6 +44,9 @@ let NextQueriesList = class NextQueriesList extends mixins(ItemsListInjectionMix
42
44
  if (!this.injectedListItems) {
43
45
  return this.nextQueriesGroups;
44
46
  }
47
+ if (this.nextQueriesAreOutdated) {
48
+ return this.injectedListItems;
49
+ }
45
50
  return this.nextQueriesGroups.reduce((items, nextQueriesGroup, index) => {
46
51
  const targetIndex = this.offset + this.frequency * index;
47
52
  if (targetIndex <= items.length) {
@@ -50,6 +55,17 @@ let NextQueriesList = class NextQueriesList extends mixins(ItemsListInjectionMix
50
55
  return items;
51
56
  }, [...this.injectedListItems]);
52
57
  }
58
+ /**
59
+ * Checks if the next queries are outdated taking into account the injected query.
60
+ *
61
+ * @returns True if the next queries are outdated, false if not.
62
+ * @internal
63
+ */
64
+ get nextQueriesAreOutdated() {
65
+ return (!!this.injectedQuery &&
66
+ (this.$x.query.nextQueries !== this.injectedQuery ||
67
+ this.$x.status.nextQueries !== 'success'));
68
+ }
53
69
  };
54
70
  __decorate([
55
71
  Prop()
@@ -69,6 +85,9 @@ __decorate([
69
85
  __decorate([
70
86
  Getter('nextQueries', 'nextQueries')
71
87
  ], NextQueriesList.prototype, "nextQueries", void 0);
88
+ __decorate([
89
+ XInject(QUERY_KEY)
90
+ ], NextQueriesList.prototype, "injectedQuery", void 0);
72
91
  NextQueriesList = __decorate([
73
92
  Component({
74
93
  components: {
@@ -1 +1 @@
1
- {"version":3,"file":"next-queries-list.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../src/x-modules/next-queries/components/next-queries-list.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Vue from 'vue';\nimport { NextQuery } from '@empathyco/x-types';\nimport { mixins } from 'vue-class-component';\nimport { Component, Prop } from 'vue-property-decorator';\nimport { Getter } from '../../../components/decorators/store.decorators';\nimport { NoElement } from '../../../components/no-element';\nimport { ItemsListInjectionMixin } from '../../../components/items-list-injection.mixin';\nimport ItemsList from '../../../components/items-list.vue';\nimport { xComponentMixin } from '../../../components/x-component.mixin';\nimport { groupItemsBy } from '../../../utils/array';\nimport { ListItem } from '../../../utils/types';\nimport ResultsList from '../../search/components/results-list.vue';\nimport { NextQueriesGroup } from '../types';\nimport { nextQueriesXModule } from '../x-module';\n\n/**\n * Component that inserts groups of next queries in different positions of the injected search\n * items list, based on the provided configuration.\n *\n * @public\n */\n@Component({\n components: {\n ResultsList,\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(nextQueriesXModule)]\n})\nexport default class NextQueriesList extends mixins(ItemsListInjectionMixin) {\n /**\n * Animation component that will be used to animate the next queries groups.\n *\n * @public\n */\n @Prop()\n protected animation?: Vue | string;\n\n /**\n * The first index to insert a group of next queries at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public offset!: number;\n\n /**\n * The items cycle size to keep inserting next queries groups at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public frequency!: number;\n\n /**\n * The maximum amount of next queries to add in a single group.\n *\n * @public\n */\n @Prop({ default: 4 })\n public maxNextQueriesPerGroup!: number;\n\n /**\n * The maximum number of groups to insert into the injected list items list.\n *\n * @public\n */\n @Prop()\n public maxGroups!: number;\n\n /**\n * The state next queries.\n *\n * @internal\n */\n @Getter('nextQueries', 'nextQueries')\n public nextQueries!: NextQuery[];\n\n /**\n * The grouped next queries based on the given config.\n *\n * @returns A list of next queries groups.\n * @internal\n */\n protected get nextQueriesGroups(): NextQueriesGroup[] {\n return Object.values(\n groupItemsBy(this.nextQueries, (_, index) =>\n Math.floor(index / this.maxNextQueriesPerGroup)\n )\n )\n .slice(0, this.maxGroups)\n .map(nextQueries => ({\n modelName: 'NextQueriesGroup' as const,\n id: nextQueries.map(nextQuery => nextQuery.query).join(','),\n nextQueries\n }));\n }\n\n /**\n * New list of {@link ListItem}s to render.\n *\n * @returns The new list of {@link ListItem}s with the next queries groups inserted.\n * @internal\n */\n public override get items(): ListItem[] {\n if (!this.injectedListItems) {\n return this.nextQueriesGroups;\n }\n\n return this.nextQueriesGroups.reduce(\n (items, nextQueriesGroup, index) => {\n const targetIndex = this.offset + this.frequency * index;\n if (targetIndex <= items.length) {\n items.splice(targetIndex, 0, nextQueriesGroup);\n }\n return items;\n },\n [...this.injectedListItems]\n );\n }\n}\n"],"names":["ResultsList","ItemsList"],"mappings":";;;;;;;;;;;;AAkCA;;;;;;AAcA,IAAqB,eAAe,GAApC,MAAqB,eAAgB,SAAQ,MAAM,CAAC,uBAAuB,CAAC;;;;;;;IAuD1E,IAAc,iBAAiB;QAC7B,OAAO,MAAM,CAAC,MAAM,CAClB,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,KACtC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAChD,CACF;aACE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;aACxB,GAAG,CAAC,WAAW,KAAK;YACnB,SAAS,EAAE,kBAA2B;YACtC,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAC3D,WAAW;SACZ,CAAC,CAAC,CAAC;KACP;;;;;;;IAQD,IAAoB,KAAK;QACvB,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAC3B,OAAO,IAAI,CAAC,iBAAiB,CAAC;SAC/B;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAClC,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK;YAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACzD,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE;gBAC/B,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC;aAChD;YACD,OAAO,KAAK,CAAC;SACd,EACD,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAC5B,CAAC;KACH;CACF,CAAA;AApFC;IADC,IAAI,EAAE;kDAC4B;AAQnC;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;+CACC;AAQvB;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;kDACI;AAQ1B;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;+DACkB;AAQvC;IADC,IAAI,EAAE;kDACmB;AAQ1B;IADC,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC;oDACJ;AA/Cd,eAAe;IARnC,SAAS,CAAC;QACT,UAAU,EAAE;yBACVA,iBAAW;YACX,SAAS;uBACTC,mBAAS;SACV;QACD,MAAM,EAAE,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC;KAC9C,CAAC;GACmB,eAAe,CA2FnC;aA3FoB,eAAe;;;;"}
1
+ {"version":3,"file":"next-queries-list.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../src/x-modules/next-queries/components/next-queries-list.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Vue from 'vue';\nimport { NextQuery } from '@empathyco/x-types';\nimport { mixins } from 'vue-class-component';\nimport { Component, Prop } from 'vue-property-decorator';\nimport { Getter } from '../../../components/decorators/store.decorators';\nimport { NoElement } from '../../../components/no-element';\nimport { ItemsListInjectionMixin } from '../../../components/items-list-injection.mixin';\nimport ItemsList from '../../../components/items-list.vue';\nimport { xComponentMixin } from '../../../components/x-component.mixin';\nimport { groupItemsBy } from '../../../utils/array';\nimport { ListItem } from '../../../utils/types';\nimport ResultsList from '../../search/components/results-list.vue';\nimport { NextQueriesGroup } from '../types';\nimport { nextQueriesXModule } from '../x-module';\nimport { XInject } from '../../../components/decorators/injection.decorators';\nimport { QUERY_KEY } from '../../../components/decorators/injection.consts';\n\n/**\n * Component that inserts groups of next queries in different positions of the injected search\n * items list, based on the provided configuration.\n *\n * @public\n */\n@Component({\n components: {\n ResultsList,\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(nextQueriesXModule)]\n})\nexport default class NextQueriesList extends mixins(ItemsListInjectionMixin) {\n /**\n * Animation component that will be used to animate the next queries groups.\n *\n * @public\n */\n @Prop()\n protected animation?: Vue | string;\n\n /**\n * The first index to insert a group of next queries at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public offset!: number;\n\n /**\n * The items cycle size to keep inserting next queries groups at.\n *\n * @public\n */\n @Prop({ default: 24 })\n public frequency!: number;\n\n /**\n * The maximum amount of next queries to add in a single group.\n *\n * @public\n */\n @Prop({ default: 4 })\n public maxNextQueriesPerGroup!: number;\n\n /**\n * The maximum number of groups to insert into the injected list items list.\n *\n * @public\n */\n @Prop()\n public maxGroups!: number;\n\n /**\n * The state next queries.\n *\n * @internal\n */\n @Getter('nextQueries', 'nextQueries')\n public nextQueries!: NextQuery[];\n\n /**\n * Injected query, updated when the related request(s) have succeeded.\n */\n @XInject(QUERY_KEY)\n public injectedQuery!: string | undefined;\n\n /**\n * The grouped next queries based on the given config.\n *\n * @returns A list of next queries groups.\n * @internal\n */\n protected get nextQueriesGroups(): NextQueriesGroup[] {\n return Object.values(\n groupItemsBy(this.nextQueries, (_, index) =>\n Math.floor(index / this.maxNextQueriesPerGroup)\n )\n )\n .slice(0, this.maxGroups)\n .map(nextQueries => ({\n modelName: 'NextQueriesGroup' as const,\n id: nextQueries.map(nextQuery => nextQuery.query).join(','),\n nextQueries\n }));\n }\n\n /**\n * New list of {@link ListItem}s to render.\n *\n * @returns The new list of {@link ListItem}s with the next queries groups inserted.\n * @internal\n */\n public override get items(): ListItem[] {\n if (!this.injectedListItems) {\n return this.nextQueriesGroups;\n }\n if (this.nextQueriesAreOutdated) {\n return this.injectedListItems;\n }\n return this.nextQueriesGroups.reduce(\n (items, nextQueriesGroup, index) => {\n const targetIndex = this.offset + this.frequency * index;\n if (targetIndex <= items.length) {\n items.splice(targetIndex, 0, nextQueriesGroup);\n }\n return items;\n },\n [...this.injectedListItems]\n );\n }\n\n /**\n * Checks if the next queries are outdated taking into account the injected query.\n *\n * @returns True if the next queries are outdated, false if not.\n * @internal\n */\n protected get nextQueriesAreOutdated(): boolean {\n return (\n !!this.injectedQuery &&\n (this.$x.query.nextQueries !== this.injectedQuery ||\n this.$x.status.nextQueries !== 'success')\n );\n }\n}\n"],"names":["ResultsList","ItemsList"],"mappings":";;;;;;;;;;;;;;AAoCA;;;;;;AAcA,IAAqB,eAAe,GAApC,MAAqB,eAAgB,SAAQ,MAAM,CAAC,uBAAuB,CAAC;;;;;;;IA6D1E,IAAc,iBAAiB;QAC7B,OAAO,MAAM,CAAC,MAAM,CAClB,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,KACtC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAChD,CACF;aACE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;aACxB,GAAG,CAAC,WAAW,KAAK;YACnB,SAAS,EAAE,kBAA2B;YACtC,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAC3D,WAAW;SACZ,CAAC,CAAC,CAAC;KACP;;;;;;;IAQD,IAAoB,KAAK;QACvB,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAC3B,OAAO,IAAI,CAAC,iBAAiB,CAAC;SAC/B;QACD,IAAI,IAAI,CAAC,sBAAsB,EAAE;YAC/B,OAAO,IAAI,CAAC,iBAAiB,CAAC;SAC/B;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAClC,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK;YAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACzD,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE;gBAC/B,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC;aAChD;YACD,OAAO,KAAK,CAAC;SACd,EACD,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAC5B,CAAC;KACH;;;;;;;IAQD,IAAc,sBAAsB;QAClC,QACE,CAAC,CAAC,IAAI,CAAC,aAAa;aACnB,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,aAAa;gBAC/C,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,EAC3C;KACH;CACF,CAAA;AA1GC;IADC,IAAI,EAAE;kDAC4B;AAQnC;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;+CACC;AAQvB;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;kDACI;AAQ1B;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;+DACkB;AAQvC;IADC,IAAI,EAAE;kDACmB;AAQ1B;IADC,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC;oDACJ;AAMjC;IADC,OAAO,CAAC,SAAS,CAAC;sDACuB;AArDvB,eAAe;IARnC,SAAS,CAAC;QACT,UAAU,EAAE;yBACVA,iBAAW;YACX,SAAS;uBACTC,mBAAS;SACV;QACD,MAAM,EAAE,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC;KAC9C,CAAC;GACmB,eAAe,CAiHnC;aAjHoB,eAAe;;;;"}
@@ -0,0 +1,94 @@
1
+ import script from './next-query-preview.vue_rollup-plugin-vue_script.vue.js';
2
+ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.mjs';
3
+
4
+ /* script */
5
+ const __vue_script__ = script;
6
+
7
+ /* template */
8
+ var __vue_render__ = function () {
9
+ var _vm = this;
10
+ var _h = _vm.$createElement;
11
+ var _c = _vm._self._c || _h;
12
+ return _vm.suggestionResults
13
+ ? _c(
14
+ "ul",
15
+ {
16
+ staticClass: "x-next-query-preview",
17
+ attrs: { "data-test": "next-query-preview" },
18
+ },
19
+ [
20
+ _vm._t(
21
+ "default",
22
+ function () {
23
+ return _vm._l(_vm.suggestionResults.items, function (result) {
24
+ return _c(
25
+ "li",
26
+ {
27
+ key: result.id,
28
+ staticClass: "x-next-query-preview__item",
29
+ attrs: { "data-test": "next-query-preview-item" },
30
+ },
31
+ [
32
+ _vm._t(
33
+ "result",
34
+ function () {
35
+ return [
36
+ _c(
37
+ "span",
38
+ { attrs: { "data-test": "result-name" } },
39
+ [_vm._v(_vm._s(result.name))]
40
+ ),
41
+ ]
42
+ },
43
+ { result: result }
44
+ ),
45
+ ],
46
+ 2
47
+ )
48
+ })
49
+ },
50
+ {
51
+ suggestion: _vm.suggestion,
52
+ results: _vm.suggestionResults.items,
53
+ totalResults: _vm.suggestionResults.totalResults,
54
+ }
55
+ ),
56
+ ],
57
+ 2
58
+ )
59
+ : _vm._e()
60
+ };
61
+ var __vue_staticRenderFns__ = [];
62
+ __vue_render__._withStripped = true;
63
+
64
+ /* style */
65
+ const __vue_inject_styles__ = undefined;
66
+ /* scoped */
67
+ const __vue_scope_id__ = undefined;
68
+ /* module identifier */
69
+ const __vue_module_identifier__ = undefined;
70
+ /* functional template */
71
+ const __vue_is_functional_template__ = false;
72
+ /* style inject */
73
+
74
+ /* style inject SSR */
75
+
76
+ /* style inject shadow dom */
77
+
78
+
79
+
80
+ const __vue_component__ = /*#__PURE__*/__vue_normalize__(
81
+ { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
82
+ __vue_inject_styles__,
83
+ __vue_script__,
84
+ __vue_scope_id__,
85
+ __vue_is_functional_template__,
86
+ __vue_module_identifier__,
87
+ false,
88
+ undefined,
89
+ undefined,
90
+ undefined
91
+ );
92
+
93
+ export { __vue_component__ as default };
94
+ //# sourceMappingURL=next-query-preview.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-query-preview.vue.js","sources":["../../../../../src/x-modules/next-queries/components/next-query-preview.vue"],"sourcesContent":["<template>\n <ul v-if=\"suggestionResults\" data-test=\"next-query-preview\" class=\"x-next-query-preview\">\n <!--\n @slot Next Query Preview default slot.\n @binding {NextQuery} suggestion - Next Query suggestion data\n @binding {Result[]} results - The results preview of the next query\n @binding {number} totalResults - The total results of the search request\n -->\n <slot\n :suggestion=\"suggestion\"\n :results=\"suggestionResults.items\"\n :totalResults=\"suggestionResults.totalResults\"\n >\n <li\n v-for=\"result in suggestionResults.items\"\n :key=\"result.id\"\n class=\"x-next-query-preview__item\"\n data-test=\"next-query-preview-item\"\n >\n <!--\n @slot Next Query Preview result slot.\n @binding {Result} result - A Next Query Preview result\n -->\n <slot name=\"result\" :result=\"result\">\n <span data-test=\"result-name\">{{ result.name }}</span>\n </slot>\n </li>\n </slot>\n </ul>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { Component, Prop } from 'vue-property-decorator';\n import { NextQuery, PreviewResults } from '@empathyco/x-types';\n import { Dictionary } from '@empathyco/x-utils';\n import { xComponentMixin } from '../../../components/x-component.mixin';\n import { nextQueriesXModule } from '../x-module';\n import { State } from '../../../components/decorators/store.decorators';\n\n /**\n * Retrieves a preview of the results of a next query and exposes them in the default slot,\n * along with the next query and the totalResults of the search request.\n * By default, it renders the names of the results.\n *\n * @public\n */\n @Component({\n mixins: [xComponentMixin(nextQueriesXModule)]\n })\n export default class NextQueryPreview extends Vue {\n /**\n * The next query to retrieve the results preview.\n *\n * @public\n */\n @Prop({\n required: true\n })\n protected suggestion!: NextQuery;\n\n /**\n * The results preview of the next queries mounted.\n * It is a dictionary, indexed by the next query query.\n */\n @State('nextQueries', 'resultsPreview')\n public previewResults!: Dictionary<PreviewResults>;\n\n /**\n * The component emits the NextQueryPreviewMounted event to retrieve the results preview\n * of the next query.\n */\n mounted(): void {\n this.$x.emit('NextQueryPreviewMounted', this.suggestion.query);\n }\n\n /**\n * Gets from the state the results preview of the next query.\n *\n * @returns The results preview of the actual next query.\n */\n public get suggestionResults(): PreviewResults {\n return this.previewResults[this.suggestion.query];\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the `NextQueryPreviewMounted` when it is mounted.\n\n## See it in action\n\nHere you have a basic example of how the NextQueryPreview is rendered. Keep in mind that this\ncomponent is intended to be used overriding its default slot. By default it will only render the\nnames of the results.\n\n```vue live\n<template>\n <NextQueryPreview :suggestion=\"suggestion\" />\n</template>\n\n<script>\n import { NextQueryPreview } from '@empathyco/x-components/next-queries';\n\n export default {\n name: 'NextQueryPreviewDemo',\n components: {\n NextQueryPreview\n },\n data() {\n return {\n suggestion: {\n modelName: 'NextQuery',\n query: 'tshirt',\n facets: []\n }\n };\n }\n };\n</script>\n```\n\n### Play with the default slot\n\nIn this example, the results will be rendered inside a sliding panel.\n\n```vue live\n<template>\n <NextQueryPreview :suggestion=\"suggestion\" #default=\"{ totalResults, results }\">\n <p>Total results: {{ totalResults }}</p>\n <SlidingPanel :resetOnContentChange=\"false\">\n <article\n v-for=\"result in results\"\n :key=\"result.id\"\n class=\"x-result\"\n style=\"max-width: 300px; overflow: hidden\"\n >\n <BaseResultLink :result=\"result\">\n <BaseResultImage :result=\"result\" class=\"x-result__picture\" />\n </BaseResultLink>\n <div class=\"x-result__description\">\n <BaseResultLink :result=\"result\">\n <h1 class=\"x-title3\">{{ result.name }}</h1>\n </BaseResultLink>\n </div>\n </article>\n </SlidingPanel>\n </NextQueryPreview>\n</template>\n\n<script>\n import { NextQueryPreview } from '@empathyco/x-components/next-queries';\n import { SlidingPanel, BaseResultLink, BaseResultImage } from '@empathyco/x-components';\n\n export default {\n name: 'NextQueryPreviewDemoOverridingSlot',\n components: {\n NextQueryPreview,\n SlidingPanel,\n BaseResultLink,\n BaseResultImage\n },\n data() {\n return {\n suggestion: {\n modelName: 'NextQuery',\n query: 'tshirt',\n facets: []\n }\n };\n }\n };\n</script>\n```\n\n### Play with the result slot\n\nThe component exposes a slot to override the result content, without modifying the list.\n\nIn this example, the ID of the results will be rendered along with the name.\n\n```vue\n<template>\n <NextQueryPreview :suggestion=\"suggestion\" #result=\"{ result }\">\n <span>{{ result.id }}</span>\n <span>{{ result.name }}</span>\n </NextQueryPreview>\n</template>\n\n<script>\n import { NextQueryPreview } from '@empathyco/x-components/next-queries';\n\n export default {\n name: 'NextQueryPreviewDemoOverridingResultSlot',\n components: {\n NextQueryPreview\n },\n data() {\n return {\n suggestion: {\n modelName: 'NextQuery',\n query: 'tshirt',\n facets: []\n }\n };\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,48 @@
1
+ import { __decorate } from 'tslib';
2
+ import Vue from 'vue';
3
+ import { Prop, Component } from 'vue-property-decorator';
4
+ import { xComponentMixin } from '../../../components/x-component.mixin.js';
5
+ import { nextQueriesXModule } from '../x-module.js';
6
+ import { State } from '../../../components/decorators/store.decorators.js';
7
+
8
+ /**
9
+ * Retrieves a preview of the results of a next query and exposes them in the default slot,
10
+ * along with the next query and the totalResults of the search request.
11
+ * By default, it renders the names of the results.
12
+ *
13
+ * @public
14
+ */
15
+ let NextQueryPreview = class NextQueryPreview extends Vue {
16
+ /**
17
+ * The component emits the NextQueryPreviewMounted event to retrieve the results preview
18
+ * of the next query.
19
+ */
20
+ mounted() {
21
+ this.$x.emit('NextQueryPreviewMounted', this.suggestion.query);
22
+ }
23
+ /**
24
+ * Gets from the state the results preview of the next query.
25
+ *
26
+ * @returns The results preview of the actual next query.
27
+ */
28
+ get suggestionResults() {
29
+ return this.previewResults[this.suggestion.query];
30
+ }
31
+ };
32
+ __decorate([
33
+ Prop({
34
+ required: true
35
+ })
36
+ ], NextQueryPreview.prototype, "suggestion", void 0);
37
+ __decorate([
38
+ State('nextQueries', 'resultsPreview')
39
+ ], NextQueryPreview.prototype, "previewResults", void 0);
40
+ NextQueryPreview = __decorate([
41
+ Component({
42
+ mixins: [xComponentMixin(nextQueriesXModule)]
43
+ })
44
+ ], NextQueryPreview);
45
+ var script = NextQueryPreview;
46
+
47
+ export { script as default };
48
+ //# sourceMappingURL=next-query-preview.vue_rollup-plugin-vue_script.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-query-preview.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../src/x-modules/next-queries/components/next-query-preview.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Vue from 'vue';\nimport { Component, Prop } from 'vue-property-decorator';\nimport { NextQuery, PreviewResults } from '@empathyco/x-types';\nimport { Dictionary } from '@empathyco/x-utils';\nimport { xComponentMixin } from '../../../components/x-component.mixin';\nimport { nextQueriesXModule } from '../x-module';\nimport { State } from '../../../components/decorators/store.decorators';\n\n/**\n * Retrieves a preview of the results of a next query and exposes them in the default slot,\n * along with the next query and the totalResults of the search request.\n * By default, it renders the names of the results.\n *\n * @public\n */\n@Component({\n mixins: [xComponentMixin(nextQueriesXModule)]\n})\nexport default class NextQueryPreview extends Vue {\n /**\n * The next query to retrieve the results preview.\n *\n * @public\n */\n @Prop({\n required: true\n })\n protected suggestion!: NextQuery;\n\n /**\n * The results preview of the next queries mounted.\n * It is a dictionary, indexed by the next query query.\n */\n @State('nextQueries', 'resultsPreview')\n public previewResults!: Dictionary<PreviewResults>;\n\n /**\n * The component emits the NextQueryPreviewMounted event to retrieve the results preview\n * of the next query.\n */\n mounted(): void {\n this.$x.emit('NextQueryPreviewMounted', this.suggestion.query);\n }\n\n /**\n * Gets from the state the results preview of the next query.\n *\n * @returns The results preview of the actual next query.\n */\n public get suggestionResults(): PreviewResults {\n return this.previewResults[this.suggestion.query];\n }\n}\n"],"names":[],"mappings":";;;;;;;AAwCA;;;;;;;AAUA,IAAqB,gBAAgB,GAArC,MAAqB,gBAAiB,SAAQ,GAAG;;;;;IAsB/C,OAAO;QACL,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;KAChE;;;;;;IAOD,IAAW,iBAAiB;QAC1B,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;KACnD;CACF,CAAA;AAzBC;IAHC,IAAI,CAAC;QACJ,QAAQ,EAAE,IAAI;KACf,CAAC;oDAC+B;AAOjC;IADC,KAAK,CAAC,aAAa,EAAE,gBAAgB,CAAC;wDACY;AAhBhC,gBAAgB;IAHpC,SAAS,CAAC;QACT,MAAM,EAAE,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC;KAC9C,CAAC;GACmB,gBAAgB,CAkCpC;aAlCoB,gBAAgB;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-and-save-next-query-preview.action.js","sources":["../../../../../../src/x-modules/next-queries/store/actions/fetch-and-save-next-query-preview.action.ts"],"sourcesContent":["import { NextQueriesXStoreModule } from '../types';\n\n// eslint-disable-next-line max-len\nexport const fetchAndSaveNextQueryPreview: NextQueriesXStoreModule['actions']['fetchAndSaveNextQueryPreview'] =\n ({ dispatch, commit }, query): Promise<void> => {\n return dispatch('fetchNextQueryPreview', query)\n .then(response => {\n if (response) {\n commit('setResultsPreview', {\n [query]: {\n query,\n totalResults: response.totalResults,\n items: response.results\n }\n });\n }\n })\n .catch(error => {\n // eslint-disable-next-line no-console\n console.error(error);\n });\n };\n"],"names":[],"mappings":"AAEA;MACa,4BAA4B,GACvC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK;IAC1B,OAAO,QAAQ,CAAC,uBAAuB,EAAE,KAAK,CAAC;SAC5C,IAAI,CAAC,QAAQ;QACZ,IAAI,QAAQ,EAAE;YACZ,MAAM,CAAC,mBAAmB,EAAE;gBAC1B,CAAC,KAAK,GAAG;oBACP,KAAK;oBACL,YAAY,EAAE,QAAQ,CAAC,YAAY;oBACnC,KAAK,EAAE,QAAQ,CAAC,OAAO;iBACxB;aACF,CAAC,CAAC;SACJ;KACF,CAAC;SACD,KAAK,CAAC,KAAK;;QAEV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;KACtB,CAAC,CAAC;AACP;;;;"}
1
+ {"version":3,"file":"fetch-and-save-next-query-preview.action.js","sources":["../../../../../../src/x-modules/next-queries/store/actions/fetch-and-save-next-query-preview.action.ts"],"sourcesContent":["import { NextQueriesXStoreModule } from '../types';\n\n// eslint-disable-next-line max-len\nexport const fetchAndSaveNextQueryPreview: NextQueriesXStoreModule['actions']['fetchAndSaveNextQueryPreview'] =\n ({ dispatch, commit }, query) => {\n return dispatch('fetchNextQueryPreview', query)\n .then(response => {\n if (response) {\n commit('setResultsPreview', {\n [query]: {\n query,\n totalResults: response.totalResults,\n items: response.results\n }\n });\n }\n })\n .catch(error => {\n // eslint-disable-next-line no-console\n console.error(error);\n });\n };\n"],"names":[],"mappings":"AAEA;MACa,4BAA4B,GACvC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK;IAC1B,OAAO,QAAQ,CAAC,uBAAuB,EAAE,KAAK,CAAC;SAC5C,IAAI,CAAC,QAAQ;QACZ,IAAI,QAAQ,EAAE;YACZ,MAAM,CAAC,mBAAmB,EAAE;gBAC1B,CAAC,KAAK,GAAG;oBACP,KAAK;oBACL,YAAY,EAAE,QAAQ,CAAC,YAAY;oBACnC,KAAK,EAAE,QAAQ,CAAC,OAAO;iBACxB;aACF,CAAC,CAAC;SACJ;KACF,CAAC;SACD,KAAK,CAAC,KAAK;;QAEV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;KACtB,CAAC,CAAC;AACP;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"results-list.vue.js","sources":["../../../../../src/x-modules/search/components/results-list.vue"],"sourcesContent":["<template>\n <NoElement>\n <!--\n @slot Customize ResultsList.\n @binding {Result[]} items - Results to render.\n @binding {Vue | string} animation - Animation to animate the elements.\n -->\n <slot v-bind=\"{ items, animation }\">\n <ItemsList :animation=\"animation\" :items=\"items\">\n <template v-for=\"(_, slotName) in $scopedSlots\" v-slot:[slotName]=\"{ item }\">\n <slot :name=\"slotName\" :item=\"item\" />\n </template>\n </ItemsList>\n </slot>\n </NoElement>\n</template>\n\n<script lang=\"ts\">\n import { Result } from '@empathyco/x-types';\n import Vue from 'vue';\n import { Component, Prop } from 'vue-property-decorator';\n import { LIST_ITEMS_KEY } from '../../../components/decorators/injection.consts';\n import { XProvide } from '../../../components/decorators/injection.decorators';\n import { State } from '../../../components/decorators/store.decorators';\n import { NoElement } from '../../../components/no-element';\n import ItemsList from '../../../components/items-list.vue';\n import { xComponentMixin } from '../../../components/x-component.mixin';\n import { InfiniteScroll } from '../../../directives/infinite-scroll/infinite-scroll.types';\n import { searchXModule } from '../x-module';\n\n /**\n * It renders a {@link ItemsList} list with the results from {@link SearchState.results} by\n * default.\n *\n * The component provides a default slot which wraps the whole component with the `results` bound.\n *\n * It also provides the slot result to customize the item, which is within the default slot, with\n * the result bound.\n *\n * @public\n */\n @Component({\n components: {\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(searchXModule)]\n })\n export default class ResultsList extends Vue implements InfiniteScroll {\n /**\n * The results to render from the state.\n *\n * @remarks The results list are provided with `items` key. It can be\n * concatenated with list items from components such as `BannersList`, `PromotedsList`,\n * `BaseGrid` or any component that injects the list.\n *\n * @public\n */\n @XProvide(LIST_ITEMS_KEY)\n @State('search', 'results')\n public items!: Result[];\n\n /**\n * Animation component that will be used to animate the results.\n *\n * @public\n */\n @Prop({ default: 'ul' })\n protected animation!: Vue | string;\n\n /**\n * It emits an {@link SearchXEvents.UserReachedResultsListEnd} event.\n *\n * @internal\n */\n onInfiniteScrollEnd(): void {\n this.$x.emit('UserReachedResultsListEnd');\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend service required\nTo use this component, the Search service must be implemented.\n:::\n<!-- prettier-ignore-end -->\n\nHere you have a basic example of how the ResultsList is rendered.\n\n_Type any term in the input field to try it out!_\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList />\n </div>\n</template>\n\n<script>\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList\n }\n };\n</script>\n```\n\n### Play with the animation\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList :animation=\"fadeAndSlide\" />\n </div>\n</template>\n\n<script>\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n import { FadeAndSlide } from '@empathyco/x-components/animations';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList\n },\n data() {\n return {\n fadeAndSlide: FadeAndSlide\n };\n }\n };\n</script>\n```\n\n### Overriding default content\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList #default=\"{ items, animation }\">\n <BaseGrid :items=\"items\" :animation=\"animation\">\n <template #result=\"{ item }\">\n <span>Result: {{ item.name }}</span>\n </template>\n <template #default=\"{ item }\">\n <span>Default: {{ item }}</span>\n </template>\n </BaseGrid>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n import { BaseGrid } from '@empathyco/x-components';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList,\n BaseGrid\n }\n };\n</script>\n```\n\n### Overriding result content\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList #result=\"{ item }\">\n <span class=\"result\">\n {{ item.name }}\n </span>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { SearchInput, ResultsList } from '@empathyco/x-components/search';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList\n }\n };\n</script>\n```\n\n### Data injection\n\nStarting with the `ResultsList` component as root element, you can concat the list of list items\nusing `BannersList`, `PromotedsList`, `BaseGrid` or any component that injects the `listItems`\nvalue.\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <BannersList>\n <PromotedsList>\n <template #result=\"{ item }\">Result: {{ item.id }}</template>\n <template #banner=\"{ item }\">Banner: {{ item.id }}</template>\n <template #promoted=\"{ item }\">Promoted: {{ item.id }}</template>\n </PromotedsList>\n </BannersList>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { ResultsList, BannersList, PromotedsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList,\n BannersList,\n PromotedsList\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"results-list.vue.js","sources":["../../../../../src/x-modules/search/components/results-list.vue"],"sourcesContent":["<template>\n <NoElement>\n <!--\n @slot Customize ResultsList.\n @binding {Result[]} items - Results to render.\n @binding {Vue | string} animation - Animation to animate the elements.\n -->\n <slot v-bind=\"{ items, animation }\">\n <ItemsList :animation=\"animation\" :items=\"items\">\n <template v-for=\"(_, slotName) in $scopedSlots\" v-slot:[slotName]=\"{ item }\">\n <slot :name=\"slotName\" :item=\"item\" />\n </template>\n </ItemsList>\n </slot>\n </NoElement>\n</template>\n\n<script lang=\"ts\">\n import { Result } from '@empathyco/x-types';\n import Vue from 'vue';\n import { Component, Prop, Watch } from 'vue-property-decorator';\n import { LIST_ITEMS_KEY, QUERY_KEY } from '../../../components/decorators/injection.consts';\n import { XProvide } from '../../../components/decorators/injection.decorators';\n import { State } from '../../../components/decorators/store.decorators';\n import { NoElement } from '../../../components/no-element';\n import ItemsList from '../../../components/items-list.vue';\n import { xComponentMixin } from '../../../components/x-component.mixin';\n import { InfiniteScroll } from '../../../directives/infinite-scroll/infinite-scroll.types';\n import { searchXModule } from '../x-module';\n import { RequestStatus } from '../../../store/utils/status-store.utils';\n\n /**\n * It renders a {@link ItemsList} list with the results from {@link SearchState.results} by\n * default.\n *\n * The component provides a default slot which wraps the whole component with the `results` bound.\n *\n * It also provides the slot result to customize the item, which is within the default slot, with\n * the result bound.\n *\n * @public\n */\n @Component({\n components: {\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(searchXModule)]\n })\n export default class ResultsList extends Vue implements InfiniteScroll {\n /**\n * The results to render from the state.\n *\n * @remarks The results list are provided with `items` key. It can be\n * concatenated with list items from components such as `BannersList`, `PromotedsList`,\n * `BaseGrid` or any component that injects the list.\n *\n * @public\n */\n @XProvide(LIST_ITEMS_KEY)\n @State('search', 'results')\n public items!: Result[];\n\n /**\n * It provides the search query.\n * This query is updated only when the search request has succeeded.\n */\n @XProvide(QUERY_KEY)\n public providedQuery = '';\n\n /**\n * The status of the search request, taken from the state.\n */\n @State('search', 'status')\n public searchStatus!: RequestStatus;\n\n /**\n * The query of the search request, taken from the state.\n */\n @State('search', 'query')\n public searchQuery!: string;\n\n /**\n * Animation component that will be used to animate the results.\n *\n * @public\n */\n @Prop({ default: 'ul' })\n protected animation!: Vue | string;\n\n /**\n * Updates the query to be provided to the child components\n * when the search request has succeeded.\n *\n * @param status - The status of the search request.\n */\n @Watch('searchStatus')\n updateQuery(status: RequestStatus): void {\n if (status === 'success') {\n this.providedQuery = this.searchQuery;\n }\n }\n\n /**\n * It emits an {@link SearchXEvents.UserReachedResultsListEnd} event.\n *\n * @internal\n */\n onInfiniteScrollEnd(): void {\n this.$x.emit('UserReachedResultsListEnd');\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend service required\nTo use this component, the Search service must be implemented.\n:::\n<!-- prettier-ignore-end -->\n\nHere you have a basic example of how the ResultsList is rendered.\n\n_Type any term in the input field to try it out!_\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList />\n </div>\n</template>\n\n<script>\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList\n }\n };\n</script>\n```\n\n### Play with the animation\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList :animation=\"fadeAndSlide\" />\n </div>\n</template>\n\n<script>\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n import { FadeAndSlide } from '@empathyco/x-components/animations';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList\n },\n data() {\n return {\n fadeAndSlide: FadeAndSlide\n };\n }\n };\n</script>\n```\n\n### Overriding default content\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList #default=\"{ items, animation }\">\n <BaseGrid :items=\"items\" :animation=\"animation\">\n <template #result=\"{ item }\">\n <span>Result: {{ item.name }}</span>\n </template>\n <template #default=\"{ item }\">\n <span>Default: {{ item }}</span>\n </template>\n </BaseGrid>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { ResultsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n import { BaseGrid } from '@empathyco/x-components';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList,\n BaseGrid\n }\n };\n</script>\n```\n\n### Overriding result content\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList #result=\"{ item }\">\n <span class=\"result\">\n {{ item.name }}\n </span>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { SearchInput, ResultsList } from '@empathyco/x-components/search';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList\n }\n };\n</script>\n```\n\n### Data injection\n\nStarting with the `ResultsList` component as root element, you can concat the list of list items\nusing `BannersList`, `PromotedsList`, `BaseGrid` or any component that injects the `listItems`\nvalue.\n\n```vue\n<template>\n <div>\n <SearchInput />\n <ResultsList>\n <BannersList>\n <PromotedsList>\n <template #result=\"{ item }\">Result: {{ item.id }}</template>\n <template #banner=\"{ item }\">Banner: {{ item.id }}</template>\n <template #promoted=\"{ item }\">Promoted: {{ item.id }}</template>\n </PromotedsList>\n </BannersList>\n </ResultsList>\n </div>\n</template>\n\n<script>\n import { ResultsList, BannersList, PromotedsList } from '@empathyco/x-components/search';\n import { SearchInput } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'ResultsListDemo',\n components: {\n SearchInput,\n ResultsList,\n BannersList,\n PromotedsList\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import Vue from 'vue';
3
- import { Prop, Component } from 'vue-property-decorator';
4
- import { LIST_ITEMS_KEY } from '../../../components/decorators/injection.consts.js';
3
+ import { Prop, Watch, Component } from 'vue-property-decorator';
4
+ import { LIST_ITEMS_KEY, QUERY_KEY } from '../../../components/decorators/injection.consts.js';
5
5
  import { XProvide } from '../../../components/decorators/injection.decorators.js';
6
6
  import { State } from '../../../components/decorators/store.decorators.js';
7
7
  import { NoElement } from '../../../components/no-element.js';
@@ -21,6 +21,25 @@ import { searchXModule } from '../x-module.js';
21
21
  * @public
22
22
  */
23
23
  let ResultsList = class ResultsList extends Vue {
24
+ constructor() {
25
+ super(...arguments);
26
+ /**
27
+ * It provides the search query.
28
+ * This query is updated only when the search request has succeeded.
29
+ */
30
+ this.providedQuery = '';
31
+ }
32
+ /**
33
+ * Updates the query to be provided to the child components
34
+ * when the search request has succeeded.
35
+ *
36
+ * @param status - The status of the search request.
37
+ */
38
+ updateQuery(status) {
39
+ if (status === 'success') {
40
+ this.providedQuery = this.searchQuery;
41
+ }
42
+ }
24
43
  /**
25
44
  * It emits an {@link SearchXEvents.UserReachedResultsListEnd} event.
26
45
  *
@@ -34,9 +53,21 @@ __decorate([
34
53
  XProvide(LIST_ITEMS_KEY),
35
54
  State('search', 'results')
36
55
  ], ResultsList.prototype, "items", void 0);
56
+ __decorate([
57
+ XProvide(QUERY_KEY)
58
+ ], ResultsList.prototype, "providedQuery", void 0);
59
+ __decorate([
60
+ State('search', 'status')
61
+ ], ResultsList.prototype, "searchStatus", void 0);
62
+ __decorate([
63
+ State('search', 'query')
64
+ ], ResultsList.prototype, "searchQuery", void 0);
37
65
  __decorate([
38
66
  Prop({ default: 'ul' })
39
67
  ], ResultsList.prototype, "animation", void 0);
68
+ __decorate([
69
+ Watch('searchStatus')
70
+ ], ResultsList.prototype, "updateQuery", null);
40
71
  ResultsList = __decorate([
41
72
  Component({
42
73
  components: {
@@ -1 +1 @@
1
- {"version":3,"file":"results-list.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../src/x-modules/search/components/results-list.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { Result } from '@empathyco/x-types';\nimport Vue from 'vue';\nimport { Component, Prop } from 'vue-property-decorator';\nimport { LIST_ITEMS_KEY } from '../../../components/decorators/injection.consts';\nimport { XProvide } from '../../../components/decorators/injection.decorators';\nimport { State } from '../../../components/decorators/store.decorators';\nimport { NoElement } from '../../../components/no-element';\nimport ItemsList from '../../../components/items-list.vue';\nimport { xComponentMixin } from '../../../components/x-component.mixin';\nimport { InfiniteScroll } from '../../../directives/infinite-scroll/infinite-scroll.types';\nimport { searchXModule } from '../x-module';\n\n/**\n * It renders a {@link ItemsList} list with the results from {@link SearchState.results} by\n * default.\n *\n * The component provides a default slot which wraps the whole component with the `results` bound.\n *\n * It also provides the slot result to customize the item, which is within the default slot, with\n * the result bound.\n *\n * @public\n */\n@Component({\n components: {\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(searchXModule)]\n})\nexport default class ResultsList extends Vue implements InfiniteScroll {\n /**\n * The results to render from the state.\n *\n * @remarks The results list are provided with `items` key. It can be\n * concatenated with list items from components such as `BannersList`, `PromotedsList`,\n * `BaseGrid` or any component that injects the list.\n *\n * @public\n */\n @XProvide(LIST_ITEMS_KEY)\n @State('search', 'results')\n public items!: Result[];\n\n /**\n * Animation component that will be used to animate the results.\n *\n * @public\n */\n @Prop({ default: 'ul' })\n protected animation!: Vue | string;\n\n /**\n * It emits an {@link SearchXEvents.UserReachedResultsListEnd} event.\n *\n * @internal\n */\n onInfiniteScrollEnd(): void {\n this.$x.emit('UserReachedResultsListEnd');\n }\n}\n"],"names":["ItemsList"],"mappings":";;;;;;;;;;;AA8BA;;;;;;;;;;;AAkBA,IAAqB,WAAW,GAAhC,MAAqB,WAAY,SAAQ,GAAG;;;;;;IA2B1C,mBAAmB;QACjB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;KAC3C;CACF,CAAA;AAlBC;IAFC,QAAQ,CAAC,cAAc,CAAC;IACxB,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC;0CACH;AAQxB;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CACW;AApBhB,WAAW;IAP/B,SAAS,CAAC;QACT,UAAU,EAAE;YACV,SAAS;uBACTA,iBAAS;SACV;QACD,MAAM,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;KACzC,CAAC;GACmB,WAAW,CA8B/B;aA9BoB,WAAW;;;;"}
1
+ {"version":3,"file":"results-list.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../src/x-modules/search/components/results-list.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { Result } from '@empathyco/x-types';\nimport Vue from 'vue';\nimport { Component, Prop, Watch } from 'vue-property-decorator';\nimport { LIST_ITEMS_KEY, QUERY_KEY } from '../../../components/decorators/injection.consts';\nimport { XProvide } from '../../../components/decorators/injection.decorators';\nimport { State } from '../../../components/decorators/store.decorators';\nimport { NoElement } from '../../../components/no-element';\nimport ItemsList from '../../../components/items-list.vue';\nimport { xComponentMixin } from '../../../components/x-component.mixin';\nimport { InfiniteScroll } from '../../../directives/infinite-scroll/infinite-scroll.types';\nimport { searchXModule } from '../x-module';\nimport { RequestStatus } from '../../../store/utils/status-store.utils';\n\n/**\n * It renders a {@link ItemsList} list with the results from {@link SearchState.results} by\n * default.\n *\n * The component provides a default slot which wraps the whole component with the `results` bound.\n *\n * It also provides the slot result to customize the item, which is within the default slot, with\n * the result bound.\n *\n * @public\n */\n@Component({\n components: {\n NoElement,\n ItemsList\n },\n mixins: [xComponentMixin(searchXModule)]\n})\nexport default class ResultsList extends Vue implements InfiniteScroll {\n /**\n * The results to render from the state.\n *\n * @remarks The results list are provided with `items` key. It can be\n * concatenated with list items from components such as `BannersList`, `PromotedsList`,\n * `BaseGrid` or any component that injects the list.\n *\n * @public\n */\n @XProvide(LIST_ITEMS_KEY)\n @State('search', 'results')\n public items!: Result[];\n\n /**\n * It provides the search query.\n * This query is updated only when the search request has succeeded.\n */\n @XProvide(QUERY_KEY)\n public providedQuery = '';\n\n /**\n * The status of the search request, taken from the state.\n */\n @State('search', 'status')\n public searchStatus!: RequestStatus;\n\n /**\n * The query of the search request, taken from the state.\n */\n @State('search', 'query')\n public searchQuery!: string;\n\n /**\n * Animation component that will be used to animate the results.\n *\n * @public\n */\n @Prop({ default: 'ul' })\n protected animation!: Vue | string;\n\n /**\n * Updates the query to be provided to the child components\n * when the search request has succeeded.\n *\n * @param status - The status of the search request.\n */\n @Watch('searchStatus')\n updateQuery(status: RequestStatus): void {\n if (status === 'success') {\n this.providedQuery = this.searchQuery;\n }\n }\n\n /**\n * It emits an {@link SearchXEvents.UserReachedResultsListEnd} event.\n *\n * @internal\n */\n onInfiniteScrollEnd(): void {\n this.$x.emit('UserReachedResultsListEnd');\n }\n}\n"],"names":["ItemsList"],"mappings":";;;;;;;;;;;AA+BA;;;;;;;;;;;AAkBA,IAAqB,WAAW,GAAhC,MAAqB,WAAY,SAAQ,GAAG;IAA5C;;;;;;QAmBS,kBAAa,GAAG,EAAE,CAAC;KA2C3B;;;;;;;IAdC,WAAW,CAAC,MAAqB;QAC/B,IAAI,MAAM,KAAK,SAAS,EAAE;YACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC;SACvC;KACF;;;;;;IAOD,mBAAmB;QACjB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;KAC3C;CACF,CAAA;AAlDC;IAFC,QAAQ,CAAC,cAAc,CAAC;IACxB,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC;0CACH;AAOxB;IADC,QAAQ,CAAC,SAAS,CAAC;kDACM;AAM1B;IADC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC;iDACU;AAMpC;IADC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC;gDACG;AAQ5B;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CACW;AASnC;IADC,KAAK,CAAC,cAAc,CAAC;8CAKrB;AApDkB,WAAW;IAP/B,SAAS,CAAC;QACT,UAAU,EAAE;YACV,SAAS;uBACTA,iBAAS;SACV;QACD,MAAM,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;KACzC,CAAC;GACmB,WAAW,CA8D/B;aA9DoB,WAAW;;;;"}