@empathyco/x-components 6.1.4 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/ai/index.js +0 -1
- package/core/index.js.map +1 -1
- package/docs/API-reference/api/x-components.aicarousel.md +24 -28
- package/docs/API-reference/api/x-components.aimutations.md +1 -58
- package/docs/API-reference/api/x-components.aimutations.setexcludedresultids.md +1 -1
- package/docs/API-reference/api/x-components.aistate.md +0 -55
- package/docs/API-reference/api/x-components.aixevents.md +3 -3
- package/docs/API-reference/api/{x-components.aixevents.userclickedaioverviewexpandbutton.md → x-components.aixevents.userclickedanaicarouseladd2cart.md} +3 -3
- package/docs/API-reference/api/{x-components.aixevents.userclickedanaioverviewresult.md → x-components.aixevents.userclickedanaicarouselresult.md} +3 -3
- package/docs/API-reference/api/x-components.hierarchicalfilter.md +2 -2
- package/docs/API-reference/api/x-components.md +0 -9
- package/docs/API-reference/api/x-components.simplefilter.md +2 -2
- package/docs/API-reference/api/x-components.slidingpanel.md +9 -0
- package/docs/API-reference/api/x-components.snippetcallbacks.md +2 -2
- package/docs/API-reference/components/ai/x-components.ai-carousel.md +9 -7
- package/docs/API-reference/components/ai/x-components.ai-grouped-carousel.md +25 -0
- package/docs/API-reference/components/common/x-components.display-click-provider.md +1 -1
- package/docs/API-reference/components/common/x-components.sliding-panel.md +1 -0
- package/js/components/display-click-provider.vue.js +3 -3
- package/js/components/display-click-provider.vue.js.map +1 -1
- package/js/components/icons/spinner.vue.js +2 -2
- package/js/components/sliding-panel.vue.js +1 -1
- package/js/components/sliding-panel.vue.js.map +1 -1
- package/js/components/sliding-panel.vue2.js +7 -0
- package/js/components/sliding-panel.vue2.js.map +1 -1
- package/js/index.js +0 -1
- package/js/index.js.map +1 -1
- package/js/x-modules/ai/components/ai-carousel.vue.js +121 -66
- package/js/x-modules/ai/components/ai-carousel.vue.js.map +1 -1
- package/js/x-modules/ai/components/ai-carousel.vue2.js +18 -17
- package/js/x-modules/ai/components/ai-carousel.vue2.js.map +1 -1
- package/js/x-modules/ai/components/ai-carousel.vue3.js +1 -1
- package/js/x-modules/ai/components/ai-grouped-carousel.vue.js +68 -0
- package/js/x-modules/ai/components/ai-grouped-carousel.vue.js.map +1 -0
- package/js/x-modules/ai/components/{ai-overview.vue2.js → ai-grouped-carousel.vue2.js} +24 -86
- package/js/x-modules/ai/components/ai-grouped-carousel.vue2.js.map +1 -0
- package/js/x-modules/ai/store/actions/fetch-and-save-ai-suggestions.action.js +2 -10
- package/js/x-modules/ai/store/actions/fetch-and-save-ai-suggestions.action.js.map +1 -1
- package/js/x-modules/ai/store/module.js +6 -18
- package/js/x-modules/ai/store/module.js.map +1 -1
- package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue.js +2 -1
- package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue.js.map +1 -1
- package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue2.js.map +1 -1
- package/js/x-modules/tagging/wiring.js +2 -2
- package/js/x-modules/tagging/wiring.js.map +1 -1
- package/package.json +2 -3
- package/report/x-components.api.json +122 -711
- package/report/x-components.api.md +46 -128
- package/types/src/components/sliding-panel.vue.d.ts +15 -0
- package/types/src/components/sliding-panel.vue.d.ts.map +1 -1
- package/types/src/components/snippet-callbacks.vue.d.ts +2 -2
- package/types/src/x-modules/ai/components/ai-carousel.vue.d.ts +24 -28
- package/types/src/x-modules/ai/components/ai-carousel.vue.d.ts.map +1 -1
- package/types/src/x-modules/ai/components/ai-grouped-carousel.vue.d.ts +19 -0
- package/types/src/x-modules/ai/components/ai-grouped-carousel.vue.d.ts.map +1 -0
- package/types/src/x-modules/ai/components/index.d.ts +0 -1
- package/types/src/x-modules/ai/components/index.d.ts.map +1 -1
- package/types/src/x-modules/ai/events.types.d.ts +2 -2
- package/types/src/x-modules/ai/events.types.d.ts.map +1 -1
- package/types/src/x-modules/ai/store/actions/fetch-and-save-ai-suggestions.action.d.ts.map +1 -1
- package/types/src/x-modules/ai/store/module.d.ts.map +1 -1
- package/types/src/x-modules/ai/store/types.d.ts +6 -29
- package/types/src/x-modules/ai/store/types.d.ts.map +1 -1
- package/types/src/x-modules/facets/components/filters/hierarchical-filter.vue.d.ts +2 -2
- package/types/src/x-modules/facets/components/filters/simple-filter.vue.d.ts +2 -2
- package/types/src/x-modules/tagging/wiring.d.ts +2 -2
- package/docs/API-reference/api/x-components.aimutations.setisnoresults.md +0 -13
- package/docs/API-reference/api/x-components.aimutations.setresponsetext.md +0 -13
- package/docs/API-reference/api/x-components.aimutations.setsuggestiontext.md +0 -13
- package/docs/API-reference/api/x-components.aioverview.md +0 -88
- package/docs/API-reference/api/x-components.aistate.isnoresults.md +0 -13
- package/docs/API-reference/api/x-components.aistate.responsetext.md +0 -13
- package/docs/API-reference/api/x-components.aistate.suggestiontext.md +0 -11
- package/docs/API-reference/components/ai/x-components.ai-overview.md +0 -96
- package/js/x-modules/ai/components/ai-overview.vue.js +0 -267
- package/js/x-modules/ai/components/ai-overview.vue.js.map +0 -1
- package/js/x-modules/ai/components/ai-overview.vue2.js.map +0 -1
- package/js/x-modules/ai/components/ai-overview.vue3.js +0 -7
- package/js/x-modules/ai/components/ai-overview.vue3.js.map +0 -1
- package/types/src/x-modules/ai/components/ai-overview.vue.d.ts +0 -81
- package/types/src/x-modules/ai/components/ai-overview.vue.d.ts.map +0 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import _sfc_main from './ai-grouped-carousel.vue2.js';
|
|
2
|
+
import { resolveComponent, openBlock, createBlock, normalizeClass, withCtx, createElementVNode, createElementBlock, Fragment, renderList, renderSlot } from 'vue';
|
|
3
|
+
import _export_sfc from '../../../_virtual/_plugin-vue_export-helper.js';
|
|
4
|
+
|
|
5
|
+
const _hoisted_1 = { class: "x-ai-carousel-suggestion-results" };
|
|
6
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
7
|
+
const _component_DisplayClickProvider = resolveComponent("DisplayClickProvider");
|
|
8
|
+
const _component_SlidingPanel = resolveComponent("SlidingPanel");
|
|
9
|
+
return openBlock(), createBlock(_component_SlidingPanel, {
|
|
10
|
+
class: normalizeClass(_ctx.slidingPanelClasses),
|
|
11
|
+
"scroll-container-class": _ctx.slidingPanelContainerClasses,
|
|
12
|
+
"button-class": _ctx.slidingPanelButtonsClasses,
|
|
13
|
+
"reset-on-content-change": false
|
|
14
|
+
}, {
|
|
15
|
+
"sliding-panel-addons": withCtx(({ arrivedState }) => [
|
|
16
|
+
renderSlot(_ctx.$slots, "sliding-panels-addons", { arrivedState })
|
|
17
|
+
]),
|
|
18
|
+
"sliding-panel-left-button": withCtx(() => [
|
|
19
|
+
renderSlot(_ctx.$slots, "sliding-panels-left-button")
|
|
20
|
+
]),
|
|
21
|
+
"sliding-panel-right-button": withCtx(() => [
|
|
22
|
+
renderSlot(_ctx.$slots, "sliding-panels-right-button")
|
|
23
|
+
]),
|
|
24
|
+
default: withCtx(() => [
|
|
25
|
+
createElementVNode("ul", _hoisted_1, [
|
|
26
|
+
(openBlock(true), createElementBlock(
|
|
27
|
+
Fragment,
|
|
28
|
+
null,
|
|
29
|
+
renderList(_ctx.suggestionsSearch, (suggestion) => {
|
|
30
|
+
return openBlock(), createBlock(_component_DisplayClickProvider, {
|
|
31
|
+
key: suggestion.query,
|
|
32
|
+
"tooling-display-tagging": _ctx.tagging?.searchQueries[suggestion.query].toolingDisplayClick,
|
|
33
|
+
"tooling-add2-cart-tagging": _ctx.tagging?.searchQueries[suggestion.query].toolingDisplayAdd2Cart,
|
|
34
|
+
"result-feature": "ai_carousel"
|
|
35
|
+
}, {
|
|
36
|
+
default: withCtx(() => [
|
|
37
|
+
(openBlock(true), createElementBlock(
|
|
38
|
+
Fragment,
|
|
39
|
+
null,
|
|
40
|
+
renderList(suggestion.results, (result) => {
|
|
41
|
+
return openBlock(), createElementBlock("li", {
|
|
42
|
+
key: result.id,
|
|
43
|
+
"data-test": "ai-carousel-suggestion-result"
|
|
44
|
+
}, [
|
|
45
|
+
renderSlot(_ctx.$slots, "result", { result })
|
|
46
|
+
]);
|
|
47
|
+
}),
|
|
48
|
+
128
|
|
49
|
+
/* KEYED_FRAGMENT */
|
|
50
|
+
))
|
|
51
|
+
]),
|
|
52
|
+
_: 2
|
|
53
|
+
/* DYNAMIC */
|
|
54
|
+
}, 1032, ["tooling-display-tagging", "tooling-add2-cart-tagging"]);
|
|
55
|
+
}),
|
|
56
|
+
128
|
|
57
|
+
/* KEYED_FRAGMENT */
|
|
58
|
+
))
|
|
59
|
+
])
|
|
60
|
+
]),
|
|
61
|
+
_: 3
|
|
62
|
+
/* FORWARDED */
|
|
63
|
+
}, 8, ["class", "scroll-container-class", "button-class"]);
|
|
64
|
+
}
|
|
65
|
+
var AiGroupedCarousel = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
66
|
+
|
|
67
|
+
export { AiGroupedCarousel as default };
|
|
68
|
+
//# sourceMappingURL=ai-grouped-carousel.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-grouped-carousel.vue.js","sources":["../../../../../src/x-modules/ai/components/ai-grouped-carousel.vue"],"sourcesContent":["<template>\n <SlidingPanel\n :class=\"slidingPanelClasses\"\n :scroll-container-class=\"slidingPanelContainerClasses\"\n :button-class=\"slidingPanelButtonsClasses\"\n :reset-on-content-change=\"false\"\n >\n <template #sliding-panel-addons=\"{ arrivedState }\">\n <slot name=\"sliding-panels-addons\" :arrived-state=\"arrivedState\" />\n </template>\n <template #sliding-panel-left-button>\n <slot name=\"sliding-panels-left-button\" />\n </template>\n <template #sliding-panel-right-button>\n <slot name=\"sliding-panels-right-button\" />\n </template>\n <ul class=\"x-ai-carousel-suggestion-results\">\n <DisplayClickProvider\n v-for=\"suggestion in suggestionsSearch\"\n :key=\"suggestion.query\"\n :tooling-display-tagging=\"tagging?.searchQueries[suggestion.query].toolingDisplayClick\"\n :tooling-add2-cart-tagging=\"tagging?.searchQueries[suggestion.query].toolingDisplayAdd2Cart\"\n result-feature=\"ai_carousel\"\n >\n <li\n v-for=\"result in suggestion.results\"\n :key=\"result.id\"\n data-test=\"ai-carousel-suggestion-result\"\n >\n <!-- @slot (required) result card -->\n <slot name=\"result\" :result=\"result\" />\n </li>\n </DisplayClickProvider>\n </ul>\n </SlidingPanel>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { DisplayClickProvider, SlidingPanel } from '../../../components'\nimport { useState } from '../../../composables'\n\nexport default defineComponent({\n components: {\n DisplayClickProvider,\n SlidingPanel,\n },\n props: {\n /* The title text displayed */\n title: String,\n /* The classes added to the sliding panel. */\n slidingPanelClasses: String,\n /* The classes added to the sliding panel container. */\n slidingPanelContainerClasses: String,\n /* The classes added to the sliding panel buttons. */\n slidingPanelButtonsClasses: String,\n },\n setup() {\n const { suggestionsSearch, tagging } = useState('ai')\n\n return {\n suggestionsSearch,\n tagging,\n }\n },\n})\n</script>\n"],"names":["_createBlock","_normalizeClass","_withCtx","_renderSlot","_createElementVNode","_openBlock","_createElementBlock","_Fragment","_renderList"],"mappings":";;;;AAgBQ,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,kCAAA,EAAkC;;;;sBAf9CA,WAAA,CAiCe,uBAAA,EAAA;AAAA,IAhCZ,KAAA,EAAKC,eAAE,IAAA,CAAA,mBAAmB,CAAA;AAAA,IAC1B,wBAAA,EAAwB,IAAA,CAAA,4BAAA;AAAA,IACxB,cAAA,EAAc,IAAA,CAAA,0BAAA;AAAA,IACd,yBAAA,EAAyB;AAAA,GAAA,EAAA;IAEf,sBAAA,EAAoBC,OAAA,CAC7B,CAAmE,EADlC,YAAA,EAAY,KAAA;AAAA,MAC7CC,UAAA,CAAmE,wCAA/B,YAAA,EAA2B;AAAA,KAAA,CAAA;AAEtD,IAAA,2BAAA,EAAyBD,QAClC,MAA0C;AAAA,MAA1CC,UAAA,CAA0C,IAAA,CAAA,MAAA,EAAA,4BAAA;AAAA,KAAA,CAAA;AAEjC,IAAA,4BAAA,EAA0BD,QACnC,MAA2C;AAAA,MAA3CC,UAAA,CAA2C,IAAA,CAAA,MAAA,EAAA,6BAAA;AAAA,KAAA,CAAA;qBAE7C,MAiBK;AAAA,MAjBLC,kBAAA,CAiBK,MAjBL,UAAA,EAiBK;AAAA,SAAAC,SAAA,CAAA,IAAA,CAAA,EAhBHC,kBAAA;AAAA,UAeuBC,QAAA;AAAA,UAAA,IAAA;AAAA,UAAAC,UAAA,CAdA,IAAA,CAAA,iBAAA,EAAiB,CAA/B,UAAA,KAAU;gCADnBR,WAAA,CAeuB,+BAAA,EAAA;AAAA,cAbpB,KAAK,UAAA,CAAW,KAAA;AAAA,cAChB,yBAAA,EAAyB,IAAA,CAAA,OAAA,EAAS,aAAA,CAAc,UAAA,CAAW,KAAK,CAAA,CAAE,mBAAA;AAAA,cAClE,2BAAA,EAA2B,IAAA,CAAA,OAAA,EAAS,aAAA,CAAc,UAAA,CAAW,KAAK,CAAA,CAAE,sBAAA;AAAA,cACrE,gBAAA,EAAe;AAAA,aAAA,EAAA;+BAGb,MAAoC;AAAA,iBAAAK,SAAA,CAAA,IAAA,CAAA,EADtCC,kBAAA;AAAA,kBAOKC,QAAA;AAAA,kBAAA,IAAA;AAAA,kBAAAC,UAAA,CANc,UAAA,CAAW,OAAA,EAAO,CAA5B,MAAA,KAAM;wCADfF,kBAAA,CAOK,IAAA,EAAA;AAAA,sBALF,KAAK,MAAA,CAAO,EAAA;AAAA,sBACb,WAAA,EAAU;AAAA,qBAAA,EAAA;AAGV,sBAAAH,UAAA,CAAuC,yBAAlB,MAAA,EAAc;AAAA,qBAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { defineComponent, ref, computed, onMounted } from 'vue';
|
|
1
|
+
import { defineComponent } from 'vue';
|
|
3
2
|
import '../../../components/animations/animate-clip-path.vue2.js';
|
|
4
3
|
import '../../../components/animations/animate-scale.vue2.js';
|
|
5
4
|
import '../../../components/animations/animate-translate.vue2.js';
|
|
6
5
|
import '../../../components/animations/animate-width.vue2.js';
|
|
7
6
|
import '../../../components/animations/animate-width.vue3.js';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
7
|
+
import '../../../components/animations/change-height.vue2.js';
|
|
8
|
+
import '../../../components/animations/change-height.vue3.js';
|
|
9
|
+
import '../../../components/animations/collapse-height.vue2.js';
|
|
10
|
+
import '../../../components/animations/collapse-height.vue3.js';
|
|
10
11
|
import '../../../components/animations/collapse-width.vue2.js';
|
|
11
12
|
import '../../../components/animations/collapse-width.vue3.js';
|
|
12
13
|
import '../../../components/animations/cross-fade.vue2.js';
|
|
13
14
|
import '../../../components/animations/cross-fade.vue3.js';
|
|
14
15
|
import '../../../components/animations/fade-and-slide.vue2.js';
|
|
15
16
|
import '../../../components/animations/fade-and-slide.vue3.js';
|
|
16
|
-
import
|
|
17
|
+
import '../../../components/animations/fade.vue2.js';
|
|
18
|
+
import '../../../components/animations/fade.vue3.js';
|
|
17
19
|
import '../../../components/animations/no-animation.vue.js';
|
|
18
20
|
import '../../../components/animations/staggered-fade-and-slide.vue2.js';
|
|
19
21
|
import '../../../components/animations/staggered-fade-and-slide.vue3.js';
|
|
@@ -21,7 +23,7 @@ import '../../../components/auto-progress-bar.vue2.js';
|
|
|
21
23
|
import '../../../components/auto-progress-bar.vue3.js';
|
|
22
24
|
import '../../../components/base-dropdown.vue2.js';
|
|
23
25
|
import '../../../components/base-dropdown.vue3.js';
|
|
24
|
-
import
|
|
26
|
+
import '../../../components/base-event-button.vue2.js';
|
|
25
27
|
import '../../../components/base-grid.vue2.js';
|
|
26
28
|
import '../../../components/base-grid.vue3.js';
|
|
27
29
|
import '../../../components/base-keyboard-navigation.vue2.js';
|
|
@@ -37,14 +39,11 @@ import '../../../components/column-picker/base-column-picker-dropdown.vue2.js';
|
|
|
37
39
|
import '../../../components/column-picker/base-column-picker-list.vue2.js';
|
|
38
40
|
import '../../../components/currency/base-currency.vue2.js';
|
|
39
41
|
import _sfc_main$1 from '../../../components/display-click-provider.vue.js';
|
|
40
|
-
import
|
|
42
|
+
import '../../../components/display-emitter.vue.js';
|
|
41
43
|
import '../../../components/filters/labels/base-price-filter-label.vue.js';
|
|
42
44
|
import '../../../components/filters/labels/base-rating-filter-label.vue2.js';
|
|
43
45
|
import '../../../components/global-x-bus.vue.js';
|
|
44
46
|
import '../../../components/highlight.vue2.js';
|
|
45
|
-
import AIStarIcon from '../../../components/icons/ai-star.vue.js';
|
|
46
|
-
import ArrowRightIcon from '../../../components/icons/arrow-right.vue.js';
|
|
47
|
-
import SpinnerIcon from '../../../components/icons/spinner.vue.js';
|
|
48
47
|
import '../../../components/items-list.vue2.js';
|
|
49
48
|
import '../../../components/location-provider.vue.js';
|
|
50
49
|
import '../../../components/modals/base-events-modal-close.vue2.js';
|
|
@@ -83,103 +82,42 @@ import '../../../components/result/result-variant-selector.vue3.js';
|
|
|
83
82
|
import '../../../components/result/result-variants-provider.vue.js';
|
|
84
83
|
import '../../../components/scroll/base-scroll.vue2.js';
|
|
85
84
|
import '@empathyco/x-utils';
|
|
86
|
-
import
|
|
85
|
+
import 'vuex';
|
|
86
|
+
import '../../../plugins/x-bus.js';
|
|
87
|
+
import '../../../plugins/x-plugin.js';
|
|
88
|
+
import 'rxjs';
|
|
87
89
|
import SlidingPanel from '../../../components/sliding-panel.vue.js';
|
|
88
90
|
import '../../../components/snippet-callbacks.vue2.js';
|
|
89
91
|
import '../../../components/suggestions/base-suggestion.vue2.js';
|
|
90
92
|
import '../../../components/suggestions/base-suggestions.vue2.js';
|
|
91
93
|
import '../../../components/suggestions/base-suggestions.vue3.js';
|
|
92
94
|
import '../../../composables/create-use-device.js';
|
|
93
|
-
import 'vuex';
|
|
94
|
-
import '../../../plugins/x-bus.js';
|
|
95
|
-
import '../../../plugins/x-plugin.js';
|
|
96
95
|
import '@vueuse/core';
|
|
97
|
-
import 'rxjs';
|
|
98
96
|
import { useState } from '../../../composables/use-state.js';
|
|
99
|
-
import { typing } from '../../../directives/typing.js';
|
|
100
|
-
import { aiXModule } from '../x-module.js';
|
|
101
97
|
|
|
102
98
|
var _sfc_main = defineComponent({
|
|
103
|
-
directives: {
|
|
104
|
-
typing,
|
|
105
|
-
},
|
|
106
|
-
xModule: aiXModule.name,
|
|
107
99
|
components: {
|
|
108
|
-
AIStarIcon,
|
|
109
|
-
ArrowRightIcon,
|
|
110
|
-
BaseEventButton,
|
|
111
|
-
CollapseHeight,
|
|
112
|
-
ChangeHeight,
|
|
113
|
-
Fade,
|
|
114
|
-
SlidingPanel,
|
|
115
|
-
SpinnerIcon,
|
|
116
|
-
DisplayEmitter: _sfc_main$2,
|
|
117
100
|
DisplayClickProvider: _sfc_main$1,
|
|
101
|
+
SlidingPanel,
|
|
118
102
|
},
|
|
119
103
|
props: {
|
|
120
|
-
/* The text displayed
|
|
121
|
-
title:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
/* The
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
},
|
|
129
|
-
/* Auto expand the AI Overview when there are queries in AI and no-results in search. */
|
|
130
|
-
autoExpandInSearchNoResults: {
|
|
131
|
-
type: Boolean,
|
|
132
|
-
default: true,
|
|
133
|
-
},
|
|
134
|
-
/* The classes added to the parsed response text container. */
|
|
135
|
-
contentClasses: {
|
|
136
|
-
type: String,
|
|
137
|
-
},
|
|
138
|
-
/* The classes added to each sliding panel for each query. */
|
|
139
|
-
slidingPanelsClasses: {
|
|
140
|
-
type: String,
|
|
141
|
-
},
|
|
142
|
-
/* The classes added to each sliding panel container of each query. */
|
|
143
|
-
slidingPanelContainersClasses: {
|
|
144
|
-
type: String,
|
|
145
|
-
},
|
|
146
|
-
/* The classes added to each sliding panel button of each query. */
|
|
147
|
-
slidingPanelButtonsClasses: {
|
|
148
|
-
type: String,
|
|
149
|
-
},
|
|
104
|
+
/* The title text displayed */
|
|
105
|
+
title: String,
|
|
106
|
+
/* The classes added to the sliding panel. */
|
|
107
|
+
slidingPanelClasses: String,
|
|
108
|
+
/* The classes added to the sliding panel container. */
|
|
109
|
+
slidingPanelContainerClasses: String,
|
|
110
|
+
/* The classes added to the sliding panel buttons. */
|
|
111
|
+
slidingPanelButtonsClasses: String,
|
|
150
112
|
},
|
|
151
113
|
setup() {
|
|
152
|
-
const
|
|
153
|
-
const { suggestionText, responseText, suggestionsSearch, suggestionsStatus, tagging, isNoResults, queries, query, } = useState('ai');
|
|
154
|
-
const emptyTaggingRequest = { url: '', params: {} };
|
|
155
|
-
const aiOverviewRef = ref(null);
|
|
156
|
-
const expanded = ref(false);
|
|
157
|
-
const shouldAnimateSuggestion = ref(true);
|
|
158
|
-
const parsedResponseText = computed(() => marked.parse(responseText.value));
|
|
159
|
-
const suggestionsLoading = computed(() => suggestionsStatus.value !== 'success' && suggestionsStatus.value !== 'error');
|
|
160
|
-
$x.on('AiSuggestionsRequestUpdated', false).subscribe(() => {
|
|
161
|
-
expanded.value = false;
|
|
162
|
-
shouldAnimateSuggestion.value = true;
|
|
163
|
-
});
|
|
164
|
-
onMounted(() => {
|
|
165
|
-
$x.emit('AiComponentMounted', undefined, { feature: 'overview' });
|
|
166
|
-
});
|
|
114
|
+
const { suggestionsSearch, tagging } = useState('ai');
|
|
167
115
|
return {
|
|
168
|
-
aiOverviewRef,
|
|
169
|
-
emptyTaggingRequest,
|
|
170
|
-
expanded,
|
|
171
|
-
parsedResponseText,
|
|
172
|
-
suggestionsLoading,
|
|
173
116
|
suggestionsSearch,
|
|
174
|
-
suggestionText,
|
|
175
|
-
shouldAnimateSuggestion,
|
|
176
|
-
query,
|
|
177
117
|
tagging,
|
|
178
|
-
isNoResults,
|
|
179
|
-
queries,
|
|
180
118
|
};
|
|
181
119
|
},
|
|
182
120
|
});
|
|
183
121
|
|
|
184
122
|
export { _sfc_main as default };
|
|
185
|
-
//# sourceMappingURL=ai-
|
|
123
|
+
//# sourceMappingURL=ai-grouped-carousel.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-grouped-carousel.vue2.js","sources":["../../../../../src/x-modules/ai/components/ai-grouped-carousel.vue"],"sourcesContent":["<template>\n <SlidingPanel\n :class=\"slidingPanelClasses\"\n :scroll-container-class=\"slidingPanelContainerClasses\"\n :button-class=\"slidingPanelButtonsClasses\"\n :reset-on-content-change=\"false\"\n >\n <template #sliding-panel-addons=\"{ arrivedState }\">\n <slot name=\"sliding-panels-addons\" :arrived-state=\"arrivedState\" />\n </template>\n <template #sliding-panel-left-button>\n <slot name=\"sliding-panels-left-button\" />\n </template>\n <template #sliding-panel-right-button>\n <slot name=\"sliding-panels-right-button\" />\n </template>\n <ul class=\"x-ai-carousel-suggestion-results\">\n <DisplayClickProvider\n v-for=\"suggestion in suggestionsSearch\"\n :key=\"suggestion.query\"\n :tooling-display-tagging=\"tagging?.searchQueries[suggestion.query].toolingDisplayClick\"\n :tooling-add2-cart-tagging=\"tagging?.searchQueries[suggestion.query].toolingDisplayAdd2Cart\"\n result-feature=\"ai_carousel\"\n >\n <li\n v-for=\"result in suggestion.results\"\n :key=\"result.id\"\n data-test=\"ai-carousel-suggestion-result\"\n >\n <!-- @slot (required) result card -->\n <slot name=\"result\" :result=\"result\" />\n </li>\n </DisplayClickProvider>\n </ul>\n </SlidingPanel>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\nimport { DisplayClickProvider, SlidingPanel } from '../../../components'\nimport { useState } from '../../../composables'\n\nexport default defineComponent({\n components: {\n DisplayClickProvider,\n SlidingPanel,\n },\n props: {\n /* The title text displayed */\n title: String,\n /* The classes added to the sliding panel. */\n slidingPanelClasses: String,\n /* The classes added to the sliding panel container. */\n slidingPanelContainerClasses: String,\n /* The classes added to the sliding panel buttons. */\n slidingPanelButtonsClasses: String,\n },\n setup() {\n const { suggestionsSearch, tagging } = useState('ai')\n\n return {\n suggestionsSearch,\n tagging,\n }\n },\n})\n</script>\n"],"names":["DisplayClickProvider"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,gBAAe,eAAe,CAAC;AAC7B,IAAA,UAAU,EAAE;8BACVA,WAAoB;QACpB,YAAY;AACb,KAAA;AACD,IAAA,KAAK,EAAE;;AAEL,QAAA,KAAK,EAAE,MAAM;;AAEb,QAAA,mBAAmB,EAAE,MAAM;;AAE3B,QAAA,4BAA4B,EAAE,MAAM;;AAEpC,QAAA,0BAA0B,EAAE,MAAM;AACnC,KAAA;IACD,KAAK,GAAA;QACH,MAAM,EAAE,iBAAiB,EAAE,OAAM,EAAE,GAAI,QAAQ,CAAC,IAAI,CAAA;QAEpD,OAAO;YACL,iBAAiB;YACjB,OAAO;SACT;IACF,CAAC;AACF,CAAA,CAAA;;;;"}
|
|
@@ -27,8 +27,8 @@ const fetchAndSaveAiSuggestions = async ({ commit }, request) => {
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
};
|
|
30
|
-
function mapTaggingData(
|
|
31
|
-
const { toolingDisplay, toolingDisplayClick, searchQueries } =
|
|
30
|
+
function mapTaggingData(taggingData) {
|
|
31
|
+
const { toolingDisplay, toolingDisplayClick, searchQueries } = taggingData.tagging[0];
|
|
32
32
|
// TODO: Using the getTaggingInfoFromUrl util here is a temporary solution.
|
|
33
33
|
// It creates a dependency with the x-adapter-platform project that should be avoided.
|
|
34
34
|
return {
|
|
@@ -62,14 +62,6 @@ function readAnswer(reader, commit) {
|
|
|
62
62
|
continue;
|
|
63
63
|
const raw = line.startsWith('data:') ? line.slice(5).trim() : line.trim();
|
|
64
64
|
const data = JSON.parse(raw);
|
|
65
|
-
if ('suggestionText' in data) {
|
|
66
|
-
commit('setIsNoResults', false);
|
|
67
|
-
commit('setSuggestionText', data.suggestionText);
|
|
68
|
-
}
|
|
69
|
-
if ('responseText' in data) {
|
|
70
|
-
commit('setIsNoResults', false);
|
|
71
|
-
commit('setResponseText', data.responseText);
|
|
72
|
-
}
|
|
73
65
|
if ('queries' in data) {
|
|
74
66
|
commit('setQueries', data.queries);
|
|
75
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-and-save-ai-suggestions.action.js","sources":["../../../../../../src/x-modules/ai/store/actions/fetch-and-save-ai-suggestions.action.ts"],"sourcesContent":["import type { AiSuggestionQuery, AiSuggestionTagging } from '@empathyco/x-types'\nimport type { AiActionContext, AiXStoreModule } from '../types'\nimport { getTaggingInfoFromUrl } from '@empathyco/x-adapter-platform'\nimport { XPlugin } from '../../../../plugins'\n\ninterface TaggingData {\n tagging: {\n toolingDisplay: string\n toolingDisplayClick: string\n searchQueries: Record<\n string,\n {\n toolingDisplay: string\n toolingDisplayClick: string\n toolingDisplayAdd2Cart: string\n }\n >\n }[]\n}\n\ntype AnswerData
|
|
1
|
+
{"version":3,"file":"fetch-and-save-ai-suggestions.action.js","sources":["../../../../../../src/x-modules/ai/store/actions/fetch-and-save-ai-suggestions.action.ts"],"sourcesContent":["import type { AiSuggestionQuery, AiSuggestionTagging } from '@empathyco/x-types'\nimport type { AiActionContext, AiXStoreModule } from '../types'\nimport { getTaggingInfoFromUrl } from '@empathyco/x-adapter-platform'\nimport { XPlugin } from '../../../../plugins'\n\ninterface TaggingData {\n tagging: {\n toolingDisplay: string\n toolingDisplayClick: string\n searchQueries: Record<\n string,\n {\n toolingDisplay: string\n toolingDisplayClick: string\n toolingDisplayAdd2Cart: string\n }\n >\n }[]\n}\n\ntype AnswerData = { queries: AiSuggestionQuery[] } | TaggingData\n\n/**\n * Default implementation for the {@link AiActions.fetchAndSaveAiSuggestions}.\n *\n * @param _ - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the actions,\n * provided by Vuex.\n * @param request - The AI request to make.\n * @returns The AI response.\n * @public\n */\nexport const fetchAndSaveAiSuggestions: AiXStoreModule['actions']['fetchAndSaveAiSuggestions'] =\n async ({ commit }, request) => {\n if (!request) {\n return\n }\n commit('setSuggestionsStatus', 'loading')\n\n return XPlugin.adapter.aiSuggestions(request).then(({ body, status }) => {\n if (status !== 200) {\n return\n }\n if (body) {\n const reader = body.getReader()\n readAnswer(reader, commit)\n }\n })\n }\n\nfunction mapTaggingData(taggingData: TaggingData): AiSuggestionTagging {\n const { toolingDisplay, toolingDisplayClick, searchQueries } = taggingData.tagging[0]\n // TODO: Using the getTaggingInfoFromUrl util here is a temporary solution.\n // It creates a dependency with the x-adapter-platform project that should be avoided.\n return {\n toolingDisplay: getTaggingInfoFromUrl(toolingDisplay),\n toolingDisplayClick: getTaggingInfoFromUrl(toolingDisplayClick),\n searchQueries: Object.fromEntries(\n Object.entries(searchQueries).map(\n ([query, { toolingDisplay, toolingDisplayClick, toolingDisplayAdd2Cart }]) => [\n query,\n {\n toolingDisplay: getTaggingInfoFromUrl(toolingDisplay),\n toolingDisplayClick: getTaggingInfoFromUrl(toolingDisplayClick),\n toolingDisplayAdd2Cart: getTaggingInfoFromUrl(toolingDisplayAdd2Cart),\n },\n ],\n ),\n ),\n }\n}\n\nfunction readAnswer(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n commit: AiActionContext['commit'],\n): void {\n reader\n .read()\n .then(({ value, done }) => {\n if (done) {\n commit('setSuggestionsStatus', 'success')\n return\n }\n\n const result = new TextDecoder().decode(value, { stream: true })\n const parts = result.split('\\n\\n')\n for (const part of parts) {\n const lines = part.split('\\n')\n\n for (const line of lines) {\n // line.length check to avoid event lines or empty lines\n if (line.length <= 5 || line.startsWith('event:')) continue\n\n const raw = line.startsWith('data:') ? line.slice(5).trim() : line.trim()\n const data = JSON.parse(raw) as AnswerData\n\n if ('queries' in data) {\n commit('setQueries', data.queries)\n }\n if ('tagging' in data) {\n commit('setTagging', mapTaggingData(data))\n }\n }\n }\n readAnswer(reader, commit)\n })\n .catch((error: { code: number }) => {\n commit('setSuggestionsStatus', 'error')\n // AbortError code === 20\n if (error.code !== 20) {\n console.error(error)\n }\n })\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,9 @@ const aiXStoreModule = {
|
|
|
27
27
|
origin: null,
|
|
28
28
|
relatedTags: [],
|
|
29
29
|
searchTotalResults: 0,
|
|
30
|
+
excludeOptions: {
|
|
31
|
+
resultIds: [],
|
|
32
|
+
},
|
|
30
33
|
}),
|
|
31
34
|
getters: {
|
|
32
35
|
suggestionsRequest,
|
|
@@ -34,18 +37,9 @@ const aiXStoreModule = {
|
|
|
34
37
|
},
|
|
35
38
|
mutations: {
|
|
36
39
|
/* Streamed fields */
|
|
37
|
-
setResponseText: (state, responseText) => {
|
|
38
|
-
state.responseText = responseText;
|
|
39
|
-
},
|
|
40
|
-
setSuggestionText: (state, suggestionText) => {
|
|
41
|
-
state.suggestionText = suggestionText;
|
|
42
|
-
},
|
|
43
40
|
setQueries: (state, queries) => {
|
|
44
41
|
state.queries = queries;
|
|
45
42
|
},
|
|
46
|
-
setExcludedResultIds: (state, resultIds) => {
|
|
47
|
-
state.excludeOptions.resultIds = resultIds;
|
|
48
|
-
},
|
|
49
43
|
setTagging: (state, tagging) => {
|
|
50
44
|
state.tagging = tagging;
|
|
51
45
|
},
|
|
@@ -59,6 +53,9 @@ const aiXStoreModule = {
|
|
|
59
53
|
setSuggestionsSearchStatus: (state, status) => {
|
|
60
54
|
state.suggestionsSearchStatus = status;
|
|
61
55
|
},
|
|
56
|
+
setExcludedResultIds: (state, resultIds) => {
|
|
57
|
+
state.excludeOptions.resultIds = resultIds;
|
|
58
|
+
},
|
|
62
59
|
setQuery,
|
|
63
60
|
setParams(state, params) {
|
|
64
61
|
state.params = params;
|
|
@@ -72,9 +69,6 @@ const aiXStoreModule = {
|
|
|
72
69
|
setAiRelatedTags(state, relatedTags) {
|
|
73
70
|
state.relatedTags = relatedTags;
|
|
74
71
|
},
|
|
75
|
-
setIsNoResults(state, isNoResults) {
|
|
76
|
-
state.isNoResults = isNoResults;
|
|
77
|
-
},
|
|
78
72
|
setSelectedFilters(state, selectedFilters) {
|
|
79
73
|
state.selectedFilters = groupItemsBy(selectedFilters, filter => isFacetFilter(filter) ? filter.facetId : UNKNOWN_FACET_KEY);
|
|
80
74
|
},
|
|
@@ -101,17 +95,11 @@ const aiXStoreModule = {
|
|
|
101
95
|
*/
|
|
102
96
|
function resettableAiState() {
|
|
103
97
|
return {
|
|
104
|
-
responseText: '',
|
|
105
|
-
suggestionText: '',
|
|
106
98
|
queries: [],
|
|
107
|
-
excludeOptions: {
|
|
108
|
-
resultIds: [],
|
|
109
|
-
},
|
|
110
99
|
tagging: undefined,
|
|
111
100
|
suggestionsSearch: [],
|
|
112
101
|
suggestionsStatus: 'initial',
|
|
113
102
|
suggestionsSearchStatus: 'initial',
|
|
114
|
-
isNoResults: true,
|
|
115
103
|
};
|
|
116
104
|
}
|
|
117
105
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sources":["../../../../../src/x-modules/ai/store/module.ts"],"sourcesContent":["import type { AiSuggestionQuery, AiSuggestionSearch, Result } from '@empathyco/x-types'\nimport type { RequestStatus } from '../../../store/utils/status-store.utils'\nimport type { AiState, AiXStoreModule } from './types'\nimport { isFacetFilter } from '@empathyco/x-types'\nimport { mergeConfig, setConfig } from '../../../store/utils/config-store.utils'\nimport { setQuery } from '../../../store/utils/query.utils'\nimport { groupItemsBy } from '../../../utils/array'\nimport { UNKNOWN_FACET_KEY } from '../../facets/store/constants'\nimport { fetchAndSaveAiSuggestionsSearch } from './actions/fetch-and-save-ai-suggestions-search.action'\nimport { fetchAndSaveAiSuggestions } from './actions/fetch-and-save-ai-suggestions.action'\nimport { saveOrigin } from './actions/save-origin.action'\nimport { setUrlParams } from './actions/set-url-params.action'\nimport {\n aiSuggestionsRequest as suggestionsRequest,\n aiSuggestionsSearchRequest as suggestionsSearchRequest,\n} from './getters'\n\n/**\n * {@link XStoreModule} For the ai module.\n *\n * @internal\n */\nexport const aiXStoreModule: AiXStoreModule = {\n state: () => ({\n ...resettableAiState(),\n selectedFilters: {},\n query: '',\n config: {\n lowResultsThreshold: 50,\n },\n params: {},\n origin: null,\n relatedTags: [],\n searchTotalResults: 0,\n }),\n getters: {\n suggestionsRequest,\n suggestionsSearchRequest,\n },\n mutations: {\n /* Streamed fields */\n
|
|
1
|
+
{"version":3,"file":"module.js","sources":["../../../../../src/x-modules/ai/store/module.ts"],"sourcesContent":["import type { AiSuggestionQuery, AiSuggestionSearch, Result } from '@empathyco/x-types'\nimport type { RequestStatus } from '../../../store/utils/status-store.utils'\nimport type { AiState, AiXStoreModule } from './types'\nimport { isFacetFilter } from '@empathyco/x-types'\nimport { mergeConfig, setConfig } from '../../../store/utils/config-store.utils'\nimport { setQuery } from '../../../store/utils/query.utils'\nimport { groupItemsBy } from '../../../utils/array'\nimport { UNKNOWN_FACET_KEY } from '../../facets/store/constants'\nimport { fetchAndSaveAiSuggestionsSearch } from './actions/fetch-and-save-ai-suggestions-search.action'\nimport { fetchAndSaveAiSuggestions } from './actions/fetch-and-save-ai-suggestions.action'\nimport { saveOrigin } from './actions/save-origin.action'\nimport { setUrlParams } from './actions/set-url-params.action'\nimport {\n aiSuggestionsRequest as suggestionsRequest,\n aiSuggestionsSearchRequest as suggestionsSearchRequest,\n} from './getters'\n\n/**\n * {@link XStoreModule} For the ai module.\n *\n * @internal\n */\nexport const aiXStoreModule: AiXStoreModule = {\n state: () => ({\n ...resettableAiState(),\n selectedFilters: {},\n query: '',\n config: {\n lowResultsThreshold: 50,\n },\n params: {},\n origin: null,\n relatedTags: [],\n searchTotalResults: 0,\n excludeOptions: {\n resultIds: [],\n },\n }),\n getters: {\n suggestionsRequest,\n suggestionsSearchRequest,\n },\n mutations: {\n /* Streamed fields */\n setQueries: (state, queries: AiSuggestionQuery[]) => {\n state.queries = queries\n },\n setTagging: (state, tagging) => {\n state.tagging = tagging\n },\n /* END Streamed fields */\n setSuggestionsSearch: (state, suggestionsSearch: AiSuggestionSearch[]) => {\n state.suggestionsSearch = suggestionsSearch\n },\n setSuggestionsStatus: (state, status: RequestStatus) => {\n state.suggestionsStatus = status\n },\n setSuggestionsSearchStatus: (state, status: RequestStatus) => {\n state.suggestionsSearchStatus = status\n },\n setExcludedResultIds: (state, resultIds: Result['id'][]) => {\n state.excludeOptions.resultIds = resultIds\n },\n setQuery,\n setParams(state, params) {\n state.params = params\n },\n setOrigin(state, origin = null) {\n state.origin = origin\n },\n resetAiState(state) {\n Object.assign(state, resettableAiState())\n },\n setAiRelatedTags(state, relatedTags) {\n state.relatedTags = relatedTags\n },\n setSelectedFilters(state, selectedFilters) {\n state.selectedFilters = groupItemsBy(selectedFilters, filter =>\n isFacetFilter(filter) ? filter.facetId : UNKNOWN_FACET_KEY,\n )\n },\n setSearchTotalResults(state, totalResults) {\n state.searchTotalResults = totalResults\n },\n setConfig,\n mergeConfig,\n },\n actions: {\n fetchAndSaveAiSuggestions,\n fetchAndSaveAiSuggestionsSearch,\n setUrlParams,\n saveOrigin,\n },\n}\n\n/**\n * Function to return the \"resettable\" part of the state. This will be used in the `resetState`\n * mutation to reset to the initial state.\n *\n * @returns The \"resettable\" part of the {@link AiState}.\n *\n * @internal\n */\nfunction resettableAiState() {\n return {\n queries: [],\n tagging: undefined,\n suggestionsSearch: [],\n suggestionsStatus: 'initial' as RequestStatus,\n suggestionsSearchStatus: 'initial' as RequestStatus,\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAiBA;;;;AAIG;AACI,MAAM,cAAc,GAAmB;AAC5C,IAAA,KAAK,EAAE,OAAO;AACZ,QAAA,GAAG,iBAAiB,EAAE;AACtB,QAAA,eAAe,EAAE,EAAE;AACnB,QAAA,KAAK,EAAE,EAAE;AACT,QAAA,MAAM,EAAE;AACN,YAAA,mBAAmB,EAAE,EAAE;AACxB,SAAA;AACD,QAAA,MAAM,EAAE,EAAE;AACV,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,WAAW,EAAE,EAAE;AACf,QAAA,kBAAkB,EAAE,CAAC;AACrB,QAAA,cAAc,EAAE;AACd,YAAA,SAAS,EAAE,EAAE;AACd,SAAA;KACF,CAAC;AACF,IAAA,OAAO,EAAE;QACP,kBAAkB;QAClB,wBAAwB;AACzB,KAAA;AACD,IAAA,SAAS,EAAE;;AAET,QAAA,UAAU,EAAE,CAAC,KAAK,EAAE,OAA4B,KAAI;AAClD,YAAA,KAAK,CAAC,OAAO,GAAG,OAAO;QACzB,CAAC;AACD,QAAA,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAI;AAC7B,YAAA,KAAK,CAAC,OAAO,GAAG,OAAO;QACzB,CAAC;;AAED,QAAA,oBAAoB,EAAE,CAAC,KAAK,EAAE,iBAAuC,KAAI;AACvE,YAAA,KAAK,CAAC,iBAAiB,GAAG,iBAAiB;QAC7C,CAAC;AACD,QAAA,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAqB,KAAI;AACrD,YAAA,KAAK,CAAC,iBAAiB,GAAG,MAAM;QAClC,CAAC;AACD,QAAA,0BAA0B,EAAE,CAAC,KAAK,EAAE,MAAqB,KAAI;AAC3D,YAAA,KAAK,CAAC,uBAAuB,GAAG,MAAM;QACxC,CAAC;AACD,QAAA,oBAAoB,EAAE,CAAC,KAAK,EAAE,SAAyB,KAAI;AACzD,YAAA,KAAK,CAAC,cAAc,CAAC,SAAS,GAAG,SAAS;QAC5C,CAAC;QACD,QAAQ;QACR,SAAS,CAAC,KAAK,EAAE,MAAM,EAAA;AACrB,YAAA,KAAK,CAAC,MAAM,GAAG,MAAM;QACvB,CAAC;AACD,QAAA,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAA;AAC5B,YAAA,KAAK,CAAC,MAAM,GAAG,MAAM;QACvB,CAAC;AACD,QAAA,YAAY,CAAC,KAAK,EAAA;YAChB,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC;QAC3C,CAAC;QACD,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAA;AACjC,YAAA,KAAK,CAAC,WAAW,GAAG,WAAW;QACjC,CAAC;QACD,kBAAkB,CAAC,KAAK,EAAE,eAAe,EAAA;YACvC,KAAK,CAAC,eAAe,GAAG,YAAY,CAAC,eAAe,EAAE,MAAM,IAC1D,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,GAAG,iBAAiB,CAC3D;QACH,CAAC;QACD,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAA;AACvC,YAAA,KAAK,CAAC,kBAAkB,GAAG,YAAY;QACzC,CAAC;QACD,SAAS;QACT,WAAW;AACZ,KAAA;AACD,IAAA,OAAO,EAAE;QACP,yBAAyB;QACzB,+BAA+B;QAC/B,YAAY;QACZ,UAAU;AACX,KAAA;;AAGH;;;;;;;AAOG;AACH,SAAS,iBAAiB,GAAA;IACxB,OAAO;AACL,QAAA,OAAO,EAAE,EAAE;AACX,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,iBAAiB,EAAE,EAAE;AACrB,QAAA,iBAAiB,EAAE,SAA0B;AAC7C,QAAA,uBAAuB,EAAE,SAA0B;KACpD;AACH;;;;"}
|
|
@@ -10,6 +10,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
10
10
|
const _component_SlidingPanel = resolveComponent("SlidingPanel");
|
|
11
11
|
return openBlock(), createBlock(_component_SlidingPanel, {
|
|
12
12
|
key: _ctx.x.query.search,
|
|
13
|
+
fade: _ctx.selectedPromptIndex === -1,
|
|
13
14
|
"reset-on-content-change": false,
|
|
14
15
|
"button-class": _ctx.buttonClass,
|
|
15
16
|
"show-buttons": _ctx.showButtons && _ctx.selectedPromptIndex === -1,
|
|
@@ -93,7 +94,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
93
94
|
]),
|
|
94
95
|
_: 3
|
|
95
96
|
/* FORWARDED */
|
|
96
|
-
}, 8, ["button-class", "show-buttons", "scroll-container-class"]);
|
|
97
|
+
}, 8, ["fade", "button-class", "show-buttons", "scroll-container-class"]);
|
|
97
98
|
}
|
|
98
99
|
var relatedPromptsTagList = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
99
100
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"related-prompts-tag-list.vue.js","sources":["../../../../../src/x-modules/related-prompts/components/related-prompts-tag-list.vue"],"sourcesContent":["<template>\n <SlidingPanel\n :key=\"x.query.search\"\n :reset-on-content-change=\"false\"\n :button-class=\"buttonClass\"\n :show-buttons=\"showButtons && selectedPromptIndex === -1\"\n :scroll-container-class=\"[\n 'x-related-prompts-tag-list-scroll-container',\n scrollContainerClass || '',\n ]\"\n >\n <template #sliding-panel-left-button>\n <!--\n @slot sliding-panel-left-button - The button to be displayed on the left side of the sliding panel.\n -->\n <slot name=\"sliding-panel-left-button\" />\n </template>\n <transition-group\n class=\"x-related-prompts-tag-list\"\n :css=\"false\"\n tag=\"ul\"\n appear\n @before-enter=\"onBeforeEnter\"\n @enter=\"onEnter\"\n @leave=\"onLeave\"\n >\n <li\n v-for=\"{ index, ...relatedPrompt } in visibleRelatedPrompts\"\n ref=\"listItems\"\n :key=\"relatedPrompt.suggestionText\"\n class=\"x-related-prompts-tag-list-item\"\n :class=\"[tagClass, tagColors && tagColors[index % tagColors.length]]\"\n :data-index=\"index\"\n :style=\"{\n ...(selectedPromptIndex === index && { width: '100%' }),\n ...(isAnimating && { pointerEvents: 'none' }),\n }\"\n data-test=\"related-prompts-tag-list-item\"\n >\n <!--\n @slot - The slot to render related prompt information.\n @prop {Object} relatedPrompt - The related prompt object.\n @prop {Function} onSelect - The function to select the related prompt.\n @prop {Boolean} isSelected - Indicates if the related prompt is currently selected.\n -->\n <slot\n :related-prompt=\"relatedPrompt\"\n :on-select=\"() => onSelect(index)\"\n :is-selected=\"selectedPromptIndex === index\"\n >\n <DisplayEmitter\n :payload=\"relatedPrompt.tagging?.toolingDisplayTagging!\"\n :event-metadata=\"{\n feature: 'related-prompts',\n displayOriginalQuery: x.query.searchBox,\n replaceable: false,\n }\"\n >\n <RelatedPrompt\n :related-prompt=\"relatedPrompt\"\n :selected=\"selectedPromptIndex === index\"\n @click=\"onSelect(index)\"\n >\n <template #related-prompt-extra-content>\n <!--\n @slot related-prompt-extra-content - The slot to render related prompt extra information.\n @prop {Object} relatedPrompt - The related prompt object.\n -->\n <slot name=\"related-prompt-extra-content\" :related-prompt=\"relatedPrompt\" />\n </template>\n </RelatedPrompt>\n </DisplayEmitter>\n </slot>\n </li>\n </transition-group>\n <template #sliding-panel-right-button>\n <!--\n @slot sliding-panel-right-button - The button to be displayed on the right side of the sliding panel.\n -->\n <slot name=\"sliding-panel-right-button\" />\n </template>\n </SlidingPanel>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport { computed, defineComponent, onBeforeUnmount, ref } from 'vue'\nimport DisplayEmitter from '../../../components/display-emitter.vue'\nimport SlidingPanel from '../../../components/sliding-panel.vue'\nimport { use$x, useState } from '../../../composables'\nimport { relatedPromptsXModule } from '../x-module'\nimport RelatedPrompt from './related-prompt.vue'\n\n/**\n * This component shows the list of `RelatedPrompts` components.\n *\n * If the default slot is reimplemented in the consumer, `onSelect` function will be\n * necessary to handle the selection of the related prompt and to trigger the stagger-fade-slide animation.\n *\n * @public\n */\nexport default defineComponent({\n name: 'RelatedPromptsTagList',\n xModule: relatedPromptsXModule.name,\n components: { DisplayEmitter, RelatedPrompt, SlidingPanel },\n props: {\n /**\n * The CSS class for the left and right button of the sliding panel.\n *\n * @public\n */\n buttonClass: String,\n /**\n * The boolean prop to handle the visiblity of sliding pannel buttons.\n *\n * @public\n */\n showButtons: { type: Boolean, default: true },\n /**\n * The CSS class for the wrapper of all the related prompt wrapper elements.\n *\n * @public\n */\n scrollContainerClass: String,\n /**\n * The CSS class for all the related prompt wrapper elements.\n *\n * @public\n */\n tagClass: String,\n /**\n * Array of colors to apply to the related prompts. It will be applied to tag\n * elements cyclically according to their index in the nex way: `tagColors[index % tagColors.length]`.\n *\n * @public\n */\n tagColors: Array as PropType<string[]>,\n /**\n * The duration of the total animation in milliseconds.\n *\n * @public\n */\n animationDurationInMs: {\n type: Number,\n default: 700,\n },\n },\n setup(props) {\n const x = use$x()\n const { relatedPrompts, selectedPrompt: selectedPromptIndex } = useState('relatedPrompts')\n\n const clickedListItemIndex = ref<number | null>(null)\n const initialOffsetLefts: Record<number, number> = {}\n const isAnimating = ref(false)\n const listItems = ref<HTMLElement[]>([])\n\n const sortedListItems = computed<HTMLElement[]>(() =>\n [...listItems.value].sort(\n (a: HTMLElement, b: HTMLElement) =>\n Number.parseInt(b.getAttribute('data-index')!) -\n Number.parseInt(a.getAttribute('data-index')!),\n ),\n )\n\n // The duration of a single animation (enter or leave) in milliseconds\n // if a related prompt is clicked (clickedListItemIndex.value !== null), the duration is divided by the number of related\n // prompts -1 (the clicked one is synchronized with the last one to leave or the first one to enter)\n const singleAnimationDurationInMs = computed(\n () =>\n props.animationDurationInMs /\n (clickedListItemIndex.value !== null\n ? relatedPrompts.value.length - 1\n : relatedPrompts.value.length),\n )\n\n const indexRelatedPrompts = computed(() =>\n relatedPrompts.value.map((relatedPrompt, index) => ({ ...relatedPrompt, index })),\n )\n\n const visibleRelatedPrompts = computed(() =>\n selectedPromptIndex.value !== -1\n ? [indexRelatedPrompts.value[selectedPromptIndex.value]]\n : indexRelatedPrompts.value,\n )\n\n let timeOutId: number\n const resetTransitionStyle = (excludedProperties: Array<string> = ['width']) => {\n if (timeOutId) {\n clearTimeout(timeOutId)\n }\n\n isAnimating.value = true\n timeOutId = +setTimeout(() => {\n isAnimating.value = false\n clickedListItemIndex.value = null\n\n sortedListItems.value.forEach(element => {\n element.style.cssText\n .split(';')\n .map(rule => rule.split(':')[0]?.trim())\n .forEach(property => {\n if (!excludedProperties.includes(property)) {\n element.style.removeProperty(property)\n }\n })\n })\n }, props.animationDurationInMs)\n }\n\n const onSelect = (selectedIndex: number): void => {\n resetTransitionStyle()\n\n clickedListItemIndex.value = selectedIndex\n const selected: HTMLElement = sortedListItems.value.find(\n element => Number.parseInt(element.getAttribute('data-index')!) === selectedIndex,\n )!\n\n // selectedPromptIndex.value === -1 ? 'SELECTING' : 'DESELECTING'\n if (selectedPromptIndex.value === -1) {\n // Prepare all the elements for the leave animation (~ 'beforeLeave' hook). Remember the elements are\n // sorted in descending order by index.\n sortedListItems.value.forEach(element => {\n const index = Number.parseInt(element.getAttribute('data-index')!)\n\n initialOffsetLefts[index] = element.offsetLeft\n element.style.left = `${element.offsetLeft}px`\n element.style.position = 'absolute'\n element.style.transitionDuration = `${singleAnimationDurationInMs.value}ms`\n\n if (index !== selectedIndex) {\n element.style.opacity = '1'\n element.style.transitionDelay = `${\n (index < selectedIndex ? index : index - 1) * singleAnimationDurationInMs.value\n }ms`\n }\n })\n\n // Synchronize the transition delay of the selected element with the last\n // element to leave\n selected.style.transitionDelay = `${\n (relatedPrompts.value.length > 1 ? relatedPrompts.value.length - 2 : 0) *\n singleAnimationDurationInMs.value\n }ms`\n\n // Trigger the animation (selecting) for the selected element\n requestAnimationFrame(() => {\n const maxWidth = getComputedStyle(selected).maxWidth\n\n selected.style.left = '0px'\n selected.style.setProperty(\n 'width',\n `${maxWidth !== 'none' ? maxWidth : '100%'}`,\n 'important',\n )\n })\n } else {\n // Prepare the selected element for the deselecting animation\n selected.style.transitionDuration = `${singleAnimationDurationInMs.value}ms`\n selected.style.left = '0px'\n selected.style.position = 'absolute'\n\n // Trigger the animation (deselecting) for the selected element\n selected.style.removeProperty('width')\n requestAnimationFrame(() => {\n selected.style.left = `${initialOffsetLefts[selectedIndex]}px`\n })\n }\n\n x.emit('UserSelectedARelatedPrompt', selectedIndex, {\n relatedPrompt: relatedPrompts.value[selectedIndex],\n selectedPrompt: selectedPromptIndex.value,\n })\n }\n\n const onBeforeEnter = (el: Element) => {\n const element = el as HTMLElement\n const index = Number.parseInt(element.getAttribute('data-index')!)\n\n // Prepare the element for the enter animation\n element.style.opacity = '0'\n element.style.transform = 'translateY(5px)'\n element.style.transitionDelay = `${\n (clickedListItemIndex.value !== null && index > clickedListItemIndex.value\n ? index - 1\n : index) * singleAnimationDurationInMs.value\n }ms`\n element.style.transitionDuration = `${singleAnimationDurationInMs.value}ms`\n }\n\n const onEnter = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n const index = Number.parseInt(element.getAttribute('data-index')!)\n\n // Also part of the preparation for the enter animation, but it needs to be done\n // once the element is inserted in DOM (if not the offsetLeft will be always 0)\n element.style.left = `${initialOffsetLefts[index] ?? element.offsetLeft}px`\n\n // trigger enter animation\n requestAnimationFrame(() => {\n element.style.opacity = '1'\n element.style.position = 'absolute'\n element.style.transform = 'translateY(0)'\n })\n\n done()\n }\n\n const onLeave = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n\n // trigger leave animation\n requestAnimationFrame(() => {\n element.style.opacity = '0'\n element.style.transform = 'translateY(5px)'\n })\n\n // Wait for the animation to finish (done() exectution extracts the element from the DOM)\n setTimeout(done, props.animationDurationInMs)\n }\n\n // Changing the request will trigger the appear animation, so we need to reset the\n // style after it finishes\n x.on('SearchRequestChanged', false).subscribe(() => {\n resetTransitionStyle([])\n })\n\n onBeforeUnmount(() => {\n x.emit('RelatedPromptsUnmounted')\n })\n\n return {\n onSelect,\n onBeforeEnter,\n onEnter,\n onLeave,\n selectedPromptIndex,\n visibleRelatedPrompts,\n listItems,\n isAnimating,\n x,\n }\n },\n})\n</script>\n\n<style lang=\"css\">\n.x-related-prompts-tag-list-scroll-container {\n height: 100%;\n position: relative;\n}\n.x-related-prompts-tag-list {\n display: flex;\n gap: 16px;\n min-width: 100%;\n width: 100%;\n}\n.x-related-prompts-tag-list-item {\n height: 100%;\n flex-shrink: 0;\n}\n</style>\n\n<docs lang=\"mdx\">\n## See it in action\n\n### Basic usage\n\n```vue live\n<template>\n <RelatedPromptsTagList />\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n\n### Customizing tag colors and classes\n\n```vue live\n<template>\n <RelatedPromptsTagList :tagColors=\"['x-bg-neutral-50', 'x-bg-lead-50']\" tagClass=\"rounded\" />\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n\n### Using the default slot to customize prompt rendering\n\n```vue live\n<template>\n <RelatedPromptsTagList>\n <template #default=\"{ relatedPrompt, onSelect, isSelected }\">\n <button :class=\"{ selected: isSelected }\" @click=\"onSelect()\">\n {{ relatedPrompt.suggestionText }}\n </button>\n </template>\n </RelatedPromptsTagList>\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n\n### Customizing extra content in RelatedPrompt\n\n```vue live\n<template>\n <RelatedPromptsTagList>\n <template #related-prompt-extra-content=\"{ relatedPrompt }\">\n <span>Extra: {{ relatedPrompt.suggestionText }}</span>\n </template>\n </RelatedPromptsTagList>\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n</docs>\n"],"names":["_createBlock","_withCtx","_renderSlot","_createVNode","_TransitionGroup","_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"related-prompts-tag-list.vue.js","sources":["../../../../../src/x-modules/related-prompts/components/related-prompts-tag-list.vue"],"sourcesContent":["<template>\n <SlidingPanel\n :key=\"x.query.search\"\n :fade=\"selectedPromptIndex === -1\"\n :reset-on-content-change=\"false\"\n :button-class=\"buttonClass\"\n :show-buttons=\"showButtons && selectedPromptIndex === -1\"\n :scroll-container-class=\"[\n 'x-related-prompts-tag-list-scroll-container',\n scrollContainerClass || '',\n ]\"\n >\n <template #sliding-panel-left-button>\n <!--\n @slot sliding-panel-left-button - The button to be displayed on the left side of the sliding panel.\n -->\n <slot name=\"sliding-panel-left-button\" />\n </template>\n <transition-group\n class=\"x-related-prompts-tag-list\"\n :css=\"false\"\n tag=\"ul\"\n appear\n @before-enter=\"onBeforeEnter\"\n @enter=\"onEnter\"\n @leave=\"onLeave\"\n >\n <li\n v-for=\"{ index, ...relatedPrompt } in visibleRelatedPrompts\"\n ref=\"listItems\"\n :key=\"relatedPrompt.suggestionText\"\n class=\"x-related-prompts-tag-list-item\"\n :class=\"[tagClass, tagColors && tagColors[index % tagColors.length]]\"\n :data-index=\"index\"\n :style=\"{\n ...(selectedPromptIndex === index && { width: '100%' }),\n ...(isAnimating && { pointerEvents: 'none' }),\n }\"\n data-test=\"related-prompts-tag-list-item\"\n >\n <!--\n @slot - The slot to render related prompt information.\n @prop {Object} relatedPrompt - The related prompt object.\n @prop {Function} onSelect - The function to select the related prompt.\n @prop {Boolean} isSelected - Indicates if the related prompt is currently selected.\n -->\n <slot\n :related-prompt=\"relatedPrompt\"\n :on-select=\"() => onSelect(index)\"\n :is-selected=\"selectedPromptIndex === index\"\n >\n <DisplayEmitter\n :payload=\"relatedPrompt.tagging?.toolingDisplayTagging!\"\n :event-metadata=\"{\n feature: 'related-prompts',\n displayOriginalQuery: x.query.searchBox,\n replaceable: false,\n }\"\n >\n <RelatedPrompt\n :related-prompt=\"relatedPrompt\"\n :selected=\"selectedPromptIndex === index\"\n @click=\"onSelect(index)\"\n >\n <template #related-prompt-extra-content>\n <!--\n @slot related-prompt-extra-content - The slot to render related prompt extra information.\n @prop {Object} relatedPrompt - The related prompt object.\n -->\n <slot name=\"related-prompt-extra-content\" :related-prompt=\"relatedPrompt\" />\n </template>\n </RelatedPrompt>\n </DisplayEmitter>\n </slot>\n </li>\n </transition-group>\n <template #sliding-panel-right-button>\n <!--\n @slot sliding-panel-right-button - The button to be displayed on the right side of the sliding panel.\n -->\n <slot name=\"sliding-panel-right-button\" />\n </template>\n </SlidingPanel>\n</template>\n\n<script lang=\"ts\">\nimport type { PropType } from 'vue'\nimport { computed, defineComponent, onBeforeUnmount, ref } from 'vue'\nimport DisplayEmitter from '../../../components/display-emitter.vue'\nimport SlidingPanel from '../../../components/sliding-panel.vue'\nimport { use$x, useState } from '../../../composables'\nimport { relatedPromptsXModule } from '../x-module'\nimport RelatedPrompt from './related-prompt.vue'\n\n/**\n * This component shows the list of `RelatedPrompts` components.\n *\n * If the default slot is reimplemented in the consumer, `onSelect` function will be\n * necessary to handle the selection of the related prompt and to trigger the stagger-fade-slide animation.\n *\n * @public\n */\nexport default defineComponent({\n name: 'RelatedPromptsTagList',\n xModule: relatedPromptsXModule.name,\n components: { DisplayEmitter, RelatedPrompt, SlidingPanel },\n props: {\n /**\n * The CSS class for the left and right button of the sliding panel.\n *\n * @public\n */\n buttonClass: String,\n /**\n * The boolean prop to handle the visiblity of sliding pannel buttons.\n *\n * @public\n */\n showButtons: { type: Boolean, default: true },\n /**\n * The CSS class for the wrapper of all the related prompt wrapper elements.\n *\n * @public\n */\n scrollContainerClass: String,\n /**\n * The CSS class for all the related prompt wrapper elements.\n *\n * @public\n */\n tagClass: String,\n /**\n * Array of colors to apply to the related prompts. It will be applied to tag\n * elements cyclically according to their index in the nex way: `tagColors[index % tagColors.length]`.\n *\n * @public\n */\n tagColors: Array as PropType<string[]>,\n /**\n * The duration of the total animation in milliseconds.\n *\n * @public\n */\n animationDurationInMs: {\n type: Number,\n default: 700,\n },\n },\n setup(props) {\n const x = use$x()\n const { relatedPrompts, selectedPrompt: selectedPromptIndex } = useState('relatedPrompts')\n\n const clickedListItemIndex = ref<number | null>(null)\n const initialOffsetLefts: Record<number, number> = {}\n const isAnimating = ref(false)\n const listItems = ref<HTMLElement[]>([])\n\n const sortedListItems = computed<HTMLElement[]>(() =>\n [...listItems.value].sort(\n (a: HTMLElement, b: HTMLElement) =>\n Number.parseInt(b.getAttribute('data-index')!) -\n Number.parseInt(a.getAttribute('data-index')!),\n ),\n )\n\n // The duration of a single animation (enter or leave) in milliseconds\n // if a related prompt is clicked (clickedListItemIndex.value !== null), the duration is divided by the number of related\n // prompts -1 (the clicked one is synchronized with the last one to leave or the first one to enter)\n const singleAnimationDurationInMs = computed(\n () =>\n props.animationDurationInMs /\n (clickedListItemIndex.value !== null\n ? relatedPrompts.value.length - 1\n : relatedPrompts.value.length),\n )\n\n const indexRelatedPrompts = computed(() =>\n relatedPrompts.value.map((relatedPrompt, index) => ({ ...relatedPrompt, index })),\n )\n\n const visibleRelatedPrompts = computed(() =>\n selectedPromptIndex.value !== -1\n ? [indexRelatedPrompts.value[selectedPromptIndex.value]]\n : indexRelatedPrompts.value,\n )\n\n let timeOutId: number\n const resetTransitionStyle = (excludedProperties: Array<string> = ['width']) => {\n if (timeOutId) {\n clearTimeout(timeOutId)\n }\n\n isAnimating.value = true\n timeOutId = +setTimeout(() => {\n isAnimating.value = false\n clickedListItemIndex.value = null\n\n sortedListItems.value.forEach(element => {\n element.style.cssText\n .split(';')\n .map(rule => rule.split(':')[0]?.trim())\n .forEach(property => {\n if (!excludedProperties.includes(property)) {\n element.style.removeProperty(property)\n }\n })\n })\n }, props.animationDurationInMs)\n }\n\n const onSelect = (selectedIndex: number): void => {\n resetTransitionStyle()\n\n clickedListItemIndex.value = selectedIndex\n const selected: HTMLElement = sortedListItems.value.find(\n element => Number.parseInt(element.getAttribute('data-index')!) === selectedIndex,\n )!\n\n // selectedPromptIndex.value === -1 ? 'SELECTING' : 'DESELECTING'\n if (selectedPromptIndex.value === -1) {\n // Prepare all the elements for the leave animation (~ 'beforeLeave' hook). Remember the elements are\n // sorted in descending order by index.\n sortedListItems.value.forEach(element => {\n const index = Number.parseInt(element.getAttribute('data-index')!)\n\n initialOffsetLefts[index] = element.offsetLeft\n element.style.left = `${element.offsetLeft}px`\n element.style.position = 'absolute'\n element.style.transitionDuration = `${singleAnimationDurationInMs.value}ms`\n\n if (index !== selectedIndex) {\n element.style.opacity = '1'\n element.style.transitionDelay = `${\n (index < selectedIndex ? index : index - 1) * singleAnimationDurationInMs.value\n }ms`\n }\n })\n\n // Synchronize the transition delay of the selected element with the last\n // element to leave\n selected.style.transitionDelay = `${\n (relatedPrompts.value.length > 1 ? relatedPrompts.value.length - 2 : 0) *\n singleAnimationDurationInMs.value\n }ms`\n\n // Trigger the animation (selecting) for the selected element\n requestAnimationFrame(() => {\n const maxWidth = getComputedStyle(selected).maxWidth\n\n selected.style.left = '0px'\n selected.style.setProperty(\n 'width',\n `${maxWidth !== 'none' ? maxWidth : '100%'}`,\n 'important',\n )\n })\n } else {\n // Prepare the selected element for the deselecting animation\n selected.style.transitionDuration = `${singleAnimationDurationInMs.value}ms`\n selected.style.left = '0px'\n selected.style.position = 'absolute'\n\n // Trigger the animation (deselecting) for the selected element\n selected.style.removeProperty('width')\n requestAnimationFrame(() => {\n selected.style.left = `${initialOffsetLefts[selectedIndex]}px`\n })\n }\n\n x.emit('UserSelectedARelatedPrompt', selectedIndex, {\n relatedPrompt: relatedPrompts.value[selectedIndex],\n selectedPrompt: selectedPromptIndex.value,\n })\n }\n\n const onBeforeEnter = (el: Element) => {\n const element = el as HTMLElement\n const index = Number.parseInt(element.getAttribute('data-index')!)\n\n // Prepare the element for the enter animation\n element.style.opacity = '0'\n element.style.transform = 'translateY(5px)'\n element.style.transitionDelay = `${\n (clickedListItemIndex.value !== null && index > clickedListItemIndex.value\n ? index - 1\n : index) * singleAnimationDurationInMs.value\n }ms`\n element.style.transitionDuration = `${singleAnimationDurationInMs.value}ms`\n }\n\n const onEnter = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n const index = Number.parseInt(element.getAttribute('data-index')!)\n\n // Also part of the preparation for the enter animation, but it needs to be done\n // once the element is inserted in DOM (if not the offsetLeft will be always 0)\n element.style.left = `${initialOffsetLefts[index] ?? element.offsetLeft}px`\n\n // trigger enter animation\n requestAnimationFrame(() => {\n element.style.opacity = '1'\n element.style.position = 'absolute'\n element.style.transform = 'translateY(0)'\n })\n\n done()\n }\n\n const onLeave = (el: Element, done: () => void) => {\n const element = el as HTMLElement\n\n // trigger leave animation\n requestAnimationFrame(() => {\n element.style.opacity = '0'\n element.style.transform = 'translateY(5px)'\n })\n\n // Wait for the animation to finish (done() exectution extracts the element from the DOM)\n setTimeout(done, props.animationDurationInMs)\n }\n\n // Changing the request will trigger the appear animation, so we need to reset the\n // style after it finishes\n x.on('SearchRequestChanged', false).subscribe(() => {\n resetTransitionStyle([])\n })\n\n onBeforeUnmount(() => {\n x.emit('RelatedPromptsUnmounted')\n })\n\n return {\n onSelect,\n onBeforeEnter,\n onEnter,\n onLeave,\n selectedPromptIndex,\n visibleRelatedPrompts,\n listItems,\n isAnimating,\n x,\n }\n },\n})\n</script>\n\n<style lang=\"css\">\n.x-related-prompts-tag-list-scroll-container {\n height: 100%;\n position: relative;\n}\n.x-related-prompts-tag-list {\n display: flex;\n gap: 16px;\n min-width: 100%;\n width: 100%;\n}\n.x-related-prompts-tag-list-item {\n height: 100%;\n flex-shrink: 0;\n}\n</style>\n\n<docs lang=\"mdx\">\n## See it in action\n\n### Basic usage\n\n```vue live\n<template>\n <RelatedPromptsTagList />\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n\n### Customizing tag colors and classes\n\n```vue live\n<template>\n <RelatedPromptsTagList :tagColors=\"['x-bg-neutral-50', 'x-bg-lead-50']\" tagClass=\"rounded\" />\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n\n### Using the default slot to customize prompt rendering\n\n```vue live\n<template>\n <RelatedPromptsTagList>\n <template #default=\"{ relatedPrompt, onSelect, isSelected }\">\n <button :class=\"{ selected: isSelected }\" @click=\"onSelect()\">\n {{ relatedPrompt.suggestionText }}\n </button>\n </template>\n </RelatedPromptsTagList>\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n\n### Customizing extra content in RelatedPrompt\n\n```vue live\n<template>\n <RelatedPromptsTagList>\n <template #related-prompt-extra-content=\"{ relatedPrompt }\">\n <span>Extra: {{ relatedPrompt.suggestionText }}</span>\n </template>\n </RelatedPromptsTagList>\n</template>\n\n<script setup>\nimport { RelatedPromptsTagList } from '@empathyco/x-components/related-prompts'\n</script>\n```\n</docs>\n"],"names":["_createBlock","_withCtx","_renderSlot","_createVNode","_TransitionGroup","_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle"],"mappings":";;;;;;;;;;sBACEA,WAAA,CAiFe,uBAAA,EAAA;AAAA,IAhFZ,GAAA,EAAK,OAAE,KAAA,CAAM,MAAA;AAAA,IACb,MAAM,IAAA,CAAA,mBAAA,KAAmB,EAAA;AAAA,IACzB,yBAAA,EAAyB,KAAA;AAAA,IACzB,cAAA,EAAc,IAAA,CAAA,WAAA;AAAA,IACd,cAAA,EAAc,oBAAe,IAAA,CAAA,mBAAA,KAAmB,EAAA;AAAA,IAChD,wBAAA,EAAsB;AAAA,MAAA,6CAAA;MAA+D,IAAA,CAAA,oBAAA,IAAoB;AAAA;;AAK/F,IAAA,2BAAA,EAAyBC,QAIlC,MAAyC;AAAA,MAAzCC,UAAA,CAAyC,IAAA,CAAA,MAAA,EAAA,2BAAA;AAAA,KAAA,CAAA;AA4DhC,IAAA,4BAAA,EAA0BD,QAInC,MAA0C;AAAA,MAA1CC,UAAA,CAA0C,IAAA,CAAA,MAAA,EAAA,4BAAA;AAAA,KAAA,CAAA;qBA9D5C,MAyDmB;AAAA,MAzDnBC,WAAA,CAyDmBC,eAAA,EAAA;AAAA,QAxDjB,KAAA,EAAM,4BAAA;AAAA,QACL,GAAA,EAAK,KAAA;AAAA,QACN,GAAA,EAAI,IAAA;AAAA,QACJ,MAAA,EAAA,EAAA;AAAA,QACC,aAAA,EAAc,IAAA,CAAA,aAAA;AAAA,QACd,OAAA,EAAO,IAAA,CAAA,OAAA;AAAA,QACP,OAAA,EAAO,IAAA,CAAA;AAAA,OAAA,EAAA;yBAGN,MAA4D;AAAA,WAAAC,SAAA,CAAA,IAAA,CAAA,EAD9DC,kBAAA;AAAA,YA+CKC,QAAA;AAAA,YAAA,IAAA;AAAA,YAAAC,UAAA,CA9CmC,IAAA,CAAA,qBAAA,EAAqB,CAAA,EAAlD,KAAA,EAAK,GAAK,aAAA,EAAa,KAAA;kCADlCF,kBAAA,CA+CK,IAAA,EAAA;AAAA,gBAAA,OAAA,EAAA,IAAA;gBA7CH,GAAA,EAAI,WAAA;AAAA,gBACH,KAAK,aAAA,CAAc,cAAA;AAAA,gBACpB,KAAA,EAAKG,gBAAC,iCAAA,EAAiC,CAC9B,eAAU,IAAA,CAAA,SAAA,IAAa,IAAA,CAAA,SAAA,CAAU,KAAA,GAAQ,IAAA,CAAA,SAAA,CAAU,MAAM,CAAA,CAAA,CAAA,CAAA;AAAA,gBACjE,YAAA,EAAY,KAAA;AAAA,gBACZ,KAAA,EAAKC,cAAA,CAAA;AAAA,kBAAA,GAAkB,6BAAwB,KAAA,IAAK,EAAA,KAAA,EAAA,MAAA,EAAA;AAAA,kBAAA,GAAsC,IAAA,CAAA,WAAA,IAAW,EAAA,aAAA,EAAA,MAAA;AAAA,iBAAA,CAAA;gBAItG,WAAA,EAAU;AAAA,eAAA,EAAA;gBAQVR,UAAA,CA2BO,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA;AAAA,kBA1BJ,aAAA;AAAA,kBACA,QAAA,EAAS,MAAQ,IAAA,CAAA,QAAA,CAAS,KAAK,CAAA;AAAA,kBAC/B,YAAa,IAAA,CAAA,mBAAA,KAAwB;AAAA,iBAAA,EAHxC,MA2BO;AAAA,kBAtBLC,WAAA,CAqBiB,yBAAA,EAAA;AAAA,oBApBd,OAAA,EAAS,cAAc,OAAA,EAAS,qBAAA;AAAA,oBAChC,gBAAA,EAAc;AAAA,sBAAA,OAAA,EAAA,iBAAA;AAAkF,sBAAA,oBAAA,EAAA,IAAA,CAAA,CAAA,CAAE,KAAA,CAAM,SAAA;AAAA,sBAAA,WAAA,EAAA;;;qCAMzG,MAYgB;AAAA,sBAZhBA,WAAA,CAYgB,wBAAA,EAAA;AAAA,wBAXb,gBAAA,EAAgB,aAAA;AAAA,wBAChB,UAAU,IAAA,CAAA,mBAAA,KAAwB,KAAA;AAAA,wBAClC,OAAA,EAAK,CAAA,MAAA,KAAE,IAAA,CAAA,QAAA,CAAS,KAAK;AAAA,uBAAA,EAAA;AAEX,wBAAA,8BAAA,EAA4BF,QAKrC,MAA4E;AAAA,0BAA5EC,UAAA,CAA4E,+CAAjC,aAAA,EAA6B;AAAA,yBAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|