@empathyco/x-components 6.0.0-alpha.203 → 6.0.0-alpha.205
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 +19 -0
- package/docs/API-reference/api/x-components.addquerytohistory.md +15 -1
- package/docs/API-reference/api/x-components.addquerytohistoryaction.addquerytohistory.md +15 -1
- package/docs/API-reference/api/x-components.addquerytohistoryaction.md +1 -1
- package/docs/API-reference/api/x-components.basedropdown.md +1 -1
- package/docs/API-reference/api/x-components.baseidmodal.md +1 -1
- package/docs/API-reference/api/x-components.baseresultimage.md +1 -1
- package/docs/API-reference/api/x-components.collapseheight.md +3 -3
- package/docs/API-reference/api/x-components.collapsewidth.md +3 -3
- package/docs/API-reference/api/x-components.createfetchandsaveactions.md +15 -1
- package/docs/API-reference/api/x-components.createrelatedtagsquerygetter.md +15 -1
- package/docs/API-reference/api/x-components.debouncefunction.md +17 -1
- package/docs/API-reference/api/x-components.defaultfacetsservice.clearfilterswithmetadata.md +17 -1
- package/docs/API-reference/api/x-components.defaultfacetsservice.md +1 -1
- package/docs/API-reference/api/x-components.historyqueriesgetter.historyqueries.md +15 -1
- package/docs/API-reference/api/x-components.historyqueriesgetter.md +1 -1
- package/docs/API-reference/api/x-components.isinrange.md +15 -1
- package/docs/API-reference/api/x-components.md +10 -10
- package/docs/API-reference/api/x-components.querysuggestionsgetter.md +1 -1
- package/docs/API-reference/api/x-components.querysuggestionsgetter.querysuggestions.md +15 -1
- package/docs/API-reference/api/x-components.usecollapseanimation.md +4 -4
- package/docs/API-reference/api/x-components.useemitdisplayevent.md +15 -1
- package/docs/API-reference/api/x-components.useondisplay.md +15 -1
- package/docs/API-reference/api/x-components.usescroll.md +15 -1
- package/docs/API-reference/api/x-types.suggestion.key.md +1 -1
- package/docs/API-reference/api/x-types.suggestion.md +4 -4
- package/js/components/animations/animate-scale/animate-scale.style.css.js +1 -1
- package/js/components/animations/use-collapse-animation.js +9 -0
- package/js/components/animations/use-collapse-animation.js.map +1 -1
- package/js/components/base-dropdown.vue.js +3 -3
- package/js/components/base-dropdown.vue.js.map +1 -1
- package/js/components/base-dropdown.vue2.js +6 -4
- package/js/components/base-dropdown.vue2.js.map +1 -1
- package/js/components/base-grid.vue.js.map +1 -1
- package/js/components/base-grid.vue2.js.map +1 -1
- package/js/components/base-rating.vue3.js +1 -1
- package/js/components/column-picker/base-column-picker-list.vue.js.map +1 -1
- package/js/components/column-picker/base-column-picker-list.vue2.js.map +1 -1
- package/js/components/modals/base-id-modal.vue.js +1 -1
- package/js/components/modals/base-id-modal.vue.js.map +1 -1
- package/js/components/modals/base-id-modal.vue2.js +3 -3
- package/js/components/modals/base-id-modal.vue2.js.map +1 -1
- package/js/components/panels/base-tabs-panel.vue.js +1 -1
- package/js/components/panels/base-tabs-panel.vue.js.map +1 -1
- package/js/components/panels/base-tabs-panel.vue2.js.map +1 -1
- package/js/components/result/base-result-current-price.vue.js +4 -3
- package/js/components/result/base-result-current-price.vue.js.map +1 -1
- package/js/components/result/base-result-current-price.vue2.js.map +1 -1
- package/js/components/result/base-result-image.vue.js.map +1 -1
- package/js/components/result/base-result-image.vue2.js +2 -1
- package/js/components/result/base-result-image.vue2.js.map +1 -1
- package/js/components/result/base-result-previous-price.vue.js +1 -1
- package/js/components/result/base-result-previous-price.vue.js.map +1 -1
- package/js/components/result/base-result-previous-price.vue2.js.map +1 -1
- package/js/components/sliding-panel.vue3.js +1 -1
- package/js/x-modules/facets/components/facets/facets.vue.js.map +1 -1
- package/js/x-modules/facets/components/facets/facets.vue2.js.map +1 -1
- package/js/x-modules/facets/components/filters/editable-number-range-filter.vue.js +2 -2
- package/js/x-modules/facets/components/filters/editable-number-range-filter.vue.js.map +1 -1
- package/js/x-modules/facets/components/filters/editable-number-range-filter.vue2.js.map +1 -1
- package/js/x-modules/facets/components/lists/filters-search.vue.js +1 -1
- package/js/x-modules/facets/components/lists/filters-search.vue.js.map +1 -1
- package/js/x-modules/facets/components/lists/filters-search.vue2.js.map +1 -1
- package/js/x-modules/facets/components/lists/filters-search.vue3.js +1 -1
- package/js/x-modules/facets/components/lists/selected-filters-list.vue.js.map +1 -1
- package/js/x-modules/facets/components/lists/selected-filters-list.vue2.js.map +1 -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/search/components/sort-picker-list.vue.js.map +1 -1
- package/js/x-modules/search/components/sort-picker-list.vue2.js.map +1 -1
- package/package.json +18 -18
- package/report/tsdoc-metadata.json +1 -1
- package/report/x-adapter-platform.api.json +1 -1
- package/report/x-components.api.json +161 -67
- package/report/x-components.api.md +46 -45
- package/report/x-types.api.json +4 -4
- package/types/components/animations/collapse-height.vue.d.ts +3 -3
- package/types/components/animations/collapse-width.vue.d.ts +3 -3
- package/types/components/animations/use-collapse-animation.d.ts +3 -3
- package/types/components/animations/use-collapse-animation.d.ts.map +1 -1
- package/types/components/base-dropdown.vue.d.ts +1 -1
- package/types/components/base-dropdown.vue.d.ts.map +1 -1
- package/types/components/base-grid.types.d.ts +11 -0
- package/types/components/base-grid.types.d.ts.map +1 -0
- package/types/components/base-grid.vue.d.ts +2 -10
- package/types/components/base-grid.vue.d.ts.map +1 -1
- package/types/components/column-picker/base-column-picker-list.types.d.ts +9 -0
- package/types/components/column-picker/base-column-picker-list.types.d.ts.map +1 -0
- package/types/components/column-picker/base-column-picker-list.vue.d.ts +1 -8
- package/types/components/column-picker/base-column-picker-list.vue.d.ts.map +1 -1
- package/types/components/modals/base-id-modal.vue.d.ts +1 -1
- package/types/components/result/base-result-image.vue.d.ts +1 -1
- package/types/components/result/base-result-image.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/facets/facets.types.d.ts +12 -0
- package/types/x-modules/facets/components/facets/facets.types.d.ts.map +1 -0
- package/types/x-modules/facets/components/facets/facets.vue.d.ts +1 -10
- package/types/x-modules/facets/components/facets/facets.vue.d.ts.map +1 -1
- package/types/x-modules/facets/components/lists/selected-filters-list.types.d.ts +11 -0
- package/types/x-modules/facets/components/lists/selected-filters-list.types.d.ts.map +1 -0
- package/types/x-modules/facets/components/lists/selected-filters-list.vue.d.ts +1 -9
- package/types/x-modules/facets/components/lists/selected-filters-list.vue.d.ts.map +1 -1
- package/types/x-modules/search/components/sort-picker-list.types.d.ts +12 -0
- package/types/x-modules/search/components/sort-picker-list.types.d.ts.map +1 -0
- package/types/x-modules/search/components/sort-picker-list.vue.d.ts +1 -10
- package/types/x-modules/search/components/sort-picker-list.vue.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selected-filters-list.vue.js","sources":["../../../../../../src/x-modules/facets/components/lists/selected-filters-list.vue"],"sourcesContent":["<template>\n <SelectedFilters :facets-ids=\"facetsIds\" :always-visible=\"alwaysVisible\">\n <component\n :is=\"animation\"\n class=\"x-selected-filters-list\"\n data-test=\"selected-filters-list\"\n tag=\"ul\"\n >\n <li\n v-for=\"{ slotName, selectedFilter } in mapSlot(selectedFilters)\"\n :key=\"selectedFilter.id\"\n class=\"x-selected-filters-list__item\"\n data-test=\"selected-filters-list-item\"\n >\n <!--\n @slot Custom filter rendering. Dynamic slot defined in the template with the filter\n facet id. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-if=\"hasSlot(slotName)\" :name=\"slotName\" :filter=\"selectedFilter\">\n <span class=\"x-tag\">{{ selectedFilter.label }}</span>\n </slot>\n\n <!--\n @slot Default filter rendering. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-else name=\"default\" :filter=\"selectedFilter\">\n {{ selectedFilter.label }}\n </slot>\n </li>\n </component>\n </SelectedFilters>\n</template>\n\n<script lang=\"ts\">\nimport type { Facet, Filter } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport { isFacetFilter } from '@empathyco/x-types'\nimport { defineComponent } from 'vue'\nimport { AnimationProp } from '../../../../types'\nimport { toKebabCase } from '../../../../utils/string'\nimport { useFacets } from '../../composables/use-facets'\nimport { facetsXModule } from '../../x-module'\nimport SelectedFilters from './selected-filters.vue'\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"selected-filters-list.vue.js","sources":["../../../../../../src/x-modules/facets/components/lists/selected-filters-list.vue"],"sourcesContent":["<template>\n <SelectedFilters :facets-ids=\"facetsIds\" :always-visible=\"alwaysVisible\">\n <component\n :is=\"animation\"\n class=\"x-selected-filters-list\"\n data-test=\"selected-filters-list\"\n tag=\"ul\"\n >\n <li\n v-for=\"{ slotName, selectedFilter } in mapSlot(selectedFilters)\"\n :key=\"selectedFilter.id\"\n class=\"x-selected-filters-list__item\"\n data-test=\"selected-filters-list-item\"\n >\n <!--\n @slot Custom filter rendering. Dynamic slot defined in the template with the filter\n facet id. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-if=\"hasSlot(slotName)\" :name=\"slotName\" :filter=\"selectedFilter\">\n <span class=\"x-tag\">{{ (selectedFilter as BooleanFilter).label }}</span>\n </slot>\n\n <!--\n @slot Default filter rendering. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-else name=\"default\" :filter=\"selectedFilter\">\n {{ (selectedFilter as BooleanFilter).label }}\n </slot>\n </li>\n </component>\n </SelectedFilters>\n</template>\n\n<script lang=\"ts\">\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport type { BooleanFilter, Facet, Filter } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport type { RenderFilter } from './selected-filters-list.types'\nimport { isFacetFilter } from '@empathyco/x-types'\nimport { defineComponent } from 'vue'\nimport { AnimationProp } from '../../../../types'\nimport { toKebabCase } from '../../../../utils/string'\nimport { useFacets } from '../../composables/use-facets'\nimport { facetsXModule } from '../../x-module'\nimport SelectedFilters from './selected-filters.vue'\n\n/**\n * This component renders a list of selected filters from every facet, or from the facet\n * ids passed as property. It uses the SelectedFilters component (state).\n *\n * It provides two slots: a scoped one which name is the filter facet id; and a default one.\n * Both exposes the filter and renders the filter label by default.\n *\n * The property \"alwaysVisible\" handles if the component is rendered if no filters are selected.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SelectedFiltersList',\n xModule: facetsXModule.name,\n components: { SelectedFilters },\n props: {\n /** Array of facets ids used to get the selected filters for those facets. */\n facetsIds: Array as PropType<Array<Facet['id']>>,\n /** Flag to render the component even if there are no filters selected. */\n alwaysVisible: Boolean,\n /** Animation component that will be used to animate the selected filters list. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n },\n setup(props, { slots }) {\n const { selectedFilters } = useFacets(props)\n\n /**\n * Transforms a dictionary of Filters including the slot name.\n *\n * @param selectedFilters - A list of selected filters without slot name.\n *\n * @returns A dictionary of facets with the slot name.\n */\n function mapSlot(selectedFilters: Filter[]): RenderFilter[] {\n return selectedFilters.map(filter => ({\n slotName: isFacetFilter(filter) ? toKebabCase(filter.facetId as string) : 'default',\n selectedFilter: filter,\n }))\n }\n\n /**\n * Whether the slot is present in the template or not.\n *\n * @param name - The slot name.\n *\n * @returns True is the slot is present in the template. False otherwise.\n */\n function hasSlot(name: string): boolean {\n return !!slots[name]\n }\n\n return {\n selectedFilters,\n mapSlot,\n hasSlot,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Example\n\nThis component renders a list of selected filters from every facet, or from the facets which facets\nids are passed as property. It uses the SelectedFilters component (state).\n\nIt provides two slots: a scoped one which name is the filter facet id; and a default one. Both\nexposes the filter and renders the filter label by default.\n\nThe property \"alwaysVisible\" handles if the component is rendered if no filters are selected.\n\n### Default usage\n\n```vue\n<template>\n <SelectedFiltersList />\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\n### Customized usage\n\n```vue\n<template>\n <SelectedFiltersList #default=\"{ filter }\">Default: {{ filter.label }}</SelectedFiltersList>\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\n```vue\n<template>\n <SelectedFiltersList>\n <template #default=\"{ filter }\">Default: {{ filter.label }}</template>\n <template #brand_facet=\"{ filter }\">Brand: {{ filter.label }}</template>\n <template #age_facet=\"{ filter }\">Age: {{ filter.label }}</template>\n <template #price_facet=\"{ filter }\">Price: {{ filter.label }}</template>\n </SelectedFiltersList>\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\n#### Always visible\n\nIf \"alwaysVisible\" is true, the component is rendered no matter if there are some filter selected.\nIf \"alwaysVisible\" is false (default), the component is rendered if there are some filter selected.\n\n```vue\n<template>\n <SelectedFiltersList :alwaysVisible=\"true\" />\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\nOutput:\n\n```html\n<div class=\"x-selected-filters\">\n <ul class=\"x-selected-filters-list\" data-test=\"selected-filters-list\"></ul>\n</div>\n```\n\n#### Providing an array of facet ids\n\nIn this example, the selected filters computed are the ones that match the facet ids passed as\nproperties.\n\n```vue\n<template>\n <SelectedFiltersList :facetsIds=\"['brand_facet', 'gender_facet']\" />\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n</docs>\n"],"names":["_createBlock","_openBlock","_resolveDynamicComponent","_createElementBlock","_Fragment","_renderList","_renderSlot","_createElementVNode","_toDisplayString","_createTextVNode"],"mappings":";;;;AAoBgB,MAAA,UAAA,GAAA,EAAA,KAAA,EAAM,OAAA,EAAO;;;sBAnB3BA,WAAA,CA+BkB,0BAAA,EAAA;AAAA,IA/BA,YAAA,EAAY,IAAA,CAAA,SAAA;AAAA,IAAY,gBAAA,EAAgB,IAAA,CAAA;AAAA,GAAA,EAAA;qBACxD,MA6BY;AAAA,OAAAC,SAAA,EAAA,EA7BZD,WAAA,CA6BYE,wBA5BL,IAAA,CAAA,SAAS,CAAA,EAAA;AAAA,QACd,KAAA,EAAM,yBAAA;AAAA,QACN,WAAA,EAAU,uBAAA;AAAA,QACV,GAAA,EAAI;AAAA,OAAA,EAAA;yBAGF,MAAgE;AAAA,WAAAD,SAAA,CAAA,IAAA,CAAA,EADlEE,kBAAA;AAAA,YAsBKC,QAAA;AAAA,YAAA,IAAA;AAAA,YAAAC,UAAA,CArBoC,IAAA,CAAA,OAAA,CAAQ,IAAA,CAAA,eAAe,CAAA,EAAA,CAAA,EAArD,QAAA,EAAU,cAAA,EAAc,KAAA;kCADnCF,kBAAA,CAsBK,IAAA,EAAA;AAAA,gBApBF,KAAK,cAAA,CAAe,EAAA;AAAA,gBACrB,KAAA,EAAM,+BAAA;AAAA,gBACN,WAAA,EAAU;AAAA,eAAA,EAAA;AAOE,gBAAA,IAAA,CAAA,OAAA,CAAQ,QAAQ,CAAA,GAA5BG,UAAA,CAEO,IAAA,CAAA,MAAA,EAF+B,QAAA,EAAQ;AAAA,kBAAA,GAAA,EAAA,CAAA;kBAAG,MAAA,EAAQ;AAAA,iBAAA,EAAzD,MAEO;AAAA,kBADLC,kBAAA;AAAA,oBAAwE,MAAA;AAAA,oBAAxE,UAAA;AAAA,oBAAwEC,eAAA,CAAhD,eAAiC,KAAK,CAAA;AAAA,oBAAA;AAAA;AAAA;AAAA,iBAAA,CAAA,GAOhEF,UAAA,CAEO,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA;AAAA,kBAAA,GAAA,EAAA,CAAA;kBAFsB,MAAA,EAAQ;AAAA,iBAAA,EAArC,MAEO;AAAA,kBAAAG,eAAA;AADD,oBAAAD,eAAA,CAAA,cAAA,CAAiC,KAAK,CAAA;AAAA,oBAAA;AAAA;AAAA;AAAA,iBAAA;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selected-filters-list.vue2.js","sources":["../../../../../../src/x-modules/facets/components/lists/selected-filters-list.vue"],"sourcesContent":["<template>\n <SelectedFilters :facets-ids=\"facetsIds\" :always-visible=\"alwaysVisible\">\n <component\n :is=\"animation\"\n class=\"x-selected-filters-list\"\n data-test=\"selected-filters-list\"\n tag=\"ul\"\n >\n <li\n v-for=\"{ slotName, selectedFilter } in mapSlot(selectedFilters)\"\n :key=\"selectedFilter.id\"\n class=\"x-selected-filters-list__item\"\n data-test=\"selected-filters-list-item\"\n >\n <!--\n @slot Custom filter rendering. Dynamic slot defined in the template with the filter\n facet id. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-if=\"hasSlot(slotName)\" :name=\"slotName\" :filter=\"selectedFilter\">\n <span class=\"x-tag\">{{ selectedFilter.label }}</span>\n </slot>\n\n <!--\n @slot Default filter rendering. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-else name=\"default\" :filter=\"selectedFilter\">\n {{ selectedFilter.label }}\n </slot>\n </li>\n </component>\n </SelectedFilters>\n</template>\n\n<script lang=\"ts\">\nimport type { Facet, Filter } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport { isFacetFilter } from '@empathyco/x-types'\nimport { defineComponent } from 'vue'\nimport { AnimationProp } from '../../../../types'\nimport { toKebabCase } from '../../../../utils/string'\nimport { useFacets } from '../../composables/use-facets'\nimport { facetsXModule } from '../../x-module'\nimport SelectedFilters from './selected-filters.vue'\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"selected-filters-list.vue2.js","sources":["../../../../../../src/x-modules/facets/components/lists/selected-filters-list.vue"],"sourcesContent":["<template>\n <SelectedFilters :facets-ids=\"facetsIds\" :always-visible=\"alwaysVisible\">\n <component\n :is=\"animation\"\n class=\"x-selected-filters-list\"\n data-test=\"selected-filters-list\"\n tag=\"ul\"\n >\n <li\n v-for=\"{ slotName, selectedFilter } in mapSlot(selectedFilters)\"\n :key=\"selectedFilter.id\"\n class=\"x-selected-filters-list__item\"\n data-test=\"selected-filters-list-item\"\n >\n <!--\n @slot Custom filter rendering. Dynamic slot defined in the template with the filter\n facet id. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-if=\"hasSlot(slotName)\" :name=\"slotName\" :filter=\"selectedFilter\">\n <span class=\"x-tag\">{{ (selectedFilter as BooleanFilter).label }}</span>\n </slot>\n\n <!--\n @slot Default filter rendering. It renders the filter label by default.\n @binding {Filter} filter - Filter to render.\n -->\n <slot v-else name=\"default\" :filter=\"selectedFilter\">\n {{ (selectedFilter as BooleanFilter).label }}\n </slot>\n </li>\n </component>\n </SelectedFilters>\n</template>\n\n<script lang=\"ts\">\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport type { BooleanFilter, Facet, Filter } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport type { RenderFilter } from './selected-filters-list.types'\nimport { isFacetFilter } from '@empathyco/x-types'\nimport { defineComponent } from 'vue'\nimport { AnimationProp } from '../../../../types'\nimport { toKebabCase } from '../../../../utils/string'\nimport { useFacets } from '../../composables/use-facets'\nimport { facetsXModule } from '../../x-module'\nimport SelectedFilters from './selected-filters.vue'\n\n/**\n * This component renders a list of selected filters from every facet, or from the facet\n * ids passed as property. It uses the SelectedFilters component (state).\n *\n * It provides two slots: a scoped one which name is the filter facet id; and a default one.\n * Both exposes the filter and renders the filter label by default.\n *\n * The property \"alwaysVisible\" handles if the component is rendered if no filters are selected.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SelectedFiltersList',\n xModule: facetsXModule.name,\n components: { SelectedFilters },\n props: {\n /** Array of facets ids used to get the selected filters for those facets. */\n facetsIds: Array as PropType<Array<Facet['id']>>,\n /** Flag to render the component even if there are no filters selected. */\n alwaysVisible: Boolean,\n /** Animation component that will be used to animate the selected filters list. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n },\n setup(props, { slots }) {\n const { selectedFilters } = useFacets(props)\n\n /**\n * Transforms a dictionary of Filters including the slot name.\n *\n * @param selectedFilters - A list of selected filters without slot name.\n *\n * @returns A dictionary of facets with the slot name.\n */\n function mapSlot(selectedFilters: Filter[]): RenderFilter[] {\n return selectedFilters.map(filter => ({\n slotName: isFacetFilter(filter) ? toKebabCase(filter.facetId as string) : 'default',\n selectedFilter: filter,\n }))\n }\n\n /**\n * Whether the slot is present in the template or not.\n *\n * @param name - The slot name.\n *\n * @returns True is the slot is present in the template. False otherwise.\n */\n function hasSlot(name: string): boolean {\n return !!slots[name]\n }\n\n return {\n selectedFilters,\n mapSlot,\n hasSlot,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Example\n\nThis component renders a list of selected filters from every facet, or from the facets which facets\nids are passed as property. It uses the SelectedFilters component (state).\n\nIt provides two slots: a scoped one which name is the filter facet id; and a default one. Both\nexposes the filter and renders the filter label by default.\n\nThe property \"alwaysVisible\" handles if the component is rendered if no filters are selected.\n\n### Default usage\n\n```vue\n<template>\n <SelectedFiltersList />\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\n### Customized usage\n\n```vue\n<template>\n <SelectedFiltersList #default=\"{ filter }\">Default: {{ filter.label }}</SelectedFiltersList>\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\n```vue\n<template>\n <SelectedFiltersList>\n <template #default=\"{ filter }\">Default: {{ filter.label }}</template>\n <template #brand_facet=\"{ filter }\">Brand: {{ filter.label }}</template>\n <template #age_facet=\"{ filter }\">Age: {{ filter.label }}</template>\n <template #price_facet=\"{ filter }\">Price: {{ filter.label }}</template>\n </SelectedFiltersList>\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\n#### Always visible\n\nIf \"alwaysVisible\" is true, the component is rendered no matter if there are some filter selected.\nIf \"alwaysVisible\" is false (default), the component is rendered if there are some filter selected.\n\n```vue\n<template>\n <SelectedFiltersList :alwaysVisible=\"true\" />\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n\nOutput:\n\n```html\n<div class=\"x-selected-filters\">\n <ul class=\"x-selected-filters-list\" data-test=\"selected-filters-list\"></ul>\n</div>\n```\n\n#### Providing an array of facet ids\n\nIn this example, the selected filters computed are the ones that match the facet ids passed as\nproperties.\n\n```vue\n<template>\n <SelectedFiltersList :facetsIds=\"['brand_facet', 'gender_facet']\" />\n</template>\n\n<script setup>\nimport { SelectedFiltersList } from '@empathyco/x-components/facets'\n</script>\n```\n</docs>\n"],"names":["SelectedFilters"],"mappings":";;;;;;;;AAgDA;;;;;;;;;;AAUE;AACF,gBAAe,eAAe,CAAC;AAC7B,IAAA,IAAI,EAAE,qBAAqB;IAC3B,OAAO,EAAE,aAAa,CAAC,IAAI;IAC3B,UAAU,EAAE,mBAAEA,WAAc,EAAG;AAC/B,IAAA,KAAK,EAAE;;AAEL,QAAA,SAAS,EAAE,KAAqC;;AAEhD,QAAA,aAAa,EAAE,OAAO;;AAEtB,QAAA,SAAS,EAAE;AACT,YAAA,IAAI,EAAE,aAAa;AACnB,YAAA,OAAO,EAAE,IAAI;AACd,SAAA;AACF,KAAA;AACD,IAAA,KAAK,CAAC,KAAK,EAAE,EAAE,KAAI,EAAG,EAAA;QACpB,MAAM,EAAE,eAAc,KAAM,SAAS,CAAC,KAAK,CAAA;AAE3C;;;;;;AAME;QACF,SAAS,OAAO,CAAC,eAAyB,EAAA;YACxC,OAAO,eAAe,CAAC,GAAG,CAAC,MAAK,KAAM;AACpC,gBAAA,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAA,GAAI,WAAW,CAAC,MAAM,CAAC,OAAiB,CAAA,GAAI,SAAS;AACnF,gBAAA,cAAc,EAAE,MAAM;AACvB,aAAA,CAAC,CAAA;QACJ;AAEA;;;;;;AAME;QACF,SAAS,OAAO,CAAC,IAAY,EAAA;AAC3B,YAAA,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;QACrB;QAEA,OAAO;YACL,eAAe;YACf,OAAO;YACP,OAAO;SACT;IACF,CAAC;AACF,CAAA,CAAA;;;;"}
|
|
@@ -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 :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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"related-prompts-tag-list.vue2.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":["DisplayEmitter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"related-prompts-tag-list.vue2.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":["DisplayEmitter"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-picker-list.vue.js","sources":["../../../../../src/x-modules/search/components/sort-picker-list.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n tag=\"div\"\n class=\"x-sort-picker-list\"\n data-test=\"sort-picker\"\n role=\"list\"\n >\n <BaseEventButton\n v-for=\"{ item, cssClasses, event } in listItems\"\n :key=\"item\"\n :class=\"[cssClasses, buttonClass]\"\n data-test=\"sort-picker-button\"\n :events=\"event\"\n :aria-pressed=\"item === selectedSort || null\"\n role=\"listitem\"\n >\n <slot v-bind=\"{ item, isSelected: item === selectedSort }\">\n {{ item }}\n </slot>\n </BaseEventButton>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { Sort } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport type Vue from 'vue'\nimport type {
|
|
1
|
+
{"version":3,"file":"sort-picker-list.vue.js","sources":["../../../../../src/x-modules/search/components/sort-picker-list.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n tag=\"div\"\n class=\"x-sort-picker-list\"\n data-test=\"sort-picker\"\n role=\"list\"\n >\n <BaseEventButton\n v-for=\"{ item, cssClasses, event } in listItems\"\n :key=\"item\"\n :class=\"[cssClasses, buttonClass]\"\n data-test=\"sort-picker-button\"\n :events=\"event\"\n :aria-pressed=\"item === selectedSort || null\"\n role=\"listitem\"\n >\n <slot v-bind=\"{ item, isSelected: item === selectedSort }\">\n {{ item }}\n </slot>\n </BaseEventButton>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { Sort } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport type Vue from 'vue'\nimport type { SortPickerItem } from './sort-picker-list.types'\nimport { computed, defineComponent, watch } from 'vue'\nimport BaseEventButton from '../../../components/base-event-button.vue'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { searchXModule } from '../x-module'\n\n/**\n * The `SortPickerList` component allows user to select the search results order. This component\n * also allows to change the selected sort programmatically.\n */\nexport default defineComponent({\n name: 'SortPickerList',\n xModule: searchXModule.name,\n components: { BaseEventButton },\n props: {\n /** The list of possible sort values. */\n items: {\n type: Array as PropType<Sort[]>,\n required: true,\n },\n /** The transition to use for rendering the list. */\n animation: {\n type: [String, Object] as PropType<string | typeof Vue>,\n default: () => 'div',\n },\n /** Class inherited by each sort button. */\n buttonClass: String,\n },\n setup(props) {\n const $x = use$x()\n\n const { sort: selectedSort } = useState('search')\n\n watch(selectedSort, (value: Sort) => $x.emit('SelectedSortProvided', value), {\n immediate: true,\n })\n\n /**\n * Sort list items.\n *\n * @returns A list of items with their css class and the event associate to it.\n */\n const listItems = computed<SortPickerItem[]>(() =>\n props.items.map(item => ({\n item,\n cssClasses: {\n 'x-selected': item === selectedSort.value,\n },\n event: { UserClickedASort: item },\n })),\n )\n\n return {\n listItems,\n selectedSort,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Sort Picker List\n\nThe `SortPickerList` component can be used to change the way the search results are ordered.\n\nTo do so, the list of valid sort values has to be provided using the `items` prop. These are the\nvalues that can then be received in the `SearchAdapter`.\n\nThe component also optionally accepts the selected sort, which can be set using the `v-model` prop.\nThis prop allows changing programmatically the selected sort, as it will be synced with the store\nimmediately. If this prop is not provided, the first item from the `items` prop will be the one\nselected by default.\n\nThis component also allows customizing each one of the possible sort values. This can be done with\nthe default slot.\n\n## Events\n\nThis component emits 2 different events:\n\n- [`SelectedSortProvided`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts):\n To sync the selected sort with the store state value. This event is emitted as soon as the list of\n items is received, whenever this list changes if there is no provided value, and when the provided\n value changes.\n- [`UserClickedASort`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts):\n As its name suggests, the event is emitted after the user clicks one of the sort options. This does\n not mean that the sort has changed, only that the user has clicked it.\n\n## Examples\n\n### Only providing the list of items\n\n```vue\n<template>\n <SortPickerList :items=\"sortValues\">\n <template #default=\"{ item, isSelected }\">Item: {{ item }}</template>\n </SortPickerList>\n</template>\n\n<script setup>\nimport { SortPickerList } from '@empathyco/x-components/search'\nimport { ref } from 'vue'\n\nconst sortValues = ref(['Relevance', 'Price asc', 'Price desc'])\n</script>\n```\n\n### Providing also the selected value\n\n```vue\n<template>\n <SortPickerList v-model=\"selectedSort\" :items=\"sortValues\">\n <template #default=\"{ item, isSelected }\">\n <span v-if=\"isSelected\">✅</span>\n {{ item }}\n </template>\n </SortPickerList>\n</template>\n\n<script setup>\nimport { SortPickerList } from '@empathyco/x-components/search'\nimport { ref } from 'vue'\n\nconst selectedSort = ref('Price asc')\nconst sortValues = ref(['Relevance', 'Price asc', 'Price desc'])\n</script>\n```\n\n### Customizing the items with classes\n\nThe `buttonClass` prop can be used to add classes to the sort items.\n\n```vue\n<template>\n <SortPickerList :items=\"sortValues\" buttonClass=\"x-button-outlined\" />\n</template>\n\n<script setup>\nimport { SortPickerList } from '@empathyco/x-components/search'\nimport { ref } from 'vue'\n\nconst sortValues = ref(['Relevance', 'Price asc', 'Price desc'])\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_resolveDynamicComponent","_createElementBlock","_Fragment","_renderList","_normalizeClass","_renderSlot","_mergeProps","_createTextVNode"],"mappings":";;;;;;AACE,EAAA,OAAAA,SAAA,EAAA,EAAAC,WAAA,CAoBYC,wBAnBL,IAAA,CAAA,SAAS,CAAA,EAAA;AAAA,IACd,GAAA,EAAI,KAAA;AAAA,IACJ,KAAA,EAAM,oBAAA;AAAA,IACN,WAAA,EAAU,aAAA;AAAA,IACV,IAAA,EAAK;AAAA,GAAA,EAAA;qBAGH,MAAgD;AAAA,OAAAF,SAAA,CAAA,IAAA,CAAA,EADlDG,kBAAA;AAAA,QAYkBC,QAAA;AAAA,QAAA,IAAA;AAAA,QAAAC,UAAA,CAXsB,IAAA,CAAA,SAAA,EAAS,CAAA,EAAtC,IAAA,EAAM,UAAA,EAAY,KAAA,EAAK,KAAA;8BADlCJ,WAAA,CAYkB,0BAAA,EAAA;AAAA,YAVf,GAAA,EAAK,IAAA;AAAA,YACL,KAAA,EAAKK,cAAA,CAAA,CAAG,UAAA,EAAY,IAAA,CAAA,WAAW,CAAA,CAAA;AAAA,YAChC,WAAA,EAAU,oBAAA;AAAA,YACT,MAAA,EAAQ,KAAA;AAAA,YACR,cAAA,EAAc,SAAS,IAAA,CAAA,YAAA,IAAY,IAAA;AAAA,YACpC,IAAA,EAAK;AAAA,WAAA,EAAA;6BAEL,MAEO;AAAA,cAFPC,UAAA,CAEO,wBAFPC,UAAA,CAEO,EAAA,OAAA,EAAA,IAAA,EAAA,EAAA,EAFS,MAAI,UAAA,EAAc,IAAA,KAAS,IAAA,CAAA,YAAA,EAAY,CAAA,EAAvD,MAEO;AAAA,gBAAAC,eAAA;kCADF,IAAI,CAAA;AAAA,kBAAA;AAAA;AAAA;AAAA,eAAA;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-picker-list.vue2.js","sources":["../../../../../src/x-modules/search/components/sort-picker-list.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n tag=\"div\"\n class=\"x-sort-picker-list\"\n data-test=\"sort-picker\"\n role=\"list\"\n >\n <BaseEventButton\n v-for=\"{ item, cssClasses, event } in listItems\"\n :key=\"item\"\n :class=\"[cssClasses, buttonClass]\"\n data-test=\"sort-picker-button\"\n :events=\"event\"\n :aria-pressed=\"item === selectedSort || null\"\n role=\"listitem\"\n >\n <slot v-bind=\"{ item, isSelected: item === selectedSort }\">\n {{ item }}\n </slot>\n </BaseEventButton>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { Sort } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport type Vue from 'vue'\nimport type {
|
|
1
|
+
{"version":3,"file":"sort-picker-list.vue2.js","sources":["../../../../../src/x-modules/search/components/sort-picker-list.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n tag=\"div\"\n class=\"x-sort-picker-list\"\n data-test=\"sort-picker\"\n role=\"list\"\n >\n <BaseEventButton\n v-for=\"{ item, cssClasses, event } in listItems\"\n :key=\"item\"\n :class=\"[cssClasses, buttonClass]\"\n data-test=\"sort-picker-button\"\n :events=\"event\"\n :aria-pressed=\"item === selectedSort || null\"\n role=\"listitem\"\n >\n <slot v-bind=\"{ item, isSelected: item === selectedSort }\">\n {{ item }}\n </slot>\n </BaseEventButton>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { Sort } from '@empathyco/x-types'\nimport type { PropType } from 'vue'\nimport type Vue from 'vue'\nimport type { SortPickerItem } from './sort-picker-list.types'\nimport { computed, defineComponent, watch } from 'vue'\nimport BaseEventButton from '../../../components/base-event-button.vue'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { searchXModule } from '../x-module'\n\n/**\n * The `SortPickerList` component allows user to select the search results order. This component\n * also allows to change the selected sort programmatically.\n */\nexport default defineComponent({\n name: 'SortPickerList',\n xModule: searchXModule.name,\n components: { BaseEventButton },\n props: {\n /** The list of possible sort values. */\n items: {\n type: Array as PropType<Sort[]>,\n required: true,\n },\n /** The transition to use for rendering the list. */\n animation: {\n type: [String, Object] as PropType<string | typeof Vue>,\n default: () => 'div',\n },\n /** Class inherited by each sort button. */\n buttonClass: String,\n },\n setup(props) {\n const $x = use$x()\n\n const { sort: selectedSort } = useState('search')\n\n watch(selectedSort, (value: Sort) => $x.emit('SelectedSortProvided', value), {\n immediate: true,\n })\n\n /**\n * Sort list items.\n *\n * @returns A list of items with their css class and the event associate to it.\n */\n const listItems = computed<SortPickerItem[]>(() =>\n props.items.map(item => ({\n item,\n cssClasses: {\n 'x-selected': item === selectedSort.value,\n },\n event: { UserClickedASort: item },\n })),\n )\n\n return {\n listItems,\n selectedSort,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Sort Picker List\n\nThe `SortPickerList` component can be used to change the way the search results are ordered.\n\nTo do so, the list of valid sort values has to be provided using the `items` prop. These are the\nvalues that can then be received in the `SearchAdapter`.\n\nThe component also optionally accepts the selected sort, which can be set using the `v-model` prop.\nThis prop allows changing programmatically the selected sort, as it will be synced with the store\nimmediately. If this prop is not provided, the first item from the `items` prop will be the one\nselected by default.\n\nThis component also allows customizing each one of the possible sort values. This can be done with\nthe default slot.\n\n## Events\n\nThis component emits 2 different events:\n\n- [`SelectedSortProvided`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts):\n To sync the selected sort with the store state value. This event is emitted as soon as the list of\n items is received, whenever this list changes if there is no provided value, and when the provided\n value changes.\n- [`UserClickedASort`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts):\n As its name suggests, the event is emitted after the user clicks one of the sort options. This does\n not mean that the sort has changed, only that the user has clicked it.\n\n## Examples\n\n### Only providing the list of items\n\n```vue\n<template>\n <SortPickerList :items=\"sortValues\">\n <template #default=\"{ item, isSelected }\">Item: {{ item }}</template>\n </SortPickerList>\n</template>\n\n<script setup>\nimport { SortPickerList } from '@empathyco/x-components/search'\nimport { ref } from 'vue'\n\nconst sortValues = ref(['Relevance', 'Price asc', 'Price desc'])\n</script>\n```\n\n### Providing also the selected value\n\n```vue\n<template>\n <SortPickerList v-model=\"selectedSort\" :items=\"sortValues\">\n <template #default=\"{ item, isSelected }\">\n <span v-if=\"isSelected\">✅</span>\n {{ item }}\n </template>\n </SortPickerList>\n</template>\n\n<script setup>\nimport { SortPickerList } from '@empathyco/x-components/search'\nimport { ref } from 'vue'\n\nconst selectedSort = ref('Price asc')\nconst sortValues = ref(['Relevance', 'Price asc', 'Price desc'])\n</script>\n```\n\n### Customizing the items with classes\n\nThe `buttonClass` prop can be used to add classes to the sort items.\n\n```vue\n<template>\n <SortPickerList :items=\"sortValues\" buttonClass=\"x-button-outlined\" />\n</template>\n\n<script setup>\nimport { SortPickerList } from '@empathyco/x-components/search'\nimport { ref } from 'vue'\n\nconst sortValues = ref(['Relevance', 'Price asc', 'Price desc'])\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;;;AAmCA;;;AAGE;AACF,gBAAe,eAAe,CAAC;AAC7B,IAAA,IAAI,EAAE,gBAAgB;IACtB,OAAO,EAAE,aAAa,CAAC,IAAI;IAC3B,UAAU,EAAE,EAAE,eAAc,EAAG;AAC/B,IAAA,KAAK,EAAE;;AAEL,QAAA,KAAK,EAAE;AACL,YAAA,IAAI,EAAE,KAAyB;AAC/B,YAAA,QAAQ,EAAE,IAAI;AACf,SAAA;;AAED,QAAA,SAAS,EAAE;AACT,YAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAkC;AACvD,YAAA,OAAO,EAAE,MAAM,KAAK;AACrB,SAAA;;AAED,QAAA,WAAW,EAAE,MAAM;AACpB,KAAA;AACD,IAAA,KAAK,CAAC,KAAK,EAAA;AACT,QAAA,MAAM,EAAC,GAAI,KAAK,EAAC;QAEjB,MAAM,EAAE,IAAI,EAAE,YAAW,KAAM,QAAQ,CAAC,QAAQ,CAAA;AAEhD,QAAA,KAAK,CAAC,YAAY,EAAE,CAAC,KAAW,KAAK,EAAE,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,EAAE;AAC3E,YAAA,SAAS,EAAE,IAAI;AAChB,SAAA,CAAA;AAED;;;;AAIE;AACF,QAAA,MAAM,YAAY,QAAQ,CAAmB,MAC3C,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAG,KAAM;YACvB,IAAI;AACJ,YAAA,UAAU,EAAE;AACV,gBAAA,YAAY,EAAE,SAAS,YAAY,CAAC,KAAK;AAC1C,aAAA;AACD,YAAA,KAAK,EAAE,EAAE,gBAAgB,EAAE,IAAG,EAAG;SAClC,CAAC,CAAC,CACL;QAEA,OAAO;YACL,SAAS;YACT,YAAY;SACd;IACF,CAAC;AACF,CAAA,CAAA;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empathyco/x-components",
|
|
3
|
-
"version": "6.0.0-alpha.
|
|
3
|
+
"version": "6.0.0-alpha.205",
|
|
4
4
|
"description": "Empathy X Components",
|
|
5
5
|
"author": "Empathy Systems Corporation S.L.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -72,52 +72,52 @@
|
|
|
72
72
|
"prepublishOnly": "pnpm run build"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
|
-
"vue": "^3.5.
|
|
75
|
+
"vue": "^3.5.28",
|
|
76
76
|
"vuex": "4.0.2"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@empathyco/x-adapter": "^8.1.0-alpha.10",
|
|
80
|
-
"@empathyco/x-adapter-platform": "1.1.0-alpha.
|
|
80
|
+
"@empathyco/x-adapter-platform": "1.1.0-alpha.45",
|
|
81
81
|
"@empathyco/x-deep-merge": "^2.0.3-alpha.10",
|
|
82
82
|
"@empathyco/x-storage-service": "^2.0.3-alpha.8",
|
|
83
|
-
"@empathyco/x-types": "10.1.0-alpha.
|
|
83
|
+
"@empathyco/x-types": "10.1.0-alpha.38",
|
|
84
84
|
"@empathyco/x-utils": "^1.0.3-alpha.9",
|
|
85
85
|
"@vue/devtools-api": "~6.6.4",
|
|
86
86
|
"@vueuse/core": "~12.8.2",
|
|
87
87
|
"js-md5": "~0.8.3",
|
|
88
|
-
"marked": "~
|
|
88
|
+
"marked": "~17.0.3",
|
|
89
89
|
"nouislider": "~15.8.1",
|
|
90
90
|
"rxjs": "~7.8.2",
|
|
91
91
|
"tslib": "~2.8.1",
|
|
92
92
|
"vue-global-events": "~3.0.1",
|
|
93
|
-
"vue-tsc": "~3.2.
|
|
93
|
+
"vue-tsc": "~3.2.5"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
|
-
"@babel/preset-env": "7.
|
|
97
|
-
"@badeball/cypress-cucumber-preprocessor": "24.0.
|
|
96
|
+
"@babel/preset-env": "7.29.0",
|
|
97
|
+
"@badeball/cypress-cucumber-preprocessor": "24.0.1",
|
|
98
98
|
"@bahmutov/cypress-esbuild-preprocessor": "2.2.8",
|
|
99
99
|
"@cucumber/messages": "32.0.1",
|
|
100
|
-
"@empathyco/x-tailwindcss": "2.0.0-alpha.
|
|
101
|
-
"@microsoft/api-documenter": "7.
|
|
102
|
-
"@microsoft/api-extractor": "7.
|
|
100
|
+
"@empathyco/x-tailwindcss": "2.0.0-alpha.24",
|
|
101
|
+
"@microsoft/api-documenter": "7.29.2",
|
|
102
|
+
"@microsoft/api-extractor": "7.57.2",
|
|
103
103
|
"@testing-library/jest-dom": "6.9.1",
|
|
104
104
|
"@types/aria-query": "5.0.4",
|
|
105
105
|
"@types/jest": "29.5.14",
|
|
106
|
-
"@types/node": "24.10.
|
|
106
|
+
"@types/node": "24.10.13",
|
|
107
107
|
"@vitejs/plugin-vue": "5.2.4",
|
|
108
108
|
"@vue/test-utils": "2.4.6",
|
|
109
109
|
"@vue/vue3-jest": "29.2.6",
|
|
110
|
-
"autoprefixer": "10.4.
|
|
110
|
+
"autoprefixer": "10.4.24",
|
|
111
111
|
"convert-source-map": "2.0.0",
|
|
112
|
-
"cypress": "15.
|
|
113
|
-
"esbuild": "0.27.
|
|
112
|
+
"cypress": "15.10.0",
|
|
113
|
+
"esbuild": "0.27.3",
|
|
114
114
|
"jest": "29.7.0",
|
|
115
115
|
"jest-environment-jsdom": "29.7.0",
|
|
116
116
|
"postcss": "8.5.6",
|
|
117
117
|
"postcss-dir-pseudo-class": "7.0.2",
|
|
118
118
|
"postcss-logical": "4.0.2",
|
|
119
119
|
"rimraf": "3.0.2",
|
|
120
|
-
"rollup": "4.
|
|
120
|
+
"rollup": "4.59.0",
|
|
121
121
|
"rollup-plugin-copy": "3.5.0",
|
|
122
122
|
"rollup-plugin-delete": "2.2.0",
|
|
123
123
|
"rollup-plugin-styles": "4.0.0",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"typescript": "5.9.3",
|
|
131
131
|
"vite": "6.4.1",
|
|
132
132
|
"vite-plugin-vue-inspector": "5.3.2",
|
|
133
|
-
"vue": "3.5.
|
|
133
|
+
"vue": "3.5.28",
|
|
134
134
|
"vue-docgen-cli": "4.79.0",
|
|
135
135
|
"vue-router": "4.6.4",
|
|
136
136
|
"vuex": "4.0.2"
|
|
@@ -139,5 +139,5 @@
|
|
|
139
139
|
"access": "public",
|
|
140
140
|
"directory": "dist"
|
|
141
141
|
},
|
|
142
|
-
"gitHead": "
|
|
142
|
+
"gitHead": "acebbc77bd18d465f88fafa8112bc00bc8cba2fd"
|
|
143
143
|
}
|