@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.
- package/CHANGELOG.md +45 -0
- package/design-system/default-theme.css +28 -28
- package/design-system/full-theme.css +53 -54
- package/docs/API-reference/api/x-adapter-platform.md +0 -1
- package/docs/API-reference/api/x-adapter-platform.searchresponsemapper.md +1 -11
- package/docs/API-reference/api/x-components.facetsmutations.md +1 -1
- package/docs/API-reference/api/x-components.facetsmutations.mutatefilter.md +24 -0
- package/docs/API-reference/api/x-components.flathierarchicalfilters.md +26 -0
- package/docs/API-reference/api/x-components.md +2 -0
- package/docs/API-reference/api/x-components.mutatefilterpayload.filter.md +13 -0
- package/docs/API-reference/api/x-components.mutatefilterpayload.md +21 -0
- package/docs/API-reference/api/x-components.mutatefilterpayload.newfilterstate.md +13 -0
- package/docs/API-reference/api/x-types.hierarchicalfilter.children.md +2 -2
- package/docs/API-reference/api/x-types.hierarchicalfilter.md +2 -2
- package/docs/API-reference/api/x-types.hierarchicalfilter.parentid.md +1 -1
- package/docs/build-search-ui/web-archetype-development-guide.md +10 -7
- package/docs/build-search-ui/web-archetype-integration-guide.md +15 -14
- package/docs/build-search-ui/web-x-components-development-guide.md +5 -4
- package/docs/experience-search-&-discovery/README.md +119 -0
- package/docs/experience-search-&-discovery/empathize.md +102 -0
- package/docs/experience-search-&-discovery/facets-and-filters.md +138 -0
- package/docs/experience-search-&-discovery/history-queries.md +56 -0
- package/docs/experience-search-&-discovery/id-results.md +40 -0
- package/docs/experience-search-&-discovery/next-queries.md +52 -0
- package/docs/experience-search-&-discovery/popular-searches.md +32 -0
- package/docs/experience-search-&-discovery/product-results-ui.md +68 -0
- package/docs/experience-search-&-discovery/query-suggestions.md +32 -0
- package/docs/experience-search-&-discovery/recommendations.md +32 -0
- package/docs/experience-search-&-discovery/related-tags.md +41 -0
- package/docs/experience-search-&-discovery/search-box.md +81 -0
- package/docs/experience-search-&-discovery/serp-ui.md +109 -0
- package/docs/experience-search-&-discovery/web-local-storage.md +25 -0
- package/facets/index.js +1 -1
- package/js/index.js +1 -1
- package/js/x-modules/facets/components/facets/facets-provider.vue.js +2 -2
- package/js/x-modules/facets/components/facets/facets-provider.vue.js.map +1 -1
- package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js +7 -2
- package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/hierarchical-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/hierarchical-filter.vue_rollup-plugin-vue_script.vue.js +2 -130
- package/js/x-modules/facets/components/filters/hierarchical-filter.vue_rollup-plugin-vue_script.vue.js.map +1 -1
- package/js/x-modules/facets/entities/editable-number-range-filter.entity.js +11 -10
- package/js/x-modules/facets/entities/editable-number-range-filter.entity.js.map +1 -1
- package/js/x-modules/facets/entities/hierarchical-filter.entity.js +9 -11
- package/js/x-modules/facets/entities/hierarchical-filter.entity.js.map +1 -1
- package/js/x-modules/facets/entities/number-range-filter.entity.js +2 -2
- package/js/x-modules/facets/entities/number-range-filter.entity.js.map +1 -1
- package/js/x-modules/facets/entities/raw-filter.entity.js +1 -1
- package/js/x-modules/facets/entities/raw-filter.entity.js.map +1 -1
- package/js/x-modules/facets/entities/simple-filter.entity.js +2 -2
- package/js/x-modules/facets/entities/simple-filter.entity.js.map +1 -1
- package/js/x-modules/facets/entities/single-select.modifier.js +1 -1
- package/js/x-modules/facets/entities/single-select.modifier.js.map +1 -1
- package/js/x-modules/facets/service/facets.service.js +18 -2
- package/js/x-modules/facets/service/facets.service.js.map +1 -1
- package/js/x-modules/facets/store/module.js +4 -3
- package/js/x-modules/facets/store/module.js.map +1 -1
- package/js/x-modules/facets/utils.js +16 -1
- package/js/x-modules/facets/utils.js.map +1 -1
- package/js/x-modules/search-box/components/search-input.vue.js +54 -45
- package/js/x-modules/search-box/components/search-input.vue.js.map +1 -1
- package/js/x-modules/search-box/components/search-input.vue_rollup-plugin-vue_script.vue.js.map +1 -1
- package/package.json +4 -4
- package/report/x-adapter-platform.api.json +5 -133
- package/report/x-components.api.json +181 -45
- package/report/x-components.api.md +14 -5
- package/report/x-types.api.json +5 -5
- package/types/x-modules/facets/components/facets/facets-provider.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts +0 -6
- package/types/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts.map +1 -1
- package/types/x-modules/facets/entities/editable-number-range-filter.entity.d.ts +1 -1
- package/types/x-modules/facets/entities/editable-number-range-filter.entity.d.ts.map +1 -1
- package/types/x-modules/facets/entities/hierarchical-filter.entity.d.ts +2 -1
- package/types/x-modules/facets/entities/hierarchical-filter.entity.d.ts.map +1 -1
- package/types/x-modules/facets/entities/single-select.modifier.d.ts.map +1 -1
- package/types/x-modules/facets/service/facets.service.d.ts +13 -0
- package/types/x-modules/facets/service/facets.service.d.ts.map +1 -1
- package/types/x-modules/facets/store/module.d.ts.map +1 -1
- package/types/x-modules/facets/store/types.d.ts +22 -6
- package/types/x-modules/facets/store/types.d.ts.map +1 -1
- package/types/x-modules/facets/utils.d.ts +11 -0
- package/types/x-modules/facets/utils.d.ts.map +1 -1
- package/types/x-modules/search-box/components/search-input.vue.d.ts.map +1 -1
- package/docs/API-reference/api/x-adapter-platform.searchresponsefacetsmapper.md +0 -27
- package/docs/API-reference/api/x-components.facetsmutations.setfilter.md +0 -24
- 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
|
+

|
|
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 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 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 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
|
+

|
|
12
|
+
|
|
13
|
+
<FootNote>
|
|
14
|
+
|
|
15
|
+
**X 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 X for web _doesn't use cookies_ for storing data. The
|
|
14
|
+
Interface X 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 X 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-
|
|
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-
|
|
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',
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/js/x-modules/facets/components/facets/facets-provider.vue_rollup-plugin-vue_script.vue.js
CHANGED
|
@@ -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
|
-
|
|
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',
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|