@empathyco/x-components 3.0.0-alpha.144 → 3.0.0-alpha.147

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 (86) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/design-system/default-theme.css +28 -28
  3. package/design-system/full-theme.css +53 -54
  4. package/docs/API-reference/api/x-adapter-platform.md +0 -1
  5. package/docs/API-reference/api/x-adapter-platform.searchresponsemapper.md +1 -11
  6. package/docs/API-reference/api/x-components.facetsmutations.md +1 -1
  7. package/docs/API-reference/api/x-components.facetsmutations.mutatefilter.md +24 -0
  8. package/docs/API-reference/api/x-components.flathierarchicalfilters.md +26 -0
  9. package/docs/API-reference/api/x-components.md +2 -0
  10. package/docs/API-reference/api/x-components.mutatefilterpayload.filter.md +13 -0
  11. package/docs/API-reference/api/x-components.mutatefilterpayload.md +21 -0
  12. package/docs/API-reference/api/x-components.mutatefilterpayload.newfilterstate.md +13 -0
  13. package/docs/API-reference/api/x-types.hierarchicalfilter.children.md +2 -2
  14. package/docs/API-reference/api/x-types.hierarchicalfilter.md +2 -2
  15. package/docs/API-reference/api/x-types.hierarchicalfilter.parentid.md +1 -1
  16. package/docs/build-search-ui/web-archetype-development-guide.md +10 -7
  17. package/docs/build-search-ui/web-archetype-integration-guide.md +15 -14
  18. package/docs/build-search-ui/web-x-components-development-guide.md +5 -4
  19. package/docs/experience-search-&-discovery/README.md +119 -0
  20. package/docs/experience-search-&-discovery/empathize.md +102 -0
  21. package/docs/experience-search-&-discovery/facets-and-filters.md +138 -0
  22. package/docs/experience-search-&-discovery/history-queries.md +56 -0
  23. package/docs/experience-search-&-discovery/id-results.md +40 -0
  24. package/docs/experience-search-&-discovery/next-queries.md +52 -0
  25. package/docs/experience-search-&-discovery/popular-searches.md +32 -0
  26. package/docs/experience-search-&-discovery/product-results-ui.md +68 -0
  27. package/docs/experience-search-&-discovery/query-suggestions.md +32 -0
  28. package/docs/experience-search-&-discovery/recommendations.md +32 -0
  29. package/docs/experience-search-&-discovery/related-tags.md +41 -0
  30. package/docs/experience-search-&-discovery/search-box.md +81 -0
  31. package/docs/experience-search-&-discovery/serp-ui.md +109 -0
  32. package/docs/experience-search-&-discovery/web-local-storage.md +25 -0
  33. package/facets/index.js +1 -1
  34. package/js/index.js +1 -1
  35. package/js/x-modules/facets/components/facets/facets-provider.vue.js +2 -2
  36. package/js/x-modules/facets/components/facets/facets-provider.vue.js.map +1 -1
  37. package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js +7 -2
  38. package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  39. package/js/x-modules/facets/components/filters/hierarchical-filter.vue.js.map +1 -1
  40. package/js/x-modules/facets/components/filters/hierarchical-filter.vue_rollup-plugin-vue_script.vue.js +2 -130
  41. package/js/x-modules/facets/components/filters/hierarchical-filter.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  42. package/js/x-modules/facets/entities/editable-number-range-filter.entity.js +11 -10
  43. package/js/x-modules/facets/entities/editable-number-range-filter.entity.js.map +1 -1
  44. package/js/x-modules/facets/entities/hierarchical-filter.entity.js +9 -11
  45. package/js/x-modules/facets/entities/hierarchical-filter.entity.js.map +1 -1
  46. package/js/x-modules/facets/entities/number-range-filter.entity.js +2 -2
  47. package/js/x-modules/facets/entities/number-range-filter.entity.js.map +1 -1
  48. package/js/x-modules/facets/entities/raw-filter.entity.js +1 -1
  49. package/js/x-modules/facets/entities/raw-filter.entity.js.map +1 -1
  50. package/js/x-modules/facets/entities/simple-filter.entity.js +2 -2
  51. package/js/x-modules/facets/entities/simple-filter.entity.js.map +1 -1
  52. package/js/x-modules/facets/entities/single-select.modifier.js +1 -1
  53. package/js/x-modules/facets/entities/single-select.modifier.js.map +1 -1
  54. package/js/x-modules/facets/service/facets.service.js +18 -2
  55. package/js/x-modules/facets/service/facets.service.js.map +1 -1
  56. package/js/x-modules/facets/store/module.js +4 -3
  57. package/js/x-modules/facets/store/module.js.map +1 -1
  58. package/js/x-modules/facets/utils.js +16 -1
  59. package/js/x-modules/facets/utils.js.map +1 -1
  60. package/js/x-modules/search-box/components/search-input.vue.js +54 -45
  61. package/js/x-modules/search-box/components/search-input.vue.js.map +1 -1
  62. package/js/x-modules/search-box/components/search-input.vue_rollup-plugin-vue_script.vue.js.map +1 -1
  63. package/package.json +4 -4
  64. package/report/x-adapter-platform.api.json +5 -133
  65. package/report/x-components.api.json +181 -45
  66. package/report/x-components.api.md +14 -5
  67. package/report/x-types.api.json +5 -5
  68. package/types/x-modules/facets/components/facets/facets-provider.vue.d.ts.map +1 -1
  69. package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts +0 -6
  70. package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts.map +1 -1
  71. package/types/x-modules/facets/entities/editable-number-range-filter.entity.d.ts +1 -1
  72. package/types/x-modules/facets/entities/editable-number-range-filter.entity.d.ts.map +1 -1
  73. package/types/x-modules/facets/entities/hierarchical-filter.entity.d.ts +2 -1
  74. package/types/x-modules/facets/entities/hierarchical-filter.entity.d.ts.map +1 -1
  75. package/types/x-modules/facets/entities/single-select.modifier.d.ts.map +1 -1
  76. package/types/x-modules/facets/service/facets.service.d.ts +13 -0
  77. package/types/x-modules/facets/service/facets.service.d.ts.map +1 -1
  78. package/types/x-modules/facets/store/module.d.ts.map +1 -1
  79. package/types/x-modules/facets/store/types.d.ts +22 -6
  80. package/types/x-modules/facets/store/types.d.ts.map +1 -1
  81. package/types/x-modules/facets/utils.d.ts +11 -0
  82. package/types/x-modules/facets/utils.d.ts.map +1 -1
  83. package/types/x-modules/search-box/components/search-input.vue.d.ts.map +1 -1
  84. package/docs/API-reference/api/x-adapter-platform.searchresponsefacetsmapper.md +0 -27
  85. package/docs/API-reference/api/x-components.facetsmutations.setfilter.md +0 -24
  86. package/docs/functional-doc/web-local-storage.md +0 -22
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Recommendations UI
3
+ ---
4
+
5
+ # Recommendations UI
6
+
7
+ The Recommendations UI component shows the most clicked products on the SERP, based on shopper
8
+ interaction within a defined period. They help your shoppers to explore your product catalogue,
9
+ guiding them to specific products without the need to launch any queries.
10
+
11
+ <img :src="$withBase('/assets/media/xcomponents_func_recommendations.gif')" alt="Recommendations]">
12
+
13
+ :::warning Recommendations are generated using collective shopper behavior, generating a feed with
14
+ the most clicked products. For a correct performance, make sure that your current search service
15
+ supports this type of feature. :::
16
+
17
+ ::: interact Can't quite capture the concept? Learn more about
18
+ [Recommendations](../search/recommendations-overview.md). :::
19
+
20
+ ## Tailor the web experience
21
+
22
+ - Configure the position and place it wherever you prefer, although they usually appear on the
23
+ results page.
24
+ - Show as many recommendations as you want.
25
+ - Animate the display of the component at your ease.
26
+ - Customize content. Show whatever you need: text, images, icons.
27
+ - Extend the performance with results-related components.
28
+
29
+ ::: interact Want to know more? Learn how to [configure](/develop-empathy-platform/ui-reference/)
30
+ your web experience. :::
31
+
32
+ [//]: # 'TIP To see Recommendations in action, play with our showcase.'
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Related Tags UI
3
+ ---
4
+
5
+ # Related Tags UI
6
+
7
+ The Related Tags UI component helps your shoppers to refine a specific search query and find what
8
+ they’re looking for with just one click. They only appear after the search process is completed, and
9
+ the results appear to fine-tune the search with extra information and get highly relevant results.
10
+ They are shown as labels usually at the top of the results page, but can be displayed anywhere
11
+ instead.
12
+
13
+ ![Related Tags](/assets/media/xcomponents_func_relatedtags.gif)
14
+
15
+ :::warning Related Tags are generated using collective shopper behavior to identify associated terms
16
+ used to refine a search query. For a correct performance, make sure that your current search service
17
+ supports this type of feature. :::
18
+
19
+ ::: interact Can't quite capture the concept? Learn more about
20
+ [Related Tags](../features/related-tags-overview.md). :::
21
+
22
+ [//]:
23
+ #
24
+ 'You can configure the behaviour of Related Tags and decide whether they’re selectable or not. If Related Tags aren’t selectable, they modify the initial query syntax by adding the related-search keywords to the query term initially typed in the search bar. Otherwise, the initial query syntax will still remain so that shoppers can select or deselect Related Tags at their ease, exploring different options and combinations.'
25
+
26
+ ## Tailor the web experience
27
+
28
+ - Configure the position and place it wherever you prefer, although Related Tags usually appear
29
+ below the search bar after completing the search.
30
+ - Show as many Related Tags as you want.
31
+ - Animate the display of Related Tags at your ease.
32
+ - Customize content. Show whatever you need: text, images, icons.
33
+
34
+ [//]:
35
+ #
36
+ '* Choose if Related Tags are selectable or change the syntax of the initial query in the search box.'
37
+
38
+ ::: interact Want to know more? Learn how to [configure](/develop-empathy-platform/ui-reference/)
39
+ your web experience. :::
40
+
41
+ [//]: # 'tip To see Related Tags in action, play with our showcase'
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Search Box UI
3
+ ---
4
+
5
+ # Search Box UI
6
+
7
+ The Search&nbsp;Box UI Component is the main entry point for search where shoppers can type what
8
+ they're looking for in your shop. It usually includes an input field, a search button, and a clear
9
+ button.
10
+
11
+ <img :src="$withBase('/assets/media/xcomponents_func_searchbox.svg')" alt="Search Box"> <br>
12
+
13
+ ::: interact Can't quite capture the concept? Learn more about
14
+ [Search Box](../overview/search-box-overview.md). :::
15
+
16
+ It can be combined with other X&nbsp;Components, such as [Query Suggestions](query-suggestions.md)
17
+ or [Next Queries](next-queries.md), to update the query according to shoppers’ intent or
18
+ behaviour. For example, if a shopper selects a query suggestion, the query is instantly updated in
19
+ the input field to the selected suggestion and the search is launched.
20
+
21
+ :::warning To modify the query syntax using
22
+ [Query Suggestions](../features/query-suggestions-overview.md) or
23
+ [Next Queries](../features/next-queries-overview.md), make sure that your current search service
24
+ supports this type of feature. :::
25
+
26
+ ## Power-up behavior
27
+
28
+ Every component has a power-up behavior under the hood that is visible to the user but not glaringly
29
+ obvious. For example, in Interface X Components for web, see what happens when:
30
+
31
+ - _A query with results is **submitted**_:
32
+
33
+ - Results are displayed
34
+ - Related tags are displayed
35
+ - Next queries are displayed
36
+ - The query can be displayed in the History Queries or Query Suggestions lists upon configuration
37
+
38
+ - _A query with results is **cleared** using the clear button_:
39
+
40
+ - Any text in the search input is cleared
41
+ - The results are cleared
42
+ - The query suggestions are cleared
43
+ - The next queries are not cleared
44
+ - The related tags are cleared
45
+ - The searched query is displayed in history queries
46
+
47
+ - _Using **instant search and a query is being typed** that has results_:
48
+
49
+ - No results are displayed before debounce time
50
+ - Results are displayed after debounce time
51
+ - Next queries are displayed after debounce time
52
+ - Related tags are displayed after debounce time
53
+
54
+ - _Using **instant search and modifying the initial query**_:
55
+ - No results related to the second query are displayed before debounce time
56
+ - Results related to the second query are displayed after debounce time
57
+ - Displayed results are different from the previous ones
58
+
59
+ ::: warning Deactivating instant search means History Queries are not updated until the search
60
+ button or Enter key is pressed, since the typed query is not submitted until one of these two
61
+ actions is performed. :::
62
+
63
+ ## Tailor the web experience
64
+
65
+ - Configure the position and place it wherever you prefer.
66
+ - Customize content. Allow shoppers to search or clear their search using text or icons.
67
+ - Determine the number of characters shoppers can enter in the search input.
68
+ - Autofocus the input field when the search&nbsp;box is displayed.
69
+ - Auto-accept the query without the need of using a search button or the Enter key. Determine the
70
+ debounce time to wait before instant search.
71
+ - Configure what will happen after the search is triggered; for example, display Related Tags or
72
+ Next Queries.
73
+
74
+ [//]:
75
+ #
76
+ 'TO BE PUBLISHED IN FUTURE ITERATIONS WHEN THE SEARCH BOX POWER-UP ARE IMPLEMENTED: * Automatically suggest search terms to guide shoppers in constructing their search query. * Prompt shoppers to start their search with animated custom hint messages. '
77
+
78
+ ::: interact Want to know more? Learn how to [configure](/develop-empathy-platform/ui-reference/)
79
+ your web experience. :::
80
+
81
+ [//]: # 'TIP: To see Search Box in action, play with our showcase.'
@@ -0,0 +1,109 @@
1
+ ---
2
+ title: SERP UI
3
+ ---
4
+
5
+ # SERP UI
6
+
7
+ To handle and display search results, the layout of results and other related discovery features is
8
+ paramount. For example, how to arrange results on the SERP or the features shoppers expect to easily
9
+ navigate and organize results are key points to have in mind. <br/>
10
+
11
+ ![X Components for results layout](/assets/media/xcomponents_func_results_layout.svg)
12
+
13
+ <FootNote>
14
+
15
+ **X&nbsp;Components for results layout** <br/> (A) Grid, (B) Number of results, (C) Column Picker,
16
+ (D) Sorting, and (E) Scrolling
17
+
18
+ </FootNote>
19
+ <br/>
20
+
21
+ **Choice of the layout view** Your shoppers should be able to select how they’d like the products
22
+ displayed and how the number of products they’d like to see per page, for example.
23
+
24
+ That’s why the **grid** (A) is the core element of the SERP. It displays the results returned by the
25
+ search service using a grid layout. Its value relies on having a configurable and flexible space to
26
+ place all types of results or even other layout components such as a carousel visualization for
27
+ [Next Queries](next-queries.md) or [Recommendations](recommendations.md).
28
+
29
+ However, the grid is not the only element to consider when designing the SERP:
30
+
31
+ [//]:
32
+ #
33
+ 'To add when ready: Include **pagination** options to browse results throughout the different result pages available or apply **infinite scroll** to ease navigation.'
34
+
35
+ - Show the **number of results** (B).
36
+ - Allow your shoppers to select the **number of columns** (C) to showcase results.
37
+ - Provide a **[sorting system](/explore-empathy-platform/overview/sorting-overview.md)** (D) so that
38
+ your shoppers can arrange results according to different criteria such as relevance, price,
39
+ alphabetical order…
40
+ - Include **[pagination](/explore-empathy-platform/overview/pagination-overview.md)** options to
41
+ browse results throughout the different result pages available or apply infinite scroll to ease
42
+ navigation.
43
+ - Apply **infinite scroll** to ease navigation and add a **scroll-to-top button** (E) to quickly
44
+ move to the top of the results page.
45
+ - Indicate your shoppers whether the
46
+ **[spellcheck](/explore-empathy-platform/features/spellcheck-overview.md)** feature is applied or
47
+ not.
48
+
49
+ ::: note Enhance the search experience, adding [Related Tags](related-tags.md) to the SERP so that
50
+ your shoppers can select descriptive keywords to refine the initial query and get highly relevant
51
+ results. :::
52
+
53
+ ::: design As most shoppers don’t like to spend time scrolling and moving between pages, a crucial
54
+ element on the SERP for a great experience is to offer **faceted search**, letting shoppers specify
55
+ the kind of product attributes they’re interested in. :::
56
+
57
+ ::: interact To learn more about the SERP, results display, and their layout, see
58
+ [Results on the SERP](../overview/results-overview.md). :::
59
+
60
+ ## Tailor the web experience
61
+
62
+ **Grid**
63
+
64
+ - Customize the layout of the results. Decide whether to display results using a grid or the default
65
+ list layout.
66
+ - Configure what to display: product results, promotion banners, promoted results, or even next
67
+ queries and recommendations.
68
+ - Customize the location, style, and content for each type of result.
69
+ - Automatically fill the grid rows with as many columns as it can fit or set the number of columns
70
+ to divide the grid.
71
+ - Indicate the number of product results to render per page.
72
+ - Animate the display of the grid at your ease.
73
+ - Allow your users to select the number of columns to display. Define if your shoppers will be
74
+ provided with a dropdown menu or a list with the columns to pick for the grid.
75
+ - Show the total number of product results displayed. Configure the content with text, images, or
76
+ icons.
77
+
78
+ **Sorting**
79
+
80
+ - Choose and configure the sorting options available. Highlight the selected sorting option.
81
+ - Select the display of the sorting system: dropdown menu or a simple list with the sorting options
82
+ available.
83
+ - Animate the display of the sorting dropdown menu.
84
+ - Set a default sorting option.
85
+ <!-- TBC: Decide which sorting option to display based on product category. -->
86
+
87
+ **Pagination & scrolling**
88
+
89
+ - Customize the content and style for the controls to move between pages.
90
+ - Include an infinite scroll to load more results when reaching the end of the page.
91
+
92
+ **Scrolling to top**
93
+
94
+ - Decide when it will be displayed: when reached a defined threshold or the page end.
95
+ - Configure the position and place it wherever you prefer.
96
+ - Customize content. Show whatever you need: text, images, icons.
97
+ - Animate the display of the scroll-to-top button at your ease.
98
+
99
+ **Spellcheck**
100
+
101
+ - Display a message to inform your shoppers that the
102
+ [spellcheck](../features/spellcheck-overview.md) feature has been used to provide results for the
103
+ current query.
104
+ - Customize the message content at your ease.
105
+
106
+ ::: interact Want to know more? Learn how to [configure](/develop-empathy-platform/ui-reference/)
107
+ your web experience. :::
108
+
109
+ [//]: # 'TIP: To see the SERP-related components in action, play with our showcase.'
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: Interface X data privacy and browser local storage
3
+ tags:
4
+ - x components
5
+ - interface x
6
+ - cookies
7
+ - local storage
8
+ - history queries
9
+ ---
10
+
11
+ # Interface X data privacy and browser local storage
12
+
13
+ Interface&nbsp;X for web _doesn't use cookies_ for storing data. The
14
+ Interface&nbsp;X&nbsp;Components use the web browser's local storage to save the technical data
15
+ required to provide the services associated with the search & discovery experience. The data remains
16
+ in the shopper's device until the expiration time is reached or the shopper chooses to delete it.
17
+
18
+ More specifically, Interface&nbsp;X&nbsp;Components store the following elements in the browser's
19
+ local storage:
20
+
21
+ | Key | Duration | Purpose |
22
+ | ---------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
23
+ | `x-session-id` | 30 minutes | Short-term session ID to be sent to the Tagging API. It identifies short sessions in a device. It does not identify individual shoppers in any way. It is required for [Analytics](https://docs.empathy.co/explore-empathy-platform/understand-data-privacy/), [Next Queries](https://docs.empathy.co/explore-empathy-platform/features/history-queries-overview.html), and [Related Tags](https://docs.empathy.co/explore-empathy-platform/features/related-tags-overview.html) features |
24
+ | `x-session-time-stamp` | 30 minutes | Timestamp for the current session ID |
25
+ | `x-history-queries` | Stored until the shopper clears/disables the feature | List of the searches performed that the shopper has chosen to store, which are shown in different steps of the search journey. |
package/facets/index.js CHANGED
@@ -32,5 +32,5 @@ export { default as SelectedFiltersList } from '../js/x-modules/facets/component
32
32
  export { default as SlicedFilters } from '../js/x-modules/facets/components/lists/sliced-filters.vue.js';
33
33
  export { default as SortedFilters } from '../js/x-modules/facets/components/lists/sorted-filters.vue.js';
34
34
  export { default as ClearFilters } from '../js/x-modules/facets/components/clear-filters.vue.js';
35
- export { isNewQuery } from '../js/x-modules/facets/utils.js';
35
+ export { flatHierarchicalFilters, isNewQuery } from '../js/x-modules/facets/utils.js';
36
36
  export { default as FacetsMixin } from '../js/x-modules/facets/components/facets.mixin.js';
package/js/index.js CHANGED
@@ -207,7 +207,7 @@ export { default as SelectedFiltersList } from './x-modules/facets/components/li
207
207
  export { default as SlicedFilters } from './x-modules/facets/components/lists/sliced-filters.vue.js';
208
208
  export { default as SortedFilters } from './x-modules/facets/components/lists/sorted-filters.vue.js';
209
209
  export { default as ClearFilters } from './x-modules/facets/components/clear-filters.vue.js';
210
- export { isNewQuery } from './x-modules/facets/utils.js';
210
+ export { flatHierarchicalFilters, isNewQuery } from './x-modules/facets/utils.js';
211
211
  export { default as FacetsMixin } from './x-modules/facets/components/facets.mixin.js';
212
212
  export { default as ClearHistoryQueries } from './x-modules/history-queries/components/clear-history-queries.vue.js';
213
213
  export { default as HistoryQueries } from './x-modules/history-queries/components/history-queries.vue.js';
@@ -10,11 +10,11 @@ const __vue_script__ = script;
10
10
  /* style */
11
11
  const __vue_inject_styles__ = function (inject) {
12
12
  if (!inject) return
13
- inject("data-v-8b95797a_0", { source: ".x-facets-list[data-v-8b95797a] {\n list-style-type: none;\n}", map: undefined, media: undefined });
13
+ inject("data-v-7e46f769_0", { source: ".x-facets-list[data-v-7e46f769] {\n list-style-type: none;\n}", map: undefined, media: undefined });
14
14
 
15
15
  };
16
16
  /* scoped */
17
- const __vue_scope_id__ = "data-v-8b95797a";
17
+ const __vue_scope_id__ = "data-v-7e46f769";
18
18
  /* module identifier */
19
19
  const __vue_module_identifier__ = undefined;
20
20
  /* functional template */
@@ -1 +1 @@
1
- {"version":3,"file":"facets-provider.vue.js","sources":["../../../../../../src/x-modules/facets/components/facets/facets-provider.vue"],"sourcesContent":["<script lang=\"ts\">\n import { Facet, Filter } from '@empathyco/x-types';\n import Vue from 'vue';\n import { Component, Prop, Watch } from 'vue-property-decorator';\n import { XOn } from '../../../../components';\n import { xComponentMixin } from '../../../../components/x-component.mixin';\n import { areFiltersDifferent } from '../../../../utils/filters';\n import { FacetsGroup } from '../../service/types';\n import { GroupId } from '../../store/types';\n import { facetsXModule } from '../../x-module';\n\n /**\n * This component allows to provide facets by prop, to add them to the state of the\n * `Facets X-Module`. These facets will be added to the `Facets X-Module` state together with\n * the facets emitted by the `Search X-Module` through the {@link SearchXEvents.FacetsChanged}\n * event.\n *\n * @public\n */\n @Component({\n mixins: [xComponentMixin(facetsXModule)]\n })\n export default class FacetsProvider extends Vue {\n /**\n * An facet group identifier to distinguish the provided facets from other facets like the\n * `Search X-Module` facets.\n *\n * @public\n */\n @Prop({ default: 'provided-facets' })\n public groupId!: GroupId;\n\n /**\n * The facets to provide to the `Facets X-Module` state. They have to include the\n * {@link @empathyco/x-types#Filter | filters}.\n *\n * @internal\n */\n @Prop({ required: true })\n public facets!: Facet[];\n\n /**\n * Temporarily stores the selected filters from the {@link FacetsProvider.facets} prop.\n * This is necessary to handle the {@link FacetsXEvents.UserChangedSelectedFilters} event.\n *\n * @internal\n */\n protected selectedFilters: Filter[] | null = null;\n\n /**\n * A computed property to group the facets and the groupId. This is used by the watcher.\n *\n * @returns The FacetGroup with the facets and the group id.\n *\n * @internal\n */\n protected get facetsGroup(): FacetsGroup {\n return { id: this.groupId, facets: this.facets };\n }\n\n /**\n * Emits the {@link FacetsXEvents.UserChangedSelectedFilters} event when the user changes\n * the selected filters.\n *\n * @param selectedFilters - The new list of selected filters.\n * @internal\n */\n @XOn('SelectedFiltersChanged')\n emitSelectedFiltersChanged(selectedFilters: Filter[]): void {\n if (\n this.selectedFilters === null ||\n areFiltersDifferent(this.selectedFilters, selectedFilters)\n ) {\n this.$x.emit('UserChangedSelectedFilters', selectedFilters);\n }\n this.selectedFilters = null;\n }\n\n /**\n * Emits the {@link FacetsXEvents.FacetsGroupProvided} event with the\n * {@link FacetsProvider.facetsGroup} as payload. It also extracts and saves the selected\n * filters.\n */\n @Watch('facetsGroup', { immediate: true })\n provideFacets(): void {\n if (this.facetsGroup.facets) {\n this.$x.emit('FacetsGroupProvided', this.facetsGroup);\n this.extractSelectedFilters(this.facets);\n }\n }\n\n /**\n * Extracts the selected filters from the facets and stores them in the\n * {@link FacetsProvider.selectedFilters} property.\n *\n * @param facets - The facets from whom extract the selected filters.\n * @internal\n */\n protected extractSelectedFilters(facets: Facet[]): void {\n this.selectedFilters = facets\n .flatMap(facet => facet.filters)\n .filter(filter => filter.selected);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n render(): void {}\n }\n</script>\n\n<style lang=\"scss\" scoped>\n .x-facets-list {\n list-style-type: none;\n }\n</style>\n\n<docs lang=\"mdx\">\n## Example\n\nThis component allows to provide facets by prop, to add them to the state of the `Facets X-Module`.\nThese facets will be added to the `Facets X-Module` state together with the facets emitted by the\n`Search X-Module` through the {@link SearchXEvents.FacetsChanged} event.\n\n```vue\n<template>\n <FacetsProvider :facets=\"myFacets\" />\n</template>\n\n<script>\n import { FacetsProvider } from '@empathyco/x-components/facets';\n\n export default {\n components: {\n FacetsProvider\n },\n data() {\n return {\n myFacets: [\n {\n modelName: 'SimpleFacet',\n id: 'color-facet',\n label: 'Color',\n filters: [\n {\n modelName: 'SimpleFilter',\n id: 'color:red',\n facetId: 'color-facet',\n label: 'Red',\n selected: false,\n value: 'color:red',\n totalResults: 10\n },\n {\n modelName: 'SimpleFilter',\n id: 'color:blue',\n facetId: 'color-facet',\n label: 'Blue',\n selected: false,\n value: 'color:blue',\n totalResults: 10\n }\n ]\n }\n ]\n };\n }\n };\n</script>\n```\n\n## Events\n\nA list of events that the component will emit:\n\n- `UserChangedSelectedFilters`: the event is emitted after the user performed an action that changed\n the selected filters. The payload is the new list of selected filters.\n- `FacetsGroupProvided`: the event is emitted after updating the facets prop with a new list of\n facets. The payload contains a Facets Group with the facets and the group id.\n</docs>\n"],"names":[],"mappings":";;;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"facets-provider.vue.js","sources":["../../../../../../src/x-modules/facets/components/facets/facets-provider.vue"],"sourcesContent":["<script lang=\"ts\">\n import { Facet, Filter, isHierarchicalFacet } from '@empathyco/x-types';\n import Vue from 'vue';\n import { Component, Prop, Watch } from 'vue-property-decorator';\n import { XOn } from '../../../../components';\n import { xComponentMixin } from '../../../../components/x-component.mixin';\n import { clone } from '../../../../utils';\n import { areFiltersDifferent } from '../../../../utils/filters';\n import { FacetsGroup } from '../../service/types';\n import { GroupId } from '../../store/types';\n import { flatHierarchicalFilters } from '../../utils';\n import { facetsXModule } from '../../x-module';\n\n /**\n * This component allows to provide facets by prop, to add them to the state of the\n * `Facets X-Module`. These facets will be added to the `Facets X-Module` state together with\n * the facets emitted by the `Search X-Module` through the {@link SearchXEvents.FacetsChanged}\n * event.\n *\n * @public\n */\n @Component({\n mixins: [xComponentMixin(facetsXModule)]\n })\n export default class FacetsProvider extends Vue {\n /**\n * An facet group identifier to distinguish the provided facets from other facets like the\n * `Search X-Module` facets.\n *\n * @public\n */\n @Prop({ default: 'provided-facets' })\n public groupId!: GroupId;\n\n /**\n * The facets to provide to the `Facets X-Module` state. They have to include the\n * {@link @empathyco/x-types#Filter | filters}.\n *\n * @internal\n */\n @Prop({ required: true })\n public facets!: Facet[];\n\n /**\n * Temporarily stores the selected filters from the {@link FacetsProvider.facets} prop.\n * This is necessary to handle the {@link FacetsXEvents.UserChangedSelectedFilters} event.\n *\n * @internal\n */\n protected selectedFilters: Filter[] | null = null;\n\n /**\n * A computed property to group the facets and the groupId. This is used by the watcher.\n *\n * @returns The FacetGroup with the facets and the group id.\n *\n * @internal\n */\n protected get facetsGroup(): FacetsGroup {\n return { id: this.groupId, facets: this.facets };\n }\n\n /**\n * Emits the {@link FacetsXEvents.UserChangedSelectedFilters} event when the user changes\n * the selected filters.\n *\n * @param selectedFilters - The new list of selected filters.\n * @internal\n */\n @XOn('SelectedFiltersChanged')\n emitSelectedFiltersChanged(selectedFilters: Filter[]): void {\n if (\n this.selectedFilters === null ||\n areFiltersDifferent(this.selectedFilters, selectedFilters)\n ) {\n this.$x.emit('UserChangedSelectedFilters', selectedFilters);\n }\n this.selectedFilters = null;\n }\n\n /**\n * Emits the {@link FacetsXEvents.FacetsGroupProvided} event with the\n * {@link FacetsProvider.facetsGroup} as payload. It also extracts and saves the selected\n * filters.\n */\n @Watch('facetsGroup', { immediate: true })\n provideFacets(): void {\n if (this.facetsGroup.facets) {\n const facetsGroupClone = clone(this.facetsGroup);\n this.$x.emit('FacetsGroupProvided', facetsGroupClone);\n this.extractSelectedFilters(this.facets);\n }\n }\n\n /**\n * Extracts the selected filters from the facets and stores them in the\n * {@link FacetsProvider.selectedFilters} property.\n *\n * @param facets - The facets from whom extract the selected filters.\n * @internal\n */\n protected extractSelectedFilters(facets: Facet[]): void {\n this.selectedFilters = facets\n .flatMap(facet =>\n isHierarchicalFacet(facet) ? flatHierarchicalFilters(facet.filters) : facet.filters\n )\n .filter(filter => filter.selected);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n render(): void {}\n }\n</script>\n\n<style lang=\"scss\" scoped>\n .x-facets-list {\n list-style-type: none;\n }\n</style>\n\n<docs lang=\"mdx\">\n## Example\n\nThis component allows to provide facets by prop, to add them to the state of the `Facets X-Module`.\nThese facets will be added to the `Facets X-Module` state together with the facets emitted by the\n`Search X-Module` through the {@link SearchXEvents.FacetsChanged} event.\n\n```vue\n<template>\n <FacetsProvider :facets=\"myFacets\" />\n</template>\n\n<script>\n import { FacetsProvider } from '@empathyco/x-components/facets';\n\n export default {\n components: {\n FacetsProvider\n },\n data() {\n return {\n myFacets: [\n {\n modelName: 'SimpleFacet',\n id: 'color-facet',\n label: 'Color',\n filters: [\n {\n modelName: 'SimpleFilter',\n id: 'color:red',\n facetId: 'color-facet',\n label: 'Red',\n selected: false,\n value: 'color:red',\n totalResults: 10\n },\n {\n modelName: 'SimpleFilter',\n id: 'color:blue',\n facetId: 'color-facet',\n label: 'Blue',\n selected: false,\n value: 'color:blue',\n totalResults: 10\n }\n ]\n }\n ]\n };\n }\n };\n</script>\n```\n\n## Events\n\nA list of events that the component will emit:\n\n- `UserChangedSelectedFilters`: the event is emitted after the user performed an action that changed\n the selected filters. The payload is the new list of selected filters.\n- `FacetsGroupProvided`: the event is emitted after updating the facets prop with a new list of\n facets. The payload contains a Facets Group with the facets and the group id.\n</docs>\n"],"names":[],"mappings":";;;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,4 +1,5 @@
1
1
  import { __decorate } from 'tslib';
2
+ import { isHierarchicalFacet } from '@empathyco/x-types';
2
3
  import Vue from 'vue';
3
4
  import { Prop, Watch, Component } from 'vue-property-decorator';
4
5
  import '../../../../components/animations/animate-width.vue.js';
@@ -123,7 +124,10 @@ import { XOn } from '../../../../components/decorators/bus.decorators.js';
123
124
  import 'vue-class-component';
124
125
  import '../../../../components/items-list-injection.mixin.js';
125
126
  import { xComponentMixin } from '../../../../components/x-component.mixin.js';
127
+ import { clone } from '../../../../utils/clone.js';
126
128
  import { areFiltersDifferent } from '../../../../utils/filters.js';
129
+ import '../../../../utils/storage.js';
130
+ import { flatHierarchicalFilters } from '../../utils.js';
127
131
  import { facetsXModule } from '../../x-module.js';
128
132
 
129
133
  /**
@@ -176,7 +180,8 @@ let FacetsProvider = class FacetsProvider extends Vue {
176
180
  */
177
181
  provideFacets() {
178
182
  if (this.facetsGroup.facets) {
179
- this.$x.emit('FacetsGroupProvided', this.facetsGroup);
183
+ const facetsGroupClone = clone(this.facetsGroup);
184
+ this.$x.emit('FacetsGroupProvided', facetsGroupClone);
180
185
  this.extractSelectedFilters(this.facets);
181
186
  }
182
187
  }
@@ -189,7 +194,7 @@ let FacetsProvider = class FacetsProvider extends Vue {
189
194
  */
190
195
  extractSelectedFilters(facets) {
191
196
  this.selectedFilters = facets
192
- .flatMap(facet => facet.filters)
197
+ .flatMap(facet => isHierarchicalFacet(facet) ? flatHierarchicalFilters(facet.filters) : facet.filters)
193
198
  .filter(filter => filter.selected);
194
199
  }
195
200
  // eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -1 +1 @@
1
- {"version":3,"file":"facets-provider.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../../src/x-modules/facets/components/facets/facets-provider.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\nimport { Facet, Filter } from '@empathyco/x-types';\nimport Vue from 'vue';\nimport { Component, Prop, Watch } from 'vue-property-decorator';\nimport { XOn } from '../../../../components';\nimport { xComponentMixin } from '../../../../components/x-component.mixin';\nimport { areFiltersDifferent } from '../../../../utils/filters';\nimport { FacetsGroup } from '../../service/types';\nimport { GroupId } from '../../store/types';\nimport { facetsXModule } from '../../x-module';\n\n/**\n * This component allows to provide facets by prop, to add them to the state of the\n * `Facets X-Module`. These facets will be added to the `Facets X-Module` state together with\n * the facets emitted by the `Search X-Module` through the {@link SearchXEvents.FacetsChanged}\n * event.\n *\n * @public\n */\n@Component({\n mixins: [xComponentMixin(facetsXModule)]\n})\nexport default class FacetsProvider extends Vue {\n /**\n * An facet group identifier to distinguish the provided facets from other facets like the\n * `Search X-Module` facets.\n *\n * @public\n */\n @Prop({ default: 'provided-facets' })\n public groupId!: GroupId;\n\n /**\n * The facets to provide to the `Facets X-Module` state. They have to include the\n * {@link @empathyco/x-types#Filter | filters}.\n *\n * @internal\n */\n @Prop({ required: true })\n public facets!: Facet[];\n\n /**\n * Temporarily stores the selected filters from the {@link FacetsProvider.facets} prop.\n * This is necessary to handle the {@link FacetsXEvents.UserChangedSelectedFilters} event.\n *\n * @internal\n */\n protected selectedFilters: Filter[] | null = null;\n\n /**\n * A computed property to group the facets and the groupId. This is used by the watcher.\n *\n * @returns The FacetGroup with the facets and the group id.\n *\n * @internal\n */\n protected get facetsGroup(): FacetsGroup {\n return { id: this.groupId, facets: this.facets };\n }\n\n /**\n * Emits the {@link FacetsXEvents.UserChangedSelectedFilters} event when the user changes\n * the selected filters.\n *\n * @param selectedFilters - The new list of selected filters.\n * @internal\n */\n @XOn('SelectedFiltersChanged')\n emitSelectedFiltersChanged(selectedFilters: Filter[]): void {\n if (\n this.selectedFilters === null ||\n areFiltersDifferent(this.selectedFilters, selectedFilters)\n ) {\n this.$x.emit('UserChangedSelectedFilters', selectedFilters);\n }\n this.selectedFilters = null;\n }\n\n /**\n * Emits the {@link FacetsXEvents.FacetsGroupProvided} event with the\n * {@link FacetsProvider.facetsGroup} as payload. It also extracts and saves the selected\n * filters.\n */\n @Watch('facetsGroup', { immediate: true })\n provideFacets(): void {\n if (this.facetsGroup.facets) {\n this.$x.emit('FacetsGroupProvided', this.facetsGroup);\n this.extractSelectedFilters(this.facets);\n }\n }\n\n /**\n * Extracts the selected filters from the facets and stores them in the\n * {@link FacetsProvider.selectedFilters} property.\n *\n * @param facets - The facets from whom extract the selected filters.\n * @internal\n */\n protected extractSelectedFilters(facets: Facet[]): void {\n this.selectedFilters = facets\n .flatMap(facet => facet.filters)\n .filter(filter => filter.selected);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n render(): void {}\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA;;;;;;;;AAWA,IAAqB,cAAc,GAAnC,MAAqB,cAAe,SAAQ,GAAG;IAA/C;;;;;;;;QAyBY,oBAAe,GAAoB,IAAI,CAAC;KA2DnD;;;;;;;;IAlDC,IAAc,WAAW;QACvB,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;KAClD;;;;;;;;IAUD,0BAA0B,CAAC,eAAyB;QAClD,IACE,IAAI,CAAC,eAAe,KAAK,IAAI;YAC7B,mBAAmB,CAAC,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,EAC1D;YACA,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;SAC7D;QACD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;KAC7B;;;;;;IAQD,aAAa;QACX,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;YAC3B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACtD,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC1C;KACF;;;;;;;;IASS,sBAAsB,CAAC,MAAe;QAC9C,IAAI,CAAC,eAAe,GAAG,MAAM;aAC1B,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;aAC/B,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC;KACtC;;IAGD,MAAM,MAAW;CAClB,CAAA;AA5EC;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;+CACZ;AASzB;IADC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8CACD;AA6BxB;IADC,GAAG,CAAC,wBAAwB,CAAC;gEAS7B;AAQD;IADC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;mDAMzC;AAnEkB,cAAc;IAHlC,SAAS,CAAC;QACT,MAAM,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;KACzC,CAAC;GACmB,cAAc,CAoFlC;aApFoB,cAAc;;;;"}
1
+ {"version":3,"file":"facets-provider.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../../../src/x-modules/facets/components/facets/facets-provider.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\nimport { Facet, Filter, isHierarchicalFacet } from '@empathyco/x-types';\nimport Vue from 'vue';\nimport { Component, Prop, Watch } from 'vue-property-decorator';\nimport { XOn } from '../../../../components';\nimport { xComponentMixin } from '../../../../components/x-component.mixin';\nimport { clone } from '../../../../utils';\nimport { areFiltersDifferent } from '../../../../utils/filters';\nimport { FacetsGroup } from '../../service/types';\nimport { GroupId } from '../../store/types';\nimport { flatHierarchicalFilters } from '../../utils';\nimport { facetsXModule } from '../../x-module';\n\n/**\n * This component allows to provide facets by prop, to add them to the state of the\n * `Facets X-Module`. These facets will be added to the `Facets X-Module` state together with\n * the facets emitted by the `Search X-Module` through the {@link SearchXEvents.FacetsChanged}\n * event.\n *\n * @public\n */\n@Component({\n mixins: [xComponentMixin(facetsXModule)]\n})\nexport default class FacetsProvider extends Vue {\n /**\n * An facet group identifier to distinguish the provided facets from other facets like the\n * `Search X-Module` facets.\n *\n * @public\n */\n @Prop({ default: 'provided-facets' })\n public groupId!: GroupId;\n\n /**\n * The facets to provide to the `Facets X-Module` state. They have to include the\n * {@link @empathyco/x-types#Filter | filters}.\n *\n * @internal\n */\n @Prop({ required: true })\n public facets!: Facet[];\n\n /**\n * Temporarily stores the selected filters from the {@link FacetsProvider.facets} prop.\n * This is necessary to handle the {@link FacetsXEvents.UserChangedSelectedFilters} event.\n *\n * @internal\n */\n protected selectedFilters: Filter[] | null = null;\n\n /**\n * A computed property to group the facets and the groupId. This is used by the watcher.\n *\n * @returns The FacetGroup with the facets and the group id.\n *\n * @internal\n */\n protected get facetsGroup(): FacetsGroup {\n return { id: this.groupId, facets: this.facets };\n }\n\n /**\n * Emits the {@link FacetsXEvents.UserChangedSelectedFilters} event when the user changes\n * the selected filters.\n *\n * @param selectedFilters - The new list of selected filters.\n * @internal\n */\n @XOn('SelectedFiltersChanged')\n emitSelectedFiltersChanged(selectedFilters: Filter[]): void {\n if (\n this.selectedFilters === null ||\n areFiltersDifferent(this.selectedFilters, selectedFilters)\n ) {\n this.$x.emit('UserChangedSelectedFilters', selectedFilters);\n }\n this.selectedFilters = null;\n }\n\n /**\n * Emits the {@link FacetsXEvents.FacetsGroupProvided} event with the\n * {@link FacetsProvider.facetsGroup} as payload. It also extracts and saves the selected\n * filters.\n */\n @Watch('facetsGroup', { immediate: true })\n provideFacets(): void {\n if (this.facetsGroup.facets) {\n const facetsGroupClone = clone(this.facetsGroup);\n this.$x.emit('FacetsGroupProvided', facetsGroupClone);\n this.extractSelectedFilters(this.facets);\n }\n }\n\n /**\n * Extracts the selected filters from the facets and stores them in the\n * {@link FacetsProvider.selectedFilters} property.\n *\n * @param facets - The facets from whom extract the selected filters.\n * @internal\n */\n protected extractSelectedFilters(facets: Facet[]): void {\n this.selectedFilters = facets\n .flatMap(facet =>\n isHierarchicalFacet(facet) ? flatHierarchicalFilters(facet.filters) : facet.filters\n )\n .filter(filter => filter.selected);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n render(): void {}\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA;;;;;;;;AAWA,IAAqB,cAAc,GAAnC,MAAqB,cAAe,SAAQ,GAAG;IAA/C;;;;;;;;QAyBY,oBAAe,GAAoB,IAAI,CAAC;KA8DnD;;;;;;;;IArDC,IAAc,WAAW;QACvB,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;KAClD;;;;;;;;IAUD,0BAA0B,CAAC,eAAyB;QAClD,IACE,IAAI,CAAC,eAAe,KAAK,IAAI;YAC7B,mBAAmB,CAAC,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,EAC1D;YACA,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;SAC7D;QACD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;KAC7B;;;;;;IAQD,aAAa;QACX,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;YAC3B,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAC;YACtD,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC1C;KACF;;;;;;;;IASS,sBAAsB,CAAC,MAAe;QAC9C,IAAI,CAAC,eAAe,GAAG,MAAM;aAC1B,OAAO,CAAC,KAAK,IACZ,mBAAmB,CAAC,KAAK,CAAC,GAAG,uBAAuB,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,OAAO,CACpF;aACA,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC;KACtC;;IAGD,MAAM,MAAW;CAClB,CAAA;AA/EC;IADC,IAAI,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;+CACZ;AASzB;IADC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8CACD;AA6BxB;IADC,GAAG,CAAC,wBAAwB,CAAC;gEAS7B;AAQD;IADC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;mDAOzC;AApEkB,cAAc;IAHlC,SAAS,CAAC;QACT,MAAM,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;KACzC,CAAC;GACmB,cAAc,CAuFlC;aAvFoB,cAAc;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"hierarchical-filter.vue.js","sources":["../../../../../../src/x-modules/facets/components/filters/hierarchical-filter.vue"],"sourcesContent":["<template>\n <div class=\"x-hierarchical-filter-container\" data-test=\"hierarchical-filter-container\">\n <RenderlessFilter\n v-slot=\"{ filter, clickFilter, cssClasses, isDisabled }\"\n :class=\"cssClasses\"\n :clickEvents=\"_clickEvents\"\n :filter=\"filter\"\n class=\"x-hierarchical-filter\"\n >\n <!--\n @slot The content to render inside the button.\n @binding {Filter} filter - The filter data.\n @binding {Function} clickFilter - The handler to invoke when clicking the filter.\n @binding {VueCssClasses} cssClasses - The CSS classes.\n @binding {boolean} isDisabled - Flag determining the disabled state.\n -->\n <slot v-bind=\"{ filter, clickFilter, cssClasses, isDisabled }\">\n <button\n @click=\"clickFilter\"\n :aria-checked=\"filter.selected.toString()\"\n :class=\"cssClasses\"\n :disabled=\"isDisabled\"\n data-test=\"filter\"\n role=\"checkbox\"\n >\n <!--\n @slot The content to render inside the button.\n @binding {Filter} filter - The filter data.\n -->\n <slot name=\"label\" :filter=\"filter\">{{ filter.label }}</slot>\n </button>\n </slot>\n </RenderlessFilter>\n <FiltersList\n v-slot=\"{ filter: childFilter }\"\n :animation=\"childrenAnimation\"\n :filters=\"renderedChildrenFilters\"\n :parent-id=\"filter.id\"\n class=\"x-hierarchical-filter__children\"\n data-test=\"children-filters\"\n >\n <HierarchicalFilter\n :childrenAnimation=\"childrenAnimation\"\n :filter=\"childFilter\"\n :clickEvents=\"getChildFilterClickEvents(childFilter)\"\n >\n <template #default=\"{ filter, clickFilter, cssClasses, isDisabled }\">\n <slot v-bind=\"{ filter, clickFilter, cssClasses, isDisabled }\" />\n </template>\n <template #label=\"{ filter }\">\n <slot name=\"label\" :filter=\"filter\" />\n </template>\n </HierarchicalFilter>\n </FiltersList>\n </div>\n</template>\n\n<script lang=\"ts\">\n import {\n Filter,\n HierarchicalFilter as HierarchicalFilterModel,\n isHierarchicalFilter\n } from '@empathyco/x-types';\n import { isObject } from '@empathyco/x-utils';\n import Vue from 'vue';\n import { Component, Prop } from 'vue-property-decorator';\n import { State, xComponentMixin } from '../../../../components';\n import { VueCSSClasses } from '../../../../utils/types';\n import { XEventsTypes } from '../../../../wiring/events.types';\n import { facetsXModule } from '../../x-module';\n import FiltersList from '../lists/filters-list.vue';\n import RenderlessFilter from './renderless-filter.vue';\n\n /**\n * Renders a hierarchical filter recursively, emitting the needed events when clicked.\n *\n * @public\n */\n @Component({\n name: 'HierarchicalFilter',\n components: { FiltersList, RenderlessFilter },\n mixins: [xComponentMixin(facetsXModule)]\n })\n export default class HierarchicalFilter extends Vue {\n /** The filter data to render. */\n @Prop({ required: true })\n public filter!: HierarchicalFilterModel;\n\n /** The animation component to use for the children filters. */\n @Prop()\n public childrenAnimation?: Vue | string;\n /**\n * The state filters.\n *\n * @internal\n */\n @State('facets', 'filters')\n public filters!: Record<Filter['id'], Filter>;\n\n /**\n * Additional events, with their payload, to emit when the filter is clicked.\n *\n * @public\n */\n @Prop()\n public clickEvents!: Partial<XEventsTypes>;\n\n /**\n * The {@link XEventsTypes | events} to emit.\n *\n * @returns The events to emit when clicked.\n * @internal\n */\n protected get _clickEvents(): Partial<XEventsTypes> {\n return {\n UserClickedAHierarchicalFilter: this.filter,\n ...this.clickEvents\n };\n }\n\n /**\n * Dynamic CSS classes to apply to the component.\n *\n * @returns The dynamic CSS classes to apply to the component.\n * @internal\n */\n protected get cssClasses(): VueCSSClasses {\n return {\n 'x-hierarchical-filter--is-partially-selected': this.isPartiallySelected,\n 'x-hierarchical-filter--is-selected': this.filter.selected,\n 'x-filter--is-partially-selected': this.isPartiallySelected\n };\n }\n\n /**\n * Gets the child filter click events, converting the payload of the events that have a\n * {@link @empathyco/x-types#HierarchicalFilter} as payload to the corresponding child filter.\n *\n * @param childFilter - The child filter.\n * @returns The events to emit when clicking a child.\n * @internal\n */\n protected getChildFilterClickEvents(\n childFilter: HierarchicalFilterModel\n ): Partial<XEventsTypes> {\n return Object.entries(this._clickEvents).reduce((clickEvents, [event, payload]) => {\n return {\n ...clickEvents,\n [event]:\n isObject(payload) &&\n isHierarchicalFilter(payload as unknown as Filter) &&\n childFilter !== (payload as unknown as HierarchicalFilterModel)\n ? childFilter\n : payload\n };\n }, {} as Partial<XEventsTypes>);\n }\n\n /**\n * Returns if the filter is partially selected, which means having more than one child filter\n * selected, but not every of them, or having at least one child filter partially selected.\n *\n * @returns True if the filter is partially selected. False otherwise.\n * @internal\n */\n protected get isPartiallySelected(): boolean {\n return this.isFilterPartiallySelected(this.filter);\n }\n\n /**\n * List of filters to render, in case that the children's array\n * is empty it will return an empty array instead of inject the ones from the parent.\n *\n * @returns A list of filters.\n * @internal\n */\n protected get renderedChildrenFilters(): Filter[] {\n return this.filter.children?.map(filterId => this.filters[filterId]) ?? [];\n }\n\n protected isFilterPartiallySelected(filter: HierarchicalFilterModel): boolean {\n const selectedChildren = filter.children\n ?.map(filterId => this.filters[filterId])\n ?.filter(filter => filter?.selected) as HierarchicalFilterModel[] | undefined;\n const filterChildrenLength = filter.children?.length ?? 0;\n return (\n !!selectedChildren &&\n ((selectedChildren.length > 0 && selectedChildren.length < filterChildrenLength) ||\n // eslint-disable-next-line @typescript-eslint/unbound-method\n selectedChildren.some(this.isFilterPartiallySelected))\n );\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nA list of events that the component will emit:\n\n- [`UserClickedAFilter`](x-components.xeventstypes.userclickedafilter.md): the event is emitted\n after the user clicks the button, using the `filter` prop as its payload.\n- [`UserClickedAHierarchicalFilter`](x-components.xeventstypes.userclickedahierarchicalfilter.md):\n the event is emitted after the user clicks the button, using the `filter` prop as its payload.\n filter.\n\n## See it in action\n\nThis component renders a button, which on clicked emits the `UserClickedAFilter` and\n`UserClickedAHierarchicalFilter` events. By default it renders the filter label as the button text.\nIf the provided filter has children filters, this component will render them recursively. Changing\nthe slot content will change it for all of the children.\n\nThe `filter` prop is required. The `clickEvents` prop is optional and allows configuring the events\nto emit on click.\n\n```vue\n<template>\n <HierarchicalFilter :filter=\"filter\" />\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n\n### Playing with props\n\nConfiguring the events to emit when the filter is clicked.\n\n```vue\n<template>\n <HierarchicalFilter :clickEvents=\"{ UserClickedAHierarchicalFilter: filter }\" :filter=\"filter\" />\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n\n### Customizing the default slot content\n\nIn this example, the child filters will also include the label and checkbox.\n\n```vue\n<template>\n <HierarchicalFilter :filter=\"filter\" v-slot=\"{ filter, clickFilter, slotCSSClasses, isDisabled }\">\n <label :class=\"slotCSSClasses\">\n <input @change=\"clickFilter\" :disabled=\"isDisabled\" />\n {{ filter.label }}\n </label>\n </HierarchicalFilter>\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n\n### Customizing the label slot content\n\n```vue\n<template>\n <HierarchicalFilter :filter=\"filter\">\n <template #label :filter=\"filter\">\n <span class=\"custom-class\">{{ filter.label }}</span>\n </template>\n </HierarchicalFilter>\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"hierarchical-filter.vue.js","sources":["../../../../../../src/x-modules/facets/components/filters/hierarchical-filter.vue"],"sourcesContent":["<template>\n <div class=\"x-hierarchical-filter-container\" data-test=\"hierarchical-filter-container\">\n <RenderlessFilter\n v-slot=\"{ filter, clickFilter, cssClasses, isDisabled }\"\n :class=\"cssClasses\"\n :clickEvents=\"_clickEvents\"\n :filter=\"filter\"\n class=\"x-hierarchical-filter\"\n >\n <!--\n @slot The content to render inside the button.\n @binding {Filter} filter - The filter data.\n @binding {Function} clickFilter - The handler to invoke when clicking the filter.\n @binding {VueCssClasses} cssClasses - The CSS classes.\n @binding {boolean} isDisabled - Flag determining the disabled state.\n -->\n <slot v-bind=\"{ filter, clickFilter, cssClasses, isDisabled }\">\n <button\n @click=\"clickFilter\"\n :aria-checked=\"filter.selected.toString()\"\n :class=\"cssClasses\"\n :disabled=\"isDisabled\"\n data-test=\"filter\"\n role=\"checkbox\"\n >\n <!--\n @slot The content to render inside the button.\n @binding {Filter} filter - The filter data.\n -->\n <slot name=\"label\" :filter=\"filter\">{{ filter.label }}</slot>\n </button>\n </slot>\n </RenderlessFilter>\n <FiltersList\n v-slot=\"{ filter: childFilter }\"\n :animation=\"childrenAnimation\"\n :filters=\"renderedChildrenFilters\"\n :parent-id=\"filter.id\"\n class=\"x-hierarchical-filter__children\"\n data-test=\"children-filters\"\n >\n <HierarchicalFilter\n :childrenAnimation=\"childrenAnimation\"\n :filter=\"childFilter\"\n :clickEvents=\"getChildFilterClickEvents(childFilter)\"\n >\n <template #default=\"{ filter, clickFilter, cssClasses, isDisabled }\">\n <slot v-bind=\"{ filter, clickFilter, cssClasses, isDisabled }\" />\n </template>\n <template #label=\"{ filter }\">\n <slot name=\"label\" :filter=\"filter\" />\n </template>\n </HierarchicalFilter>\n </FiltersList>\n </div>\n</template>\n\n<script lang=\"ts\">\n import {\n Filter,\n HierarchicalFilter as HierarchicalFilterModel,\n isHierarchicalFilter\n } from '@empathyco/x-types';\n import { isObject } from '@empathyco/x-utils';\n import Vue from 'vue';\n import { Component, Prop } from 'vue-property-decorator';\n import { xComponentMixin } from '../../../../components/x-component.mixin';\n import { VueCSSClasses } from '../../../../utils/types';\n import { XEventsTypes } from '../../../../wiring/events.types';\n import { facetsXModule } from '../../x-module';\n import FiltersList from '../lists/filters-list.vue';\n import RenderlessFilter from './renderless-filter.vue';\n\n /**\n * Renders a hierarchical filter recursively, emitting the needed events when clicked.\n *\n * @public\n */\n @Component({\n name: 'HierarchicalFilter',\n components: { FiltersList, RenderlessFilter },\n mixins: [xComponentMixin(facetsXModule)]\n })\n export default class HierarchicalFilter extends Vue {\n /** The filter data to render. */\n @Prop({ required: true })\n public filter!: HierarchicalFilterModel;\n\n /** The animation component to use for the children filters. */\n @Prop()\n public childrenAnimation?: Vue | string;\n\n /**\n * Additional events, with their payload, to emit when the filter is clicked.\n *\n * @public\n */\n @Prop()\n public clickEvents!: Partial<XEventsTypes>;\n\n /**\n * The {@link XEventsTypes | events} to emit.\n *\n * @returns The events to emit when clicked.\n * @internal\n */\n protected get _clickEvents(): Partial<XEventsTypes> {\n return {\n UserClickedAHierarchicalFilter: this.filter,\n ...this.clickEvents\n };\n }\n\n /**\n * Dynamic CSS classes to apply to the component.\n *\n * @returns The dynamic CSS classes to apply to the component.\n * @internal\n */\n protected get cssClasses(): VueCSSClasses {\n return {\n 'x-hierarchical-filter--is-partially-selected': this.isPartiallySelected,\n 'x-hierarchical-filter--is-selected': this.filter.selected,\n 'x-filter--is-partially-selected': this.isPartiallySelected\n };\n }\n\n /**\n * Gets the child filter click events, converting the payload of the events that have a\n * {@link @empathyco/x-types#HierarchicalFilter} as payload to the corresponding child filter.\n *\n * @param childFilter - The child filter.\n * @returns The events to emit when clicking a child.\n * @internal\n */\n protected getChildFilterClickEvents(\n childFilter: HierarchicalFilterModel\n ): Partial<XEventsTypes> {\n return Object.entries(this._clickEvents).reduce((clickEvents, [event, payload]) => {\n return {\n ...clickEvents,\n [event]:\n isObject(payload) &&\n isHierarchicalFilter(payload as unknown as Filter) &&\n childFilter !== (payload as unknown as HierarchicalFilterModel)\n ? childFilter\n : payload\n };\n }, {} as Partial<XEventsTypes>);\n }\n\n /**\n * Returns if the filter is partially selected, which means having more than one child filter\n * selected, but not every of them, or having at least one child filter partially selected.\n *\n * @returns True if the filter is partially selected. False otherwise.\n * @internal\n */\n protected get isPartiallySelected(): boolean {\n return this.isFilterPartiallySelected(this.filter);\n }\n\n /**\n * List of filters to render, in case that the children's array\n * is empty it will return an empty array instead of inject the ones from the parent.\n *\n * @returns A list of filters.\n * @internal\n */\n protected get renderedChildrenFilters(): Filter[] {\n return this.filter.children ?? [];\n }\n\n protected isFilterPartiallySelected(filter: HierarchicalFilterModel): boolean {\n const selectedChildren = filter.children?.filter(filter => filter.selected);\n const filterChildrenLength = filter.children?.length ?? 0;\n return (\n !!selectedChildren &&\n ((selectedChildren.length > 0 && selectedChildren.length < filterChildrenLength) ||\n // eslint-disable-next-line @typescript-eslint/unbound-method\n selectedChildren.some(this.isFilterPartiallySelected))\n );\n }\n }\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nA list of events that the component will emit:\n\n- [`UserClickedAFilter`](x-components.xeventstypes.userclickedafilter.md): the event is emitted\n after the user clicks the button, using the `filter` prop as its payload.\n- [`UserClickedAHierarchicalFilter`](x-components.xeventstypes.userclickedahierarchicalfilter.md):\n the event is emitted after the user clicks the button, using the `filter` prop as its payload.\n filter.\n\n## See it in action\n\nThis component renders a button, which on clicked emits the `UserClickedAFilter` and\n`UserClickedAHierarchicalFilter` events. By default it renders the filter label as the button text.\nIf the provided filter has children filters, this component will render them recursively. Changing\nthe slot content will change it for all of the children.\n\nThe `filter` prop is required. The `clickEvents` prop is optional and allows configuring the events\nto emit on click.\n\n```vue\n<template>\n <HierarchicalFilter :filter=\"filter\" />\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n\n### Playing with props\n\nConfiguring the events to emit when the filter is clicked.\n\n```vue\n<template>\n <HierarchicalFilter :clickEvents=\"{ UserClickedAHierarchicalFilter: filter }\" :filter=\"filter\" />\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n\n### Customizing the default slot content\n\nIn this example, the child filters will also include the label and checkbox.\n\n```vue\n<template>\n <HierarchicalFilter :filter=\"filter\" v-slot=\"{ filter, clickFilter, slotCSSClasses, isDisabled }\">\n <label :class=\"slotCSSClasses\">\n <input @change=\"clickFilter\" :disabled=\"isDisabled\" />\n {{ filter.label }}\n </label>\n </HierarchicalFilter>\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n\n### Customizing the label slot content\n\n```vue\n<template>\n <HierarchicalFilter :filter=\"filter\">\n <template #label :filter=\"filter\">\n <span class=\"custom-class\">{{ filter.label }}</span>\n </template>\n </HierarchicalFilter>\n</template>\n\n<script>\n import { HierarchicalFilter } from '@empathyco/x-components/facets';\n\n export default {\n name: 'HierarchicalFilterTest',\n components: {\n HierarchicalFilter\n },\n date() {\n return {\n filter: {\n id: `categories:men`,\n modelName: 'HierarchicalFilter',\n label: `men`,\n facetId: 'categories',\n parentId: null,\n totalResults: 10,\n children: [],\n selected: false\n }\n };\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}