@empathyco/x-components 6.0.0-alpha.94 → 6.0.0-alpha.96
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 +16 -0
- package/docs/API-reference/api/x-components.md +1 -1
- package/docs/API-reference/api/x-components.resultvariantselector.md +1 -1
- package/docs/API-reference/components/common/result/x-components.result-variant-selector.md +1 -1
- package/js/components/base-grid.vue.js.map +1 -1
- package/js/components/base-grid.vue2.js +0 -1
- package/js/components/base-grid.vue2.js.map +1 -1
- package/js/components/result/result-variant-selector.vue.js.map +1 -1
- package/js/components/result/result-variant-selector.vue2.js +1 -1
- package/js/components/result/result-variant-selector.vue2.js.map +1 -1
- package/js/components/scroll/use-scroll.js +0 -1
- package/js/components/scroll/use-scroll.js.map +1 -1
- package/js/store/utils/fetch-and-save-action.utils.js +1 -3
- package/js/store/utils/fetch-and-save-action.utils.js.map +1 -1
- package/js/x-modules/facets/composables/use-filters-injection.js +0 -1
- package/js/x-modules/facets/composables/use-filters-injection.js.map +1 -1
- package/js/x-modules/tagging/service/external-tagging.service.js +0 -2
- package/js/x-modules/tagging/service/external-tagging.service.js.map +1 -1
- package/package.json +10 -11
- package/report/x-components.api.json +1 -1
- package/types/components/base-grid.vue.d.ts.map +1 -1
- package/types/components/result/result-variant-selector.vue.d.ts +1 -1
- package/types/components/scroll/use-scroll.d.ts.map +1 -1
- package/types/store/utils/fetch-and-save-action.utils.d.ts.map +1 -1
- package/types/x-modules/facets/composables/use-filters-injection.d.ts.map +1 -1
- package/types/x-modules/tagging/service/external-tagging.service.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## 6.0.0-alpha.96 (2025-06-13)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @empathyco/x-components
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## 6.0.0-alpha.95 (2025-06-06)
|
|
15
|
+
|
|
16
|
+
* feat(logger): remove x-logger (#1800) ([70d210a](https://github.com/empathyco/x/commit/70d210a)), closes [#1800](https://github.com/empathyco/x/issues/1800)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## 6.0.0-alpha.94 (2025-06-04)
|
|
7
23
|
|
|
8
24
|
* feat!: remove deprecated design system (#1793) ([97a853d](https://github.com/empathyco/x/commit/97a853d)), closes [#1793](https://github.com/empathyco/x/issues/1793)
|
|
@@ -520,7 +520,7 @@ X-Components is a library usable everywhere not only for search experiences.
|
|
|
520
520
|
| [resetStateForReloadWire](./x-components.resetstateforreloadwire.md) | Resets the search state to reload the current search. |
|
|
521
521
|
| [resetStateIfNoRequestWire](./x-components.resetstateifnorequestwire.md) | Resets the search state when the request is changed to null. See the [SearchXStoreModule](./x-components.searchxstoremodule.md) for details. |
|
|
522
522
|
| [ResultsList](./x-components.resultslist.md) | <p>It renders a [ItemsList](./x-components.itemslist.md) list with the results from [SearchState.results](./x-components.searchstate.results.md) by default.</p><p>The component provides a default slot which wraps the whole component with the <code>results</code> bound.</p><p>It also provides the slot result to customize the item, which is within the default slot, with the result bound.</p> |
|
|
523
|
-
| [ResultVariantSelector](./x-components.resultvariantselector.md) | Component to show and select the available variants of a product for a given nest level. TODO:
|
|
523
|
+
| [ResultVariantSelector](./x-components.resultvariantselector.md) | Component to show and select the available variants of a product for a given nest level. TODO: Log warning on mount when result is not injected. |
|
|
524
524
|
| [ResultVariantsProvider](./x-components.resultvariantsprovider.md) | <p>Component that exposes the result merged with its selected variant in the default slot.</p><p>It receives the original result and keeps track of the selected variant.</p><p>It provides the original result, the array containing the selected variants and a callback to set the selected variant to be used from a child.</p> |
|
|
525
525
|
| [sanitize](./x-components.sanitize.md) | Sanitize characters from a given string. |
|
|
526
526
|
| [saveIdentifierResultsOrigin](./x-components.saveidentifierresultsorigin.md) | Default implementation for the [IdentifierResultsActions.saveOrigin](./x-components.identifierresultsactions.saveorigin.md)<!-- -->. |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## ResultVariantSelector variable
|
|
6
6
|
|
|
7
|
-
Component to show and select the available variants of a product for a given nest level. TODO:
|
|
7
|
+
Component to show and select the available variants of a product for a given nest level. TODO: Log warning on mount when result is not injected.
|
|
8
8
|
|
|
9
9
|
**Signature:**
|
|
10
10
|
|
|
@@ -7,7 +7,7 @@ title: ResultVariantSelector
|
|
|
7
7
|
# ResultVariantSelector
|
|
8
8
|
|
|
9
9
|
Component to show and select the available variants of a product for a given nest level.
|
|
10
|
-
TODO:
|
|
10
|
+
TODO: Log warning on mount when result is not injected.
|
|
11
11
|
|
|
12
12
|
## Props
|
|
13
13
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-grid.vue.js","sources":["../../../src/components/base-grid.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n ref=\"gridEl\"\n :style=\"style\"\n class=\"x-base-grid\"\n :class=\"cssClasses\"\n tag=\"ul\"\n data-test=\"grid\"\n >\n <li\n v-for=\"{ item, cssClass, slotName } in gridItems\"\n :key=\"item.id\"\n :class=\"cssClass\"\n class=\"x-base-grid__item\"\n >\n <!--\n @slot Customized item rendering. Specifying a slot with the item's modelName will result in\n the item using that slot composition to render.\n @binding {item} item - Item to render\n -->\n <slot v-if=\"slots[slotName]\" :name=\"slotName\" :item=\"item\" />\n <!--\n @slot (required) Default item rendering. This slot will be used by default for rendering\n the item without an specific slot implementation.\n @binding {item} item - Item to render\n -->\n <slot v-else :item=\"item\">{{ item.name || item.modelName || item.id || item }}</slot>\n </li>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { MaybeComputedElementRef, UseResizeObserverReturn } from '@vueuse/core'\nimport type { PropType, Ref } from 'vue'\nimport type { ListItem, VueCSSClasses } from '../utils/types'\nimport { useResizeObserver } from '@vueuse/core'\nimport { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport { toKebabCase } from '../utils/string'\nimport { LIST_ITEMS_KEY } from './decorators/injection.consts'\n\n/**\n * The type returned by the gridItems function. Basically it's a list of items with its CSS\n * classes and a slotName.\n */\ninterface GridItem {\n slotName: string\n item: ListItem\n cssClass: VueCSSClasses\n}\n\n/**\n * Grid component that is able to render different items based on their modelName value. In order\n * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used\n * do not have modelName property, the default slot is used instead. It has a required property:\n * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the\n * number of columns is not specified, the grid automatically fills the rows with as many columns\n * as it can fit.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseGrid',\n props: {\n /** Animation component that will be used to animate the base grid. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * Number of columns the grid is divided into. By default, its value is 0, setting the grid\n * columns mode to auto-fill.\n */\n columns: {\n type: Number,\n default: 0,\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an ID property.\n */\n items: {\n type: Array as PropType<ListItem[]>,\n },\n },\n setup(props, { slots }) {\n // eslint-disable-next-line ts/consistent-type-definitions\n type ElementRef = {\n $el: HTMLElement\n }\n\n const xBus = useXBus()\n\n /** It injects {@link ListItem} provided by an ancestor. */\n const injectedListItems = inject<Ref<ListItem[]>>(LIST_ITEMS_KEY as string)\n const gridEl = ref<ElementRef | HTMLElement>()\n const renderedColumnsNumber = ref(0)\n\n /**\n * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged}\n * event whenever the number of columns rendered inside the grid changes.\n */\n watch(\n renderedColumnsNumber,\n () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value),\n { immediate: false },\n )\n\n /**\n * It returns the items passed as props or the injected ones.\n *\n * @returns List of grid items.\n */\n const computedItems = computed<ListItem[] | void>(() => {\n return (\n props.items ??\n injectedListItems?.value ??\n //TODO: add here logger\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * CSS class based on the column property value so items inside the grid can fill different\n * amount of columns or rows based on how many columns the grid is divided into.\n *\n * @returns CSS class with the column property value.\n */\n const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`)\n\n /**\n * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on\n * the column property value.\n *\n * @returns A CSSStyleDeclaration to use as the style attribute.\n */\n const style = computed<Partial<CSSStyleDeclaration>>(() => ({\n gridTemplateColumns: props.columns\n ? `repeat(${props.columns}, minmax(0, 1fr))`\n : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))',\n }))\n\n /**\n * Maps the item to an object containing: the `item`, its `CSS class` and its slot name.\n *\n * @returns An array of objects containing the item and its CSS class.\n */\n const gridItems = computed<GridItem[]>(() =>\n (computedItems.value as ListItem[]).map(item => {\n const slotName = toKebabCase(item.modelName)\n return {\n slotName,\n item,\n cssClass: `x-base-grid__${slotName}`,\n }\n }),\n )\n\n /**\n * Checks if a given value is an `ElementRef` object.\n *\n * @param value - The value to check.\n * @returns `true` if the value is an `ElementRef` object, `false` otherwise.\n */\n const isElementRef = (value: any): value is ElementRef => {\n return value && value.$el instanceof HTMLElement\n }\n\n /** Updates the number of columns rendered inside the grid. */\n function updateRenderedColumnsNumber() {\n const { gridTemplateColumns } = getComputedStyle(\n isElementRef(gridEl.value) ? gridEl.value.$el : (gridEl.value as Element),\n )\n renderedColumnsNumber.value = gridTemplateColumns.split(' ').length\n }\n\n /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */\n let resizeObserver: UseResizeObserverReturn\n onMounted(() => {\n resizeObserver = useResizeObserver(\n gridEl as MaybeComputedElementRef,\n updateRenderedColumnsNumber,\n )\n })\n onBeforeUnmount(() => resizeObserver?.stop())\n\n return {\n gridItems,\n cssClasses,\n style,\n gridEl,\n slots,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-base-grid {\n display: grid;\n grid-auto-flow: dense;\n list-style: none;\n align-items: stretch;\n}\n\n.x-base-grid__banner,\n.x-base-grid__next-queries-group,\n.x-base-grid__related-prompts-group {\n grid-column-start: 1;\n grid-column-end: -1;\n}\n\n.x-base-grid__item {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-grid__item > * {\n flex-grow: 1;\n}\n\n.x-base-grid--cols-auto .x-base-grid__item {\n min-width: var(--x-size-min-width-grid-item);\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a list of elements in different slots depending on their modelName. In order\nto achieve this, it exposes a scopedSlot for each different modelName. In case the items used do not\nhave modelName property, the default slot is used instead. It has a required property, the `items`\nto render, and an optional one, the number of `columns` the grid is divided in. If the number of\ncolumns is not specified, the grid automatically fills the rows with as many columns as it can fit.\n\n### Basic example\n\nIt renders a list of items using the default slot:\n\n```vue\n<template>\n <BaseGrid :items=\"items\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Configuring the number of columns\n\nIt renders a grid with 12 columns instead of 6, which is the default value:\n\n```vue\n<template>\n <BaseGrid :items=\"items\" :columns=\"12\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Rendering usage\n\nConfiguring the number of columns.\n\nIt renders a list of items using the different scopedSlots created by the item's modelName. For\nexample, if you want to use this component as the search grid, you pass the search results (results,\nbanners, promoted, next queries...etc) as items. Each of these results have a different modelName\nand are rendered in different slots.\n\n```vue\n<template>\n <BaseGrid :animation=\"animation\" :items=\"items\">\n <template #banner=\"{ item }\">\n <span class=\"banner\">\n {{ `${item.title} banner` }}\n </span>\n </template>\n <template #next-queries=\"{ item }\">\n <span>\n {{ `${item.totalResults} next queries` }}\n </span>\n </template>\n <template #promoted=\"{ item }\">\n <span class=\"promoted\">\n {{ `${item.title} promoted` }}\n </span>\n </template>\n <template #result=\"{ item }\">\n <BaseResultLink :result=\"item\">\n {{ item.name }}\n </BaseResultLink>\n </template>\n </BaseGrid>\n</template>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseGrid :items=\"items\" style=\"--x-size-min-width-grid-item: 150px\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeStyle","_normalizeClass","_createElementBlock","_Fragment","_renderList","slots","_renderSlot"],"mappings":";;;;;SAGQ,WAAQ,CAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,QAAA,EAAA;AACN,EAAA,OAAAA,SAAA,EAAO,EAAAC,WAAA,CAAAC,uBAAA,CAAA,IAAA,CAAA,SAAA,CAAA,EAAA;AAAA,IACb,GAAK,EAAA,QAAA;AAAA,IAEL,OAAIC,cAAI,CAAA,IAAA,CAAA,KAAA,CAAA;AAAA,IACR,KAAgB,EAAAC,cAAA,CAAA,CAAA,aAAA,EAAA,IAAA,CAAA,UAAA,CAAA,CAAA;AAAA,IAAA,GAAA,EAAA,IAAA;AARpB,IAAA,WAAA,EAAA,MAAA;AAAA,GAAA,EAAA;;iBAYY,IAAO,CAAA,EAAAC,kBAAA;AAAA,QAAAC,QAAA;AAAA,QAAA,IAAA;AAAA,QAAAC,UAAA,CAAA,IAAA,CAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA;iBACPP,SAbZ,EAAA,EAAAK,kBAAA;AAAA,YAcY,IAAA;AAAA,YAAA;AAAA,cAAA,GAAA,EAAA,IAAA,CAAA,EAAA;qBAOMG,cAAc,CAAA,CAAA,QAAA,EAAA,mBAAA,CAAA,CAAA;AAAA,aAAA;;mBArBhC,KAqB+D,CAAA,QAAA,CAAA,GAAAC,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,QAAA,EAAA;AAAA,gBAAA,GAAA,EAAA,CAAA;AAMzD,gBAAA,IAAA;AAAA,eAAA,EA3BN,KA2B8B,CAAA,EAAA,IAAA,CAAA,GAAAA,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA;AAAA,gBAA6D,GAAA,EAAA,CAAA;AAAA,gBA3B3F,IAAA;AAAA,eAAA,EAAA,MAAA;;;;;;;;;;;AAAA,SAAA,CAAA;AAAA,QAAA,GAAA;AAAA;AAAA,OAAA;AAAA,KAAA,CAAA;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"base-grid.vue.js","sources":["../../../src/components/base-grid.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n ref=\"gridEl\"\n :style=\"style\"\n class=\"x-base-grid\"\n :class=\"cssClasses\"\n tag=\"ul\"\n data-test=\"grid\"\n >\n <li\n v-for=\"{ item, cssClass, slotName } in gridItems\"\n :key=\"item.id\"\n :class=\"cssClass\"\n class=\"x-base-grid__item\"\n >\n <!--\n @slot Customized item rendering. Specifying a slot with the item's modelName will result in\n the item using that slot composition to render.\n @binding {item} item - Item to render\n -->\n <slot v-if=\"slots[slotName]\" :name=\"slotName\" :item=\"item\" />\n <!--\n @slot (required) Default item rendering. This slot will be used by default for rendering\n the item without an specific slot implementation.\n @binding {item} item - Item to render\n -->\n <slot v-else :item=\"item\">{{ item.name || item.modelName || item.id || item }}</slot>\n </li>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { MaybeComputedElementRef, UseResizeObserverReturn } from '@vueuse/core'\nimport type { PropType, Ref } from 'vue'\nimport type { ListItem, VueCSSClasses } from '../utils/types'\nimport { useResizeObserver } from '@vueuse/core'\nimport { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport { toKebabCase } from '../utils/string'\nimport { LIST_ITEMS_KEY } from './decorators/injection.consts'\n\n/**\n * The type returned by the gridItems function. Basically it's a list of items with its CSS\n * classes and a slotName.\n */\ninterface GridItem {\n slotName: string\n item: ListItem\n cssClass: VueCSSClasses\n}\n\n/**\n * Grid component that is able to render different items based on their modelName value. In order\n * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used\n * do not have modelName property, the default slot is used instead. It has a required property:\n * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the\n * number of columns is not specified, the grid automatically fills the rows with as many columns\n * as it can fit.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseGrid',\n props: {\n /** Animation component that will be used to animate the base grid. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * Number of columns the grid is divided into. By default, its value is 0, setting the grid\n * columns mode to auto-fill.\n */\n columns: {\n type: Number,\n default: 0,\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an ID property.\n */\n items: {\n type: Array as PropType<ListItem[]>,\n },\n },\n setup(props, { slots }) {\n // eslint-disable-next-line ts/consistent-type-definitions\n type ElementRef = {\n $el: HTMLElement\n }\n\n const xBus = useXBus()\n\n /** It injects {@link ListItem} provided by an ancestor. */\n const injectedListItems = inject<Ref<ListItem[]>>(LIST_ITEMS_KEY as string)\n const gridEl = ref<ElementRef | HTMLElement>()\n const renderedColumnsNumber = ref(0)\n\n /**\n * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged}\n * event whenever the number of columns rendered inside the grid changes.\n */\n watch(\n renderedColumnsNumber,\n () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value),\n { immediate: false },\n )\n\n /**\n * It returns the items passed as props or the injected ones.\n *\n * @returns List of grid items.\n */\n const computedItems = computed<ListItem[] | void>(() => {\n return (\n props.items ??\n injectedListItems?.value ??\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * CSS class based on the column property value so items inside the grid can fill different\n * amount of columns or rows based on how many columns the grid is divided into.\n *\n * @returns CSS class with the column property value.\n */\n const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`)\n\n /**\n * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on\n * the column property value.\n *\n * @returns A CSSStyleDeclaration to use as the style attribute.\n */\n const style = computed<Partial<CSSStyleDeclaration>>(() => ({\n gridTemplateColumns: props.columns\n ? `repeat(${props.columns}, minmax(0, 1fr))`\n : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))',\n }))\n\n /**\n * Maps the item to an object containing: the `item`, its `CSS class` and its slot name.\n *\n * @returns An array of objects containing the item and its CSS class.\n */\n const gridItems = computed<GridItem[]>(() =>\n (computedItems.value as ListItem[]).map(item => {\n const slotName = toKebabCase(item.modelName)\n return {\n slotName,\n item,\n cssClass: `x-base-grid__${slotName}`,\n }\n }),\n )\n\n /**\n * Checks if a given value is an `ElementRef` object.\n *\n * @param value - The value to check.\n * @returns `true` if the value is an `ElementRef` object, `false` otherwise.\n */\n const isElementRef = (value: any): value is ElementRef => {\n return value && value.$el instanceof HTMLElement\n }\n\n /** Updates the number of columns rendered inside the grid. */\n function updateRenderedColumnsNumber() {\n const { gridTemplateColumns } = getComputedStyle(\n isElementRef(gridEl.value) ? gridEl.value.$el : (gridEl.value as Element),\n )\n renderedColumnsNumber.value = gridTemplateColumns.split(' ').length\n }\n\n /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */\n let resizeObserver: UseResizeObserverReturn\n onMounted(() => {\n resizeObserver = useResizeObserver(\n gridEl as MaybeComputedElementRef,\n updateRenderedColumnsNumber,\n )\n })\n onBeforeUnmount(() => resizeObserver?.stop())\n\n return {\n gridItems,\n cssClasses,\n style,\n gridEl,\n slots,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-base-grid {\n display: grid;\n grid-auto-flow: dense;\n list-style: none;\n align-items: stretch;\n}\n\n.x-base-grid__banner,\n.x-base-grid__next-queries-group,\n.x-base-grid__related-prompts-group {\n grid-column-start: 1;\n grid-column-end: -1;\n}\n\n.x-base-grid__item {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-grid__item > * {\n flex-grow: 1;\n}\n\n.x-base-grid--cols-auto .x-base-grid__item {\n min-width: var(--x-size-min-width-grid-item);\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a list of elements in different slots depending on their modelName. In order\nto achieve this, it exposes a scopedSlot for each different modelName. In case the items used do not\nhave modelName property, the default slot is used instead. It has a required property, the `items`\nto render, and an optional one, the number of `columns` the grid is divided in. If the number of\ncolumns is not specified, the grid automatically fills the rows with as many columns as it can fit.\n\n### Basic example\n\nIt renders a list of items using the default slot:\n\n```vue\n<template>\n <BaseGrid :items=\"items\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Configuring the number of columns\n\nIt renders a grid with 12 columns instead of 6, which is the default value:\n\n```vue\n<template>\n <BaseGrid :items=\"items\" :columns=\"12\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Rendering usage\n\nConfiguring the number of columns.\n\nIt renders a list of items using the different scopedSlots created by the item's modelName. For\nexample, if you want to use this component as the search grid, you pass the search results (results,\nbanners, promoted, next queries...etc) as items. Each of these results have a different modelName\nand are rendered in different slots.\n\n```vue\n<template>\n <BaseGrid :animation=\"animation\" :items=\"items\">\n <template #banner=\"{ item }\">\n <span class=\"banner\">\n {{ `${item.title} banner` }}\n </span>\n </template>\n <template #next-queries=\"{ item }\">\n <span>\n {{ `${item.totalResults} next queries` }}\n </span>\n </template>\n <template #promoted=\"{ item }\">\n <span class=\"promoted\">\n {{ `${item.title} promoted` }}\n </span>\n </template>\n <template #result=\"{ item }\">\n <BaseResultLink :result=\"item\">\n {{ item.name }}\n </BaseResultLink>\n </template>\n </BaseGrid>\n</template>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseGrid :items=\"items\" style=\"--x-size-min-width-grid-item: 150px\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n</docs>\n"],"names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeStyle","_normalizeClass","_createElementBlock","_Fragment","_renderList","slots","_renderSlot"],"mappings":";;;;;SAGQ,WAAQ,CAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,QAAA,EAAA;AACN,EAAA,OAAAA,SAAA,EAAO,EAAAC,WAAA,CAAAC,uBAAA,CAAA,IAAA,CAAA,SAAA,CAAA,EAAA;AAAA,IACb,GAAK,EAAA,QAAA;AAAA,IAEL,OAAIC,cAAI,CAAA,IAAA,CAAA,KAAA,CAAA;AAAA,IACR,KAAgB,EAAAC,cAAA,CAAA,CAAA,aAAA,EAAA,IAAA,CAAA,UAAA,CAAA,CAAA;AAAA,IAAA,GAAA,EAAA,IAAA;AARpB,IAAA,WAAA,EAAA,MAAA;AAAA,GAAA,EAAA;;iBAYY,IAAO,CAAA,EAAAC,kBAAA;AAAA,QAAAC,QAAA;AAAA,QAAA,IAAA;AAAA,QAAAC,UAAA,CAAA,IAAA,CAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA;iBACPP,SAbZ,EAAA,EAAAK,kBAAA;AAAA,YAcY,IAAA;AAAA,YAAA;AAAA,cAAA,GAAA,EAAA,IAAA,CAAA,EAAA;qBAOMG,cAAc,CAAA,CAAA,QAAA,EAAA,mBAAA,CAAA,CAAA;AAAA,aAAA;;mBArBhC,KAqB+D,CAAA,QAAA,CAAA,GAAAC,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,QAAA,EAAA;AAAA,gBAAA,GAAA,EAAA,CAAA;AAMzD,gBAAA,IAAA;AAAA,eAAA,EA3BN,KA2B8B,CAAA,EAAA,IAAA,CAAA,GAAAA,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA;AAAA,gBAA6D,GAAA,EAAA,CAAA;AAAA,gBA3B3F,IAAA;AAAA,eAAA,EAAA,MAAA;;;;;;;;;;;AAAA,SAAA,CAAA;AAAA,QAAA,GAAA;AAAA;AAAA,OAAA;AAAA,KAAA,CAAA;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-grid.vue2.js","sources":["../../../src/components/base-grid.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n ref=\"gridEl\"\n :style=\"style\"\n class=\"x-base-grid\"\n :class=\"cssClasses\"\n tag=\"ul\"\n data-test=\"grid\"\n >\n <li\n v-for=\"{ item, cssClass, slotName } in gridItems\"\n :key=\"item.id\"\n :class=\"cssClass\"\n class=\"x-base-grid__item\"\n >\n <!--\n @slot Customized item rendering. Specifying a slot with the item's modelName will result in\n the item using that slot composition to render.\n @binding {item} item - Item to render\n -->\n <slot v-if=\"slots[slotName]\" :name=\"slotName\" :item=\"item\" />\n <!--\n @slot (required) Default item rendering. This slot will be used by default for rendering\n the item without an specific slot implementation.\n @binding {item} item - Item to render\n -->\n <slot v-else :item=\"item\">{{ item.name || item.modelName || item.id || item }}</slot>\n </li>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { MaybeComputedElementRef, UseResizeObserverReturn } from '@vueuse/core'\nimport type { PropType, Ref } from 'vue'\nimport type { ListItem, VueCSSClasses } from '../utils/types'\nimport { useResizeObserver } from '@vueuse/core'\nimport { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport { toKebabCase } from '../utils/string'\nimport { LIST_ITEMS_KEY } from './decorators/injection.consts'\n\n/**\n * The type returned by the gridItems function. Basically it's a list of items with its CSS\n * classes and a slotName.\n */\ninterface GridItem {\n slotName: string\n item: ListItem\n cssClass: VueCSSClasses\n}\n\n/**\n * Grid component that is able to render different items based on their modelName value. In order\n * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used\n * do not have modelName property, the default slot is used instead. It has a required property:\n * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the\n * number of columns is not specified, the grid automatically fills the rows with as many columns\n * as it can fit.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseGrid',\n props: {\n /** Animation component that will be used to animate the base grid. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * Number of columns the grid is divided into. By default, its value is 0, setting the grid\n * columns mode to auto-fill.\n */\n columns: {\n type: Number,\n default: 0,\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an ID property.\n */\n items: {\n type: Array as PropType<ListItem[]>,\n },\n },\n setup(props, { slots }) {\n // eslint-disable-next-line ts/consistent-type-definitions\n type ElementRef = {\n $el: HTMLElement\n }\n\n const xBus = useXBus()\n\n /** It injects {@link ListItem} provided by an ancestor. */\n const injectedListItems = inject<Ref<ListItem[]>>(LIST_ITEMS_KEY as string)\n const gridEl = ref<ElementRef | HTMLElement>()\n const renderedColumnsNumber = ref(0)\n\n /**\n * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged}\n * event whenever the number of columns rendered inside the grid changes.\n */\n watch(\n renderedColumnsNumber,\n () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value),\n { immediate: false },\n )\n\n /**\n * It returns the items passed as props or the injected ones.\n *\n * @returns List of grid items.\n */\n const computedItems = computed<ListItem[] | void>(() => {\n return (\n props.items ??\n injectedListItems?.value ??\n //TODO: add here logger\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * CSS class based on the column property value so items inside the grid can fill different\n * amount of columns or rows based on how many columns the grid is divided into.\n *\n * @returns CSS class with the column property value.\n */\n const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`)\n\n /**\n * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on\n * the column property value.\n *\n * @returns A CSSStyleDeclaration to use as the style attribute.\n */\n const style = computed<Partial<CSSStyleDeclaration>>(() => ({\n gridTemplateColumns: props.columns\n ? `repeat(${props.columns}, minmax(0, 1fr))`\n : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))',\n }))\n\n /**\n * Maps the item to an object containing: the `item`, its `CSS class` and its slot name.\n *\n * @returns An array of objects containing the item and its CSS class.\n */\n const gridItems = computed<GridItem[]>(() =>\n (computedItems.value as ListItem[]).map(item => {\n const slotName = toKebabCase(item.modelName)\n return {\n slotName,\n item,\n cssClass: `x-base-grid__${slotName}`,\n }\n }),\n )\n\n /**\n * Checks if a given value is an `ElementRef` object.\n *\n * @param value - The value to check.\n * @returns `true` if the value is an `ElementRef` object, `false` otherwise.\n */\n const isElementRef = (value: any): value is ElementRef => {\n return value && value.$el instanceof HTMLElement\n }\n\n /** Updates the number of columns rendered inside the grid. */\n function updateRenderedColumnsNumber() {\n const { gridTemplateColumns } = getComputedStyle(\n isElementRef(gridEl.value) ? gridEl.value.$el : (gridEl.value as Element),\n )\n renderedColumnsNumber.value = gridTemplateColumns.split(' ').length\n }\n\n /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */\n let resizeObserver: UseResizeObserverReturn\n onMounted(() => {\n resizeObserver = useResizeObserver(\n gridEl as MaybeComputedElementRef,\n updateRenderedColumnsNumber,\n )\n })\n onBeforeUnmount(() => resizeObserver?.stop())\n\n return {\n gridItems,\n cssClasses,\n style,\n gridEl,\n slots,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-base-grid {\n display: grid;\n grid-auto-flow: dense;\n list-style: none;\n align-items: stretch;\n}\n\n.x-base-grid__banner,\n.x-base-grid__next-queries-group,\n.x-base-grid__related-prompts-group {\n grid-column-start: 1;\n grid-column-end: -1;\n}\n\n.x-base-grid__item {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-grid__item > * {\n flex-grow: 1;\n}\n\n.x-base-grid--cols-auto .x-base-grid__item {\n min-width: var(--x-size-min-width-grid-item);\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a list of elements in different slots depending on their modelName. In order\nto achieve this, it exposes a scopedSlot for each different modelName. In case the items used do not\nhave modelName property, the default slot is used instead. It has a required property, the `items`\nto render, and an optional one, the number of `columns` the grid is divided in. If the number of\ncolumns is not specified, the grid automatically fills the rows with as many columns as it can fit.\n\n### Basic example\n\nIt renders a list of items using the default slot:\n\n```vue\n<template>\n <BaseGrid :items=\"items\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Configuring the number of columns\n\nIt renders a grid with 12 columns instead of 6, which is the default value:\n\n```vue\n<template>\n <BaseGrid :items=\"items\" :columns=\"12\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Rendering usage\n\nConfiguring the number of columns.\n\nIt renders a list of items using the different scopedSlots created by the item's modelName. For\nexample, if you want to use this component as the search grid, you pass the search results (results,\nbanners, promoted, next queries...etc) as items. Each of these results have a different modelName\nand are rendered in different slots.\n\n```vue\n<template>\n <BaseGrid :animation=\"animation\" :items=\"items\">\n <template #banner=\"{ item }\">\n <span class=\"banner\">\n {{ `${item.title} banner` }}\n </span>\n </template>\n <template #next-queries=\"{ item }\">\n <span>\n {{ `${item.totalResults} next queries` }}\n </span>\n </template>\n <template #promoted=\"{ item }\">\n <span class=\"promoted\">\n {{ `${item.title} promoted` }}\n </span>\n </template>\n <template #result=\"{ item }\">\n <BaseResultLink :result=\"item\">\n {{ item.name }}\n </BaseResultLink>\n </template>\n </BaseGrid>\n</template>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseGrid :items=\"items\" style=\"--x-size-min-width-grid-item: 150px\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n</docs>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-grid.vue2.js","sources":["../../../src/components/base-grid.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n ref=\"gridEl\"\n :style=\"style\"\n class=\"x-base-grid\"\n :class=\"cssClasses\"\n tag=\"ul\"\n data-test=\"grid\"\n >\n <li\n v-for=\"{ item, cssClass, slotName } in gridItems\"\n :key=\"item.id\"\n :class=\"cssClass\"\n class=\"x-base-grid__item\"\n >\n <!--\n @slot Customized item rendering. Specifying a slot with the item's modelName will result in\n the item using that slot composition to render.\n @binding {item} item - Item to render\n -->\n <slot v-if=\"slots[slotName]\" :name=\"slotName\" :item=\"item\" />\n <!--\n @slot (required) Default item rendering. This slot will be used by default for rendering\n the item without an specific slot implementation.\n @binding {item} item - Item to render\n -->\n <slot v-else :item=\"item\">{{ item.name || item.modelName || item.id || item }}</slot>\n </li>\n </component>\n</template>\n\n<script lang=\"ts\">\nimport type { MaybeComputedElementRef, UseResizeObserverReturn } from '@vueuse/core'\nimport type { PropType, Ref } from 'vue'\nimport type { ListItem, VueCSSClasses } from '../utils/types'\nimport { useResizeObserver } from '@vueuse/core'\nimport { computed, defineComponent, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useXBus } from '../composables/use-x-bus'\nimport { AnimationProp } from '../types/animation-prop'\nimport { toKebabCase } from '../utils/string'\nimport { LIST_ITEMS_KEY } from './decorators/injection.consts'\n\n/**\n * The type returned by the gridItems function. Basically it's a list of items with its CSS\n * classes and a slotName.\n */\ninterface GridItem {\n slotName: string\n item: ListItem\n cssClass: VueCSSClasses\n}\n\n/**\n * Grid component that is able to render different items based on their modelName value. In order\n * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used\n * do not have modelName property, the default slot is used instead. It has a required property:\n * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the\n * number of columns is not specified, the grid automatically fills the rows with as many columns\n * as it can fit.\n *\n * @public\n */\nexport default defineComponent({\n name: 'BaseGrid',\n props: {\n /** Animation component that will be used to animate the base grid. */\n animation: {\n type: AnimationProp,\n default: 'ul',\n },\n /**\n * Number of columns the grid is divided into. By default, its value is 0, setting the grid\n * columns mode to auto-fill.\n */\n columns: {\n type: Number,\n default: 0,\n },\n /**\n * The list of items to be rendered.\n *\n * @remarks The items must have an ID property.\n */\n items: {\n type: Array as PropType<ListItem[]>,\n },\n },\n setup(props, { slots }) {\n // eslint-disable-next-line ts/consistent-type-definitions\n type ElementRef = {\n $el: HTMLElement\n }\n\n const xBus = useXBus()\n\n /** It injects {@link ListItem} provided by an ancestor. */\n const injectedListItems = inject<Ref<ListItem[]>>(LIST_ITEMS_KEY as string)\n const gridEl = ref<ElementRef | HTMLElement>()\n const renderedColumnsNumber = ref(0)\n\n /**\n * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged}\n * event whenever the number of columns rendered inside the grid changes.\n */\n watch(\n renderedColumnsNumber,\n () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value),\n { immediate: false },\n )\n\n /**\n * It returns the items passed as props or the injected ones.\n *\n * @returns List of grid items.\n */\n const computedItems = computed<ListItem[] | void>(() => {\n return (\n props.items ??\n injectedListItems?.value ??\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * CSS class based on the column property value so items inside the grid can fill different\n * amount of columns or rows based on how many columns the grid is divided into.\n *\n * @returns CSS class with the column property value.\n */\n const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`)\n\n /**\n * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on\n * the column property value.\n *\n * @returns A CSSStyleDeclaration to use as the style attribute.\n */\n const style = computed<Partial<CSSStyleDeclaration>>(() => ({\n gridTemplateColumns: props.columns\n ? `repeat(${props.columns}, minmax(0, 1fr))`\n : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))',\n }))\n\n /**\n * Maps the item to an object containing: the `item`, its `CSS class` and its slot name.\n *\n * @returns An array of objects containing the item and its CSS class.\n */\n const gridItems = computed<GridItem[]>(() =>\n (computedItems.value as ListItem[]).map(item => {\n const slotName = toKebabCase(item.modelName)\n return {\n slotName,\n item,\n cssClass: `x-base-grid__${slotName}`,\n }\n }),\n )\n\n /**\n * Checks if a given value is an `ElementRef` object.\n *\n * @param value - The value to check.\n * @returns `true` if the value is an `ElementRef` object, `false` otherwise.\n */\n const isElementRef = (value: any): value is ElementRef => {\n return value && value.$el instanceof HTMLElement\n }\n\n /** Updates the number of columns rendered inside the grid. */\n function updateRenderedColumnsNumber() {\n const { gridTemplateColumns } = getComputedStyle(\n isElementRef(gridEl.value) ? gridEl.value.$el : (gridEl.value as Element),\n )\n renderedColumnsNumber.value = gridTemplateColumns.split(' ').length\n }\n\n /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */\n let resizeObserver: UseResizeObserverReturn\n onMounted(() => {\n resizeObserver = useResizeObserver(\n gridEl as MaybeComputedElementRef,\n updateRenderedColumnsNumber,\n )\n })\n onBeforeUnmount(() => resizeObserver?.stop())\n\n return {\n gridItems,\n cssClasses,\n style,\n gridEl,\n slots,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-base-grid {\n display: grid;\n grid-auto-flow: dense;\n list-style: none;\n align-items: stretch;\n}\n\n.x-base-grid__banner,\n.x-base-grid__next-queries-group,\n.x-base-grid__related-prompts-group {\n grid-column-start: 1;\n grid-column-end: -1;\n}\n\n.x-base-grid__item {\n display: flex;\n flex-flow: column nowrap;\n}\n\n.x-base-grid__item > * {\n flex-grow: 1;\n}\n\n.x-base-grid--cols-auto .x-base-grid__item {\n min-width: var(--x-size-min-width-grid-item);\n}\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThis component renders a list of elements in different slots depending on their modelName. In order\nto achieve this, it exposes a scopedSlot for each different modelName. In case the items used do not\nhave modelName property, the default slot is used instead. It has a required property, the `items`\nto render, and an optional one, the number of `columns` the grid is divided in. If the number of\ncolumns is not specified, the grid automatically fills the rows with as many columns as it can fit.\n\n### Basic example\n\nIt renders a list of items using the default slot:\n\n```vue\n<template>\n <BaseGrid :items=\"items\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Configuring the number of columns\n\nIt renders a grid with 12 columns instead of 6, which is the default value:\n\n```vue\n<template>\n <BaseGrid :items=\"items\" :columns=\"12\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n\n### Rendering usage\n\nConfiguring the number of columns.\n\nIt renders a list of items using the different scopedSlots created by the item's modelName. For\nexample, if you want to use this component as the search grid, you pass the search results (results,\nbanners, promoted, next queries...etc) as items. Each of these results have a different modelName\nand are rendered in different slots.\n\n```vue\n<template>\n <BaseGrid :animation=\"animation\" :items=\"items\">\n <template #banner=\"{ item }\">\n <span class=\"banner\">\n {{ `${item.title} banner` }}\n </span>\n </template>\n <template #next-queries=\"{ item }\">\n <span>\n {{ `${item.totalResults} next queries` }}\n </span>\n </template>\n <template #promoted=\"{ item }\">\n <span class=\"promoted\">\n {{ `${item.title} promoted` }}\n </span>\n </template>\n <template #result=\"{ item }\">\n <BaseResultLink :result=\"item\">\n {{ item.name }}\n </BaseResultLink>\n </template>\n </BaseGrid>\n</template>\n```\n\n### Customizing the items width\n\nThe `--x-size-min-width-grid-item` variable can be used to customize the min width of the grid\nitems.\n\n```vue\n<template>\n <BaseGrid :items=\"items\" style=\"--x-size-min-width-grid-item: 150px\">\n <template #default=\"{ item }\">\n {{ `Default slot content: ${item.id}` }}\n </template>\n </BaseGrid>\n</template>\n```\n</docs>\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result-variant-selector.vue.js","sources":["../../../../src/components/result/result-variant-selector.vue"],"sourcesContent":["<template>\n <ul v-if=\"result && variants\" class=\"x-result-variant-selector__list\" data-test=\"variants-list\">\n <li\n v-for=\"(variant, index) in variants\"\n :key=\"index\"\n class=\"x-result-variant-selector__item\"\n :class=\"{ 'x-result-variant-selector__item--is-selected': variantIsSelected(variant) }\"\n data-test=\"variant-item\"\n >\n <!--\n @slot Variant item\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n @binding {() => void} selectVariant - Callback to select the variant\n -->\n <slot\n name=\"variant\"\n :variant=\"variant\"\n :is-selected=\"variantIsSelected(variant)\"\n :select-variant=\"() => selectVariant(variant)\"\n >\n <button data-test=\"variant-button\" class=\"x-button\" @click=\"selectVariant(variant)\">\n <!--\n @slot Variant content\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n -->\n <slot name=\"variant-content\" :variant=\"variant\" :is-selected=\"variantIsSelected(variant)\">\n {{ variant }}\n </slot>\n </button>\n </slot>\n </li>\n </ul>\n</template>\n\n<script lang=\"ts\">\nimport type { Result, ResultVariant } from '@empathyco/x-types'\nimport type { Ref } from 'vue'\nimport { computed, defineComponent, inject } from 'vue'\nimport {\n RESULT_WITH_VARIANTS_KEY,\n SELECT_RESULT_VARIANT_KEY,\n SELECTED_VARIANTS_KEY,\n} from '../decorators/injection.consts'\n\n/**\n * Component to show and select the available variants of a product for a given nest level.\n * TODO: Add logger warning on mount when result is not injected.\n *\n * @public\n */\nexport default defineComponent({\n name: 'ResultVariantSelector',\n props: {\n /** The nest level of the variants to be rendered. */\n level: {\n type: Number,\n default: 0,\n },\n },\n setup(props, { slots }) {\n /**\n * Callback to be called when a variant is selected.\n *\n * @public\n * @returns The 'selectResultVariant' injection key.\n */\n const selectResultVariant = inject<(variant: ResultVariant, level?: number) => void>(\n SELECT_RESULT_VARIANT_KEY as string,\n )\n\n /** The original result, used to retrieve the available variants for the level. */\n const result = inject<Ref<Result>>(RESULT_WITH_VARIANTS_KEY as string)\n\n /** Array containing the selected variants. */\n const selectedVariants = inject<Ref<ResultVariant[]>>(SELECTED_VARIANTS_KEY as string)\n\n /**\n * It retrieves the available variants from the result.\n *\n * @returns - The variants of the result for the current level.\n */\n const variants = computed<ResultVariant[] | undefined>(() => {\n if (props.level === 0) {\n return result!.value?.variants\n }\n return selectedVariants!.value[props.level - 1]?.variants\n })\n\n /**\n * Gets the selected variant of the current level.\n *\n * @returns - The selected variant.\n */\n const selectedVariant = computed<ResultVariant | undefined>(() =>\n variants.value?.find(variant => variant === selectedVariants!.value[props.level]),\n )\n\n /**\n * Calls the provided method to select a variant.\n *\n * @param variant - Variant to select.\n */\n const selectVariant = (variant: ResultVariant) => {\n selectResultVariant!(variant, props.level)\n }\n\n /**\n * Checks if a variant is selected.\n *\n * @param variant - Variant to check.\n * @returns True if the variant is selected, false if not.\n */\n const variantIsSelected = (variant: ResultVariant) => {\n return selectedVariant.value === variant\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no result or variants, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no result or variants.\n */\n function renderDefaultSlot() {\n const slotProps = {\n variants: variants.value,\n selectedVariant: selectedVariant.value,\n selectVariant,\n }\n return result && variants.value ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { result, variants, variantIsSelected, selectVariant }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-result-variant-selector__list {\n display: flex;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nHere you have a basic example of how the `ResultVariantSelector` component is rendered.\n\nTake into account that this component **must** be a child of a `ResultVariantsProvider` component.\n\nAlso, the component is intended to be used overwriting the content with the slots.\n\nBy default it will render a list of buttons containing the available variants.\n\nThis component only has a required `level` prop, that indicates the level of the variants to be\nrendered.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <h1>Select color</h1>\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, selectVariant }\" />\n\n <h1>Select size</h1>\n <ResultVariantSelector :level=\"1\" #variant=\"{ variant, selectVariant }\" />\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n variants: [\n {\n name: 'red XL',\n },\n {\n name: 'red L',\n },\n ],\n },\n {\n name: 'blue',\n variants: [\n {\n name: 'blue S',\n },\n {\n name: 'blue M',\n },\n {\n name: 'blue L',\n },\n ],\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nIn this example the default slot is used to customize the list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #default=\"{ variants, selectedVariant, selectVariant }\">\n <div>\n <p v-if=\"selectedVariant\">Selected variant: {{ selectedVariant.name }}</p>\n <ul class=\"x-flex\">\n <li v-for=\"(variant, index) in variants\" :key=\"index\">\n <button @click=\"selectVariant(variant)\">{{ variant.name }}</button>\n </li>\n </ul>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-slot\n\nIn this example the variant-slot is used to customize the variant item.\n\nThe variant will be rendered inside a list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, isSelected, selectVariant }\">\n <div>\n <button @click=\"selectVariant\">\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </button>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-content slot\n\nIn this example the variant-content slot is used to customize the content of the default variant\nbutton.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector #variant-content=\"{ variant, isSelected }\">\n <div>\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_renderSlot","variantIsSelected","_createElementVNode","_toDisplayString","_createCommentVNode"],"mappings":";;;;;MACgC,UAAM,GAAA;AAAA,EAAkC,GAAA,EAAA,CAAA;AAAA,EAAA,KAAA,EAAA,iCAAA;;;;AAAtE,SAAA,WAAA,CAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAgCK,QAhCL,KAgCK,EAAA,QAAA,EAAA;6BA/BH,QA8BK,IAAAA,SAAA,EAAA,EAAAC,kBAAA,CAAA,IAAA,EAAA,UAAA,EAAA;AAAA,KAAAD,SAAA,CA5BG,IAAK,CAAA,EAAAC,kBAAA;AAAA,MAAAC,QAAA;AAAA,MAAA,IAAA;AAAA,MAAAC,UAAA,CAAA,IAAA,CAAA,QAAA,EAAA,CAAA,OAAA,EAAA,KAAA,KAAA;eACNH,SALX,EAAA,EAAAC,kBAAA;AAAA,UAKY,IAAA;AAAA,UAAA;AAAA,YAEN,GAAA,EAAA,KAAA;AAAA,YAAA,KAAA,EAAAG,cAAA,CAAA,CAAA,iCAAA,EAAA,EAAA,8CAAA,EAAA,IAAA,CAAA,iBAAA,CAAA,OAAA,CAAA,EAAA,CAAA,CAAA;YAQA,WAgBO,EAAA,cAAA;AAAA,WAAA;;AAbO,YAAAC,UAAA,CAAA,IAAA,CAAEC,MAAiB,EAAA,SAAA,EAAA;AAAA,cAC9B,OAAA;AAAA,cAYI,UAAA,EAAA,IAAA,CAAA,iBAAA,CAAA,OAAA,CAAA;AAAA,cAVL,aASS,EAAA,MAAA,IAAA,CAAA,aAAA,CAAA,OAAA,CAAA;AAAA,aATD,EAAA,MAAA;AAAA,cAA2CC,kBAAA,CAAA,QAAA,EAAA;AAAA,gBAAE,WAAK,EAAA,gBAAA;AAAA,gBAAA,KAAA,EAAA,UAAA;gBAMxD,OAEO,EAAA,CAAA,MAAA,KAAA,IAAA,CAAA,aAAA,CAAA,OAAA,CAAA;AAAA,eAAA,EAAA;AAFqD,gBAAAF,UAAA,CAAA,IAAA,CAAEC,MAAyB,EAAA,iBAAA,EAAA;AAAA,kBAAA,OAAA;AA3BjG,kBAAA,UAAA,EAAA,IAAA,CAAA,iBAAA,CA4Be,OAAO,CAAA;AAAA,iBAAA,EAAA,MAAA;;AA5BtB,oBAAAE,eAAA,CAAA,OAAA,CAAA;AAAA,oBAAA,CAAA;AAAA;AAAA,mBAAA;AAAA,iBAAA,EAAA,IAAA,CAAA;;;;;;;AAAA,OAAA,CAAA;AAAA,MAAA,GAAA;AAAA;AAAA,KAAA;AAAA,GAAA,CAAA,IAAAC,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA,CAAA;;;;;;"}
|
|
1
|
+
{"version":3,"file":"result-variant-selector.vue.js","sources":["../../../../src/components/result/result-variant-selector.vue"],"sourcesContent":["<template>\n <ul v-if=\"result && variants\" class=\"x-result-variant-selector__list\" data-test=\"variants-list\">\n <li\n v-for=\"(variant, index) in variants\"\n :key=\"index\"\n class=\"x-result-variant-selector__item\"\n :class=\"{ 'x-result-variant-selector__item--is-selected': variantIsSelected(variant) }\"\n data-test=\"variant-item\"\n >\n <!--\n @slot Variant item\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n @binding {() => void} selectVariant - Callback to select the variant\n -->\n <slot\n name=\"variant\"\n :variant=\"variant\"\n :is-selected=\"variantIsSelected(variant)\"\n :select-variant=\"() => selectVariant(variant)\"\n >\n <button data-test=\"variant-button\" class=\"x-button\" @click=\"selectVariant(variant)\">\n <!--\n @slot Variant content\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n -->\n <slot name=\"variant-content\" :variant=\"variant\" :is-selected=\"variantIsSelected(variant)\">\n {{ variant }}\n </slot>\n </button>\n </slot>\n </li>\n </ul>\n</template>\n\n<script lang=\"ts\">\nimport type { Result, ResultVariant } from '@empathyco/x-types'\nimport type { Ref } from 'vue'\nimport { computed, defineComponent, inject } from 'vue'\nimport {\n RESULT_WITH_VARIANTS_KEY,\n SELECT_RESULT_VARIANT_KEY,\n SELECTED_VARIANTS_KEY,\n} from '../decorators/injection.consts'\n\n/**\n * Component to show and select the available variants of a product for a given nest level.\n * TODO: Log warning on mount when result is not injected.\n *\n * @public\n */\nexport default defineComponent({\n name: 'ResultVariantSelector',\n props: {\n /** The nest level of the variants to be rendered. */\n level: {\n type: Number,\n default: 0,\n },\n },\n setup(props, { slots }) {\n /**\n * Callback to be called when a variant is selected.\n *\n * @public\n * @returns The 'selectResultVariant' injection key.\n */\n const selectResultVariant = inject<(variant: ResultVariant, level?: number) => void>(\n SELECT_RESULT_VARIANT_KEY as string,\n )\n\n /** The original result, used to retrieve the available variants for the level. */\n const result = inject<Ref<Result>>(RESULT_WITH_VARIANTS_KEY as string)\n\n /** Array containing the selected variants. */\n const selectedVariants = inject<Ref<ResultVariant[]>>(SELECTED_VARIANTS_KEY as string)\n\n /**\n * It retrieves the available variants from the result.\n *\n * @returns - The variants of the result for the current level.\n */\n const variants = computed<ResultVariant[] | undefined>(() => {\n if (props.level === 0) {\n return result!.value?.variants\n }\n return selectedVariants!.value[props.level - 1]?.variants\n })\n\n /**\n * Gets the selected variant of the current level.\n *\n * @returns - The selected variant.\n */\n const selectedVariant = computed<ResultVariant | undefined>(() =>\n variants.value?.find(variant => variant === selectedVariants!.value[props.level]),\n )\n\n /**\n * Calls the provided method to select a variant.\n *\n * @param variant - Variant to select.\n */\n const selectVariant = (variant: ResultVariant) => {\n selectResultVariant!(variant, props.level)\n }\n\n /**\n * Checks if a variant is selected.\n *\n * @param variant - Variant to check.\n * @returns True if the variant is selected, false if not.\n */\n const variantIsSelected = (variant: ResultVariant) => {\n return selectedVariant.value === variant\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no result or variants, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no result or variants.\n */\n function renderDefaultSlot() {\n const slotProps = {\n variants: variants.value,\n selectedVariant: selectedVariant.value,\n selectVariant,\n }\n return result && variants.value ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { result, variants, variantIsSelected, selectVariant }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-result-variant-selector__list {\n display: flex;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nHere you have a basic example of how the `ResultVariantSelector` component is rendered.\n\nTake into account that this component **must** be a child of a `ResultVariantsProvider` component.\n\nAlso, the component is intended to be used overwriting the content with the slots.\n\nBy default it will render a list of buttons containing the available variants.\n\nThis component only has a required `level` prop, that indicates the level of the variants to be\nrendered.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <h1>Select color</h1>\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, selectVariant }\" />\n\n <h1>Select size</h1>\n <ResultVariantSelector :level=\"1\" #variant=\"{ variant, selectVariant }\" />\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n variants: [\n {\n name: 'red XL',\n },\n {\n name: 'red L',\n },\n ],\n },\n {\n name: 'blue',\n variants: [\n {\n name: 'blue S',\n },\n {\n name: 'blue M',\n },\n {\n name: 'blue L',\n },\n ],\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nIn this example the default slot is used to customize the list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #default=\"{ variants, selectedVariant, selectVariant }\">\n <div>\n <p v-if=\"selectedVariant\">Selected variant: {{ selectedVariant.name }}</p>\n <ul class=\"x-flex\">\n <li v-for=\"(variant, index) in variants\" :key=\"index\">\n <button @click=\"selectVariant(variant)\">{{ variant.name }}</button>\n </li>\n </ul>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-slot\n\nIn this example the variant-slot is used to customize the variant item.\n\nThe variant will be rendered inside a list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, isSelected, selectVariant }\">\n <div>\n <button @click=\"selectVariant\">\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </button>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-content slot\n\nIn this example the variant-content slot is used to customize the content of the default variant\nbutton.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector #variant-content=\"{ variant, isSelected }\">\n <div>\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_renderSlot","variantIsSelected","_createElementVNode","_toDisplayString","_createCommentVNode"],"mappings":";;;;;MACgC,UAAM,GAAA;AAAA,EAAkC,GAAA,EAAA,CAAA;AAAA,EAAA,KAAA,EAAA,iCAAA;;;;AAAtE,SAAA,WAAA,CAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAgCK,QAhCL,KAgCK,EAAA,QAAA,EAAA;6BA/BH,QA8BK,IAAAA,SAAA,EAAA,EAAAC,kBAAA,CAAA,IAAA,EAAA,UAAA,EAAA;AAAA,KAAAD,SAAA,CA5BG,IAAK,CAAA,EAAAC,kBAAA;AAAA,MAAAC,QAAA;AAAA,MAAA,IAAA;AAAA,MAAAC,UAAA,CAAA,IAAA,CAAA,QAAA,EAAA,CAAA,OAAA,EAAA,KAAA,KAAA;eACNH,SALX,EAAA,EAAAC,kBAAA;AAAA,UAKY,IAAA;AAAA,UAAA;AAAA,YAEN,GAAA,EAAA,KAAA;AAAA,YAAA,KAAA,EAAAG,cAAA,CAAA,CAAA,iCAAA,EAAA,EAAA,8CAAA,EAAA,IAAA,CAAA,iBAAA,CAAA,OAAA,CAAA,EAAA,CAAA,CAAA;YAQA,WAgBO,EAAA,cAAA;AAAA,WAAA;;AAbO,YAAAC,UAAA,CAAA,IAAA,CAAEC,MAAiB,EAAA,SAAA,EAAA;AAAA,cAC9B,OAAA;AAAA,cAYI,UAAA,EAAA,IAAA,CAAA,iBAAA,CAAA,OAAA,CAAA;AAAA,cAVL,aASS,EAAA,MAAA,IAAA,CAAA,aAAA,CAAA,OAAA,CAAA;AAAA,aATD,EAAA,MAAA;AAAA,cAA2CC,kBAAA,CAAA,QAAA,EAAA;AAAA,gBAAE,WAAK,EAAA,gBAAA;AAAA,gBAAA,KAAA,EAAA,UAAA;gBAMxD,OAEO,EAAA,CAAA,MAAA,KAAA,IAAA,CAAA,aAAA,CAAA,OAAA,CAAA;AAAA,eAAA,EAAA;AAFqD,gBAAAF,UAAA,CAAA,IAAA,CAAEC,MAAyB,EAAA,iBAAA,EAAA;AAAA,kBAAA,OAAA;AA3BjG,kBAAA,UAAA,EAAA,IAAA,CAAA,iBAAA,CA4Be,OAAO,CAAA;AAAA,iBAAA,EAAA,MAAA;;AA5BtB,oBAAAE,eAAA,CAAA,OAAA,CAAA;AAAA,oBAAA,CAAA;AAAA;AAAA,mBAAA;AAAA,iBAAA,EAAA,IAAA,CAAA;;;;;;;AAAA,OAAA,CAAA;AAAA,MAAA,GAAA;AAAA;AAAA,KAAA;AAAA,GAAA,CAAA,IAAAC,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA,CAAA;;;;;;"}
|
|
@@ -3,7 +3,7 @@ import { SELECT_RESULT_VARIANT_KEY, RESULT_WITH_VARIANTS_KEY, SELECTED_VARIANTS_
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Component to show and select the available variants of a product for a given nest level.
|
|
6
|
-
* TODO:
|
|
6
|
+
* TODO: Log warning on mount when result is not injected.
|
|
7
7
|
*
|
|
8
8
|
* @public
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result-variant-selector.vue2.js","sources":["../../../../src/components/result/result-variant-selector.vue"],"sourcesContent":["<template>\n <ul v-if=\"result && variants\" class=\"x-result-variant-selector__list\" data-test=\"variants-list\">\n <li\n v-for=\"(variant, index) in variants\"\n :key=\"index\"\n class=\"x-result-variant-selector__item\"\n :class=\"{ 'x-result-variant-selector__item--is-selected': variantIsSelected(variant) }\"\n data-test=\"variant-item\"\n >\n <!--\n @slot Variant item\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n @binding {() => void} selectVariant - Callback to select the variant\n -->\n <slot\n name=\"variant\"\n :variant=\"variant\"\n :is-selected=\"variantIsSelected(variant)\"\n :select-variant=\"() => selectVariant(variant)\"\n >\n <button data-test=\"variant-button\" class=\"x-button\" @click=\"selectVariant(variant)\">\n <!--\n @slot Variant content\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n -->\n <slot name=\"variant-content\" :variant=\"variant\" :is-selected=\"variantIsSelected(variant)\">\n {{ variant }}\n </slot>\n </button>\n </slot>\n </li>\n </ul>\n</template>\n\n<script lang=\"ts\">\nimport type { Result, ResultVariant } from '@empathyco/x-types'\nimport type { Ref } from 'vue'\nimport { computed, defineComponent, inject } from 'vue'\nimport {\n RESULT_WITH_VARIANTS_KEY,\n SELECT_RESULT_VARIANT_KEY,\n SELECTED_VARIANTS_KEY,\n} from '../decorators/injection.consts'\n\n/**\n * Component to show and select the available variants of a product for a given nest level.\n * TODO: Add logger warning on mount when result is not injected.\n *\n * @public\n */\nexport default defineComponent({\n name: 'ResultVariantSelector',\n props: {\n /** The nest level of the variants to be rendered. */\n level: {\n type: Number,\n default: 0,\n },\n },\n setup(props, { slots }) {\n /**\n * Callback to be called when a variant is selected.\n *\n * @public\n * @returns The 'selectResultVariant' injection key.\n */\n const selectResultVariant = inject<(variant: ResultVariant, level?: number) => void>(\n SELECT_RESULT_VARIANT_KEY as string,\n )\n\n /** The original result, used to retrieve the available variants for the level. */\n const result = inject<Ref<Result>>(RESULT_WITH_VARIANTS_KEY as string)\n\n /** Array containing the selected variants. */\n const selectedVariants = inject<Ref<ResultVariant[]>>(SELECTED_VARIANTS_KEY as string)\n\n /**\n * It retrieves the available variants from the result.\n *\n * @returns - The variants of the result for the current level.\n */\n const variants = computed<ResultVariant[] | undefined>(() => {\n if (props.level === 0) {\n return result!.value?.variants\n }\n return selectedVariants!.value[props.level - 1]?.variants\n })\n\n /**\n * Gets the selected variant of the current level.\n *\n * @returns - The selected variant.\n */\n const selectedVariant = computed<ResultVariant | undefined>(() =>\n variants.value?.find(variant => variant === selectedVariants!.value[props.level]),\n )\n\n /**\n * Calls the provided method to select a variant.\n *\n * @param variant - Variant to select.\n */\n const selectVariant = (variant: ResultVariant) => {\n selectResultVariant!(variant, props.level)\n }\n\n /**\n * Checks if a variant is selected.\n *\n * @param variant - Variant to check.\n * @returns True if the variant is selected, false if not.\n */\n const variantIsSelected = (variant: ResultVariant) => {\n return selectedVariant.value === variant\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no result or variants, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no result or variants.\n */\n function renderDefaultSlot() {\n const slotProps = {\n variants: variants.value,\n selectedVariant: selectedVariant.value,\n selectVariant,\n }\n return result && variants.value ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { result, variants, variantIsSelected, selectVariant }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-result-variant-selector__list {\n display: flex;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nHere you have a basic example of how the `ResultVariantSelector` component is rendered.\n\nTake into account that this component **must** be a child of a `ResultVariantsProvider` component.\n\nAlso, the component is intended to be used overwriting the content with the slots.\n\nBy default it will render a list of buttons containing the available variants.\n\nThis component only has a required `level` prop, that indicates the level of the variants to be\nrendered.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <h1>Select color</h1>\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, selectVariant }\" />\n\n <h1>Select size</h1>\n <ResultVariantSelector :level=\"1\" #variant=\"{ variant, selectVariant }\" />\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n variants: [\n {\n name: 'red XL',\n },\n {\n name: 'red L',\n },\n ],\n },\n {\n name: 'blue',\n variants: [\n {\n name: 'blue S',\n },\n {\n name: 'blue M',\n },\n {\n name: 'blue L',\n },\n ],\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nIn this example the default slot is used to customize the list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #default=\"{ variants, selectedVariant, selectVariant }\">\n <div>\n <p v-if=\"selectedVariant\">Selected variant: {{ selectedVariant.name }}</p>\n <ul class=\"x-flex\">\n <li v-for=\"(variant, index) in variants\" :key=\"index\">\n <button @click=\"selectVariant(variant)\">{{ variant.name }}</button>\n </li>\n </ul>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-slot\n\nIn this example the variant-slot is used to customize the variant item.\n\nThe variant will be rendered inside a list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, isSelected, selectVariant }\">\n <div>\n <button @click=\"selectVariant\">\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </button>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-content slot\n\nIn this example the variant-content slot is used to customize the content of the default variant\nbutton.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector #variant-content=\"{ variant, isSelected }\">\n <div>\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;AA8CA;;;;;AAKE;AACF,gBAAe,eAAe,CAAC;AAC7B,IAAA,IAAI,EAAE,uBAAuB;AAC7B,IAAA,KAAK,EAAE;;AAEL,QAAA,KAAK,EAAE;AACL,YAAA,IAAI,EAAE,MAAM;AACZ,YAAA,OAAO,EAAE,CAAC;AACX,SAAA;AACF,KAAA;AACD,IAAA,KAAK,CAAC,KAAK,EAAE,EAAE,KAAI,EAAG,EAAA;AACpB;;;;;AAKE;AACF,QAAA,MAAM,mBAAoB,GAAE,MAAM,CAChC,yBAAmC,CACrC,CAAA;;AAGA,QAAA,MAAM,MAAK,GAAI,MAAM,CAAc,wBAAkC,CAAA,CAAA;;AAGrE,QAAA,MAAM,gBAAe,GAAI,MAAM,CAAuB,qBAA+B,CAAA,CAAA;AAErF;;;;AAIE;AACF,QAAA,MAAM,QAAO,GAAI,QAAQ,CAA8B,MAAM;AAC3D,YAAA,IAAI,KAAK,CAAC,KAAI,KAAM,CAAC,EAAE;AACrB,gBAAA,OAAO,MAAO,CAAC,KAAK,EAAE,QAAO,CAAA;AAC/B,aAAA;AACA,YAAA,OAAO,gBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAO,CAAA;AAC1D,SAAC,CAAA,CAAA;AAED;;;;AAIE;AACF,QAAA,MAAM,eAAgB,GAAE,QAAQ,CAA4B,MAC1D,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,OAAM,IAAK,OAAQ,KAAI,gBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CACnF,CAAA;AAEA;;;;AAIE;AACF,QAAA,MAAM,aAAc,GAAE,CAAC,OAAsB,KAAK;AAChD,YAAA,mBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAA,CAAA;AAC3C,SAAA,CAAA;AAEA;;;;;AAKE;AACF,QAAA,MAAM,iBAAgB,GAAI,CAAC,OAAsB,KAAK;AACpD,YAAA,OAAO,eAAe,CAAC,KAAI,KAAM,OAAM,CAAA;AACzC,SAAA,CAAA;AAEA;;;;;;;;;;AAUE;AACF,QAAA,SAAS,iBAAiB,GAAA;AACxB,YAAA,MAAM,YAAY;gBAChB,QAAQ,EAAE,QAAQ,CAAC,KAAK;gBACxB,eAAe,EAAE,eAAe,CAAC,KAAK;gBACtC,aAAa;aACf,CAAA;YACA,OAAO,MAAK,IAAK,QAAQ,CAAC,KAAI,GAAI,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAE,GAAE,EAAC,CAAA;SACrE;AAEA;AAC+E;QAC/E,MAAM,cAAe,GAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAc,EAAA,CAAA;AAC5E,QAAA,QAAQ,KAAK,CAAC,OAAM,GAAI,iBAAkB,GAAE,cAAc,EAAyB;KACpF;AACF,CAAA,CAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"result-variant-selector.vue2.js","sources":["../../../../src/components/result/result-variant-selector.vue"],"sourcesContent":["<template>\n <ul v-if=\"result && variants\" class=\"x-result-variant-selector__list\" data-test=\"variants-list\">\n <li\n v-for=\"(variant, index) in variants\"\n :key=\"index\"\n class=\"x-result-variant-selector__item\"\n :class=\"{ 'x-result-variant-selector__item--is-selected': variantIsSelected(variant) }\"\n data-test=\"variant-item\"\n >\n <!--\n @slot Variant item\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n @binding {() => void} selectVariant - Callback to select the variant\n -->\n <slot\n name=\"variant\"\n :variant=\"variant\"\n :is-selected=\"variantIsSelected(variant)\"\n :select-variant=\"() => selectVariant(variant)\"\n >\n <button data-test=\"variant-button\" class=\"x-button\" @click=\"selectVariant(variant)\">\n <!--\n @slot Variant content\n @binding {ResultVariant} variant - The variant item\n @binding {boolean} isSelected - Indicates if the variant is selected\n -->\n <slot name=\"variant-content\" :variant=\"variant\" :is-selected=\"variantIsSelected(variant)\">\n {{ variant }}\n </slot>\n </button>\n </slot>\n </li>\n </ul>\n</template>\n\n<script lang=\"ts\">\nimport type { Result, ResultVariant } from '@empathyco/x-types'\nimport type { Ref } from 'vue'\nimport { computed, defineComponent, inject } from 'vue'\nimport {\n RESULT_WITH_VARIANTS_KEY,\n SELECT_RESULT_VARIANT_KEY,\n SELECTED_VARIANTS_KEY,\n} from '../decorators/injection.consts'\n\n/**\n * Component to show and select the available variants of a product for a given nest level.\n * TODO: Log warning on mount when result is not injected.\n *\n * @public\n */\nexport default defineComponent({\n name: 'ResultVariantSelector',\n props: {\n /** The nest level of the variants to be rendered. */\n level: {\n type: Number,\n default: 0,\n },\n },\n setup(props, { slots }) {\n /**\n * Callback to be called when a variant is selected.\n *\n * @public\n * @returns The 'selectResultVariant' injection key.\n */\n const selectResultVariant = inject<(variant: ResultVariant, level?: number) => void>(\n SELECT_RESULT_VARIANT_KEY as string,\n )\n\n /** The original result, used to retrieve the available variants for the level. */\n const result = inject<Ref<Result>>(RESULT_WITH_VARIANTS_KEY as string)\n\n /** Array containing the selected variants. */\n const selectedVariants = inject<Ref<ResultVariant[]>>(SELECTED_VARIANTS_KEY as string)\n\n /**\n * It retrieves the available variants from the result.\n *\n * @returns - The variants of the result for the current level.\n */\n const variants = computed<ResultVariant[] | undefined>(() => {\n if (props.level === 0) {\n return result!.value?.variants\n }\n return selectedVariants!.value[props.level - 1]?.variants\n })\n\n /**\n * Gets the selected variant of the current level.\n *\n * @returns - The selected variant.\n */\n const selectedVariant = computed<ResultVariant | undefined>(() =>\n variants.value?.find(variant => variant === selectedVariants!.value[props.level]),\n )\n\n /**\n * Calls the provided method to select a variant.\n *\n * @param variant - Variant to select.\n */\n const selectVariant = (variant: ResultVariant) => {\n selectResultVariant!(variant, props.level)\n }\n\n /**\n * Checks if a variant is selected.\n *\n * @param variant - Variant to check.\n * @returns True if the variant is selected, false if not.\n */\n const variantIsSelected = (variant: ResultVariant) => {\n return selectedVariant.value === variant\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no result or variants, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no result or variants.\n */\n function renderDefaultSlot() {\n const slotProps = {\n variants: variants.value,\n selectedVariant: selectedVariant.value,\n selectVariant,\n }\n return result && variants.value ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { result, variants, variantIsSelected, selectVariant }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-result-variant-selector__list {\n display: flex;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nHere you have a basic example of how the `ResultVariantSelector` component is rendered.\n\nTake into account that this component **must** be a child of a `ResultVariantsProvider` component.\n\nAlso, the component is intended to be used overwriting the content with the slots.\n\nBy default it will render a list of buttons containing the available variants.\n\nThis component only has a required `level` prop, that indicates the level of the variants to be\nrendered.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <h1>Select color</h1>\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, selectVariant }\" />\n\n <h1>Select size</h1>\n <ResultVariantSelector :level=\"1\" #variant=\"{ variant, selectVariant }\" />\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n variants: [\n {\n name: 'red XL',\n },\n {\n name: 'red L',\n },\n ],\n },\n {\n name: 'blue',\n variants: [\n {\n name: 'blue S',\n },\n {\n name: 'blue M',\n },\n {\n name: 'blue L',\n },\n ],\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nIn this example the default slot is used to customize the list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #default=\"{ variants, selectedVariant, selectVariant }\">\n <div>\n <p v-if=\"selectedVariant\">Selected variant: {{ selectedVariant.name }}</p>\n <ul class=\"x-flex\">\n <li v-for=\"(variant, index) in variants\" :key=\"index\">\n <button @click=\"selectVariant(variant)\">{{ variant.name }}</button>\n </li>\n </ul>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-slot\n\nIn this example the variant-slot is used to customize the variant item.\n\nThe variant will be rendered inside a list.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector :level=\"0\" #variant=\"{ variant, isSelected, selectVariant }\">\n <div>\n <button @click=\"selectVariant\">\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </button>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n\n### Play with variant-content slot\n\nIn this example the variant-content slot is used to customize the content of the default variant\nbutton.\n\n```vue\n<template>\n <ResultVariantsProvider :result=\"result\" #default=\"{ result }\">\n <p>Result name: {{ result.name }}</p>\n\n <ResultVariantSelector #variant-content=\"{ variant, isSelected }\">\n <div>\n {{ variant.name }}\n <span v-if=\"isSelected\">SELECTED!</span>\n </div>\n </ResultVariantSelector>\n </ResultVariantsProvider>\n</template>\n\n<script>\nimport { ResultVariantsProvider, ResultVariantSelector } from '@empathyco/x-components'\n\nexport default {\n name: 'ResultVariantSelectorDemo',\n components: {\n ResultVariantsProvider,\n ResultVariantSelector,\n },\n data() {\n return {\n result: {\n id: 'jacket',\n modelName: 'Result',\n type: 'Product',\n isWishlisted: false,\n identifier: { value: 'jacket' },\n images: [],\n name: 'jacket',\n price: { hasDiscount: false, originalValue: 10, value: 10 },\n url: '/products/jacket',\n variants: [\n {\n name: 'red',\n },\n {\n name: 'blue',\n },\n ],\n },\n }\n },\n}\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;AA8CA;;;;;AAKE;AACF,gBAAe,eAAe,CAAC;AAC7B,IAAA,IAAI,EAAE,uBAAuB;AAC7B,IAAA,KAAK,EAAE;;AAEL,QAAA,KAAK,EAAE;AACL,YAAA,IAAI,EAAE,MAAM;AACZ,YAAA,OAAO,EAAE,CAAC;AACX,SAAA;AACF,KAAA;AACD,IAAA,KAAK,CAAC,KAAK,EAAE,EAAE,KAAI,EAAG,EAAA;AACpB;;;;;AAKE;AACF,QAAA,MAAM,mBAAoB,GAAE,MAAM,CAChC,yBAAmC,CACrC,CAAA;;AAGA,QAAA,MAAM,MAAK,GAAI,MAAM,CAAc,wBAAkC,CAAA,CAAA;;AAGrE,QAAA,MAAM,gBAAe,GAAI,MAAM,CAAuB,qBAA+B,CAAA,CAAA;AAErF;;;;AAIE;AACF,QAAA,MAAM,QAAO,GAAI,QAAQ,CAA8B,MAAM;AAC3D,YAAA,IAAI,KAAK,CAAC,KAAI,KAAM,CAAC,EAAE;AACrB,gBAAA,OAAO,MAAO,CAAC,KAAK,EAAE,QAAO,CAAA;AAC/B,aAAA;AACA,YAAA,OAAO,gBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAO,CAAA;AAC1D,SAAC,CAAA,CAAA;AAED;;;;AAIE;AACF,QAAA,MAAM,eAAgB,GAAE,QAAQ,CAA4B,MAC1D,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,OAAM,IAAK,OAAQ,KAAI,gBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CACnF,CAAA;AAEA;;;;AAIE;AACF,QAAA,MAAM,aAAc,GAAE,CAAC,OAAsB,KAAK;AAChD,YAAA,mBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAA,CAAA;AAC3C,SAAA,CAAA;AAEA;;;;;AAKE;AACF,QAAA,MAAM,iBAAgB,GAAI,CAAC,OAAsB,KAAK;AACpD,YAAA,OAAO,eAAe,CAAC,KAAI,KAAM,OAAM,CAAA;AACzC,SAAA,CAAA;AAEA;;;;;;;;;;AAUE;AACF,QAAA,SAAS,iBAAiB,GAAA;AACxB,YAAA,MAAM,YAAY;gBAChB,QAAQ,EAAE,QAAQ,CAAC,KAAK;gBACxB,eAAe,EAAE,eAAe,CAAC,KAAK;gBACtC,aAAa;aACf,CAAA;YACA,OAAO,MAAK,IAAK,QAAQ,CAAC,KAAI,GAAI,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAE,GAAE,EAAC,CAAA;SACrE;AAEA;AAC+E;QAC/E,MAAM,cAAe,GAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAc,EAAA,CAAA;AAC5E,QAAA,QAAQ,KAAK,CAAC,OAAM,GAAI,iBAAkB,GAAE,cAAc,EAAyB;KACpF;AACF,CAAA,CAAA;;;;"}
|
|
@@ -120,7 +120,6 @@ function useScroll(props, { emit }, scrollEl) {
|
|
|
120
120
|
// eslint-disable-next-line ts/no-floating-promises
|
|
121
121
|
nextTick().then(() => {
|
|
122
122
|
if (!scrollEl.value) {
|
|
123
|
-
// TODO Replace with Empathy's logger
|
|
124
123
|
console.warn('[useScroll]', 'Components using this composable must pass `scrollEl` as the HTML node that is scrolling.');
|
|
125
124
|
}
|
|
126
125
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scroll.js","sources":["../../../../src/components/scroll/use-scroll.ts"],"sourcesContent":["import type { Ref, SetupContext } from 'vue'\nimport type { XEvent } from '../../wiring/events.types'\nimport type { ScrollDirection } from './scroll.types'\nimport { isArray } from '@empathyco/x-utils'\nimport { computed, nextTick, onMounted, ref, watch } from 'vue'\nimport { use$x } from '../../composables/use-$x'\nimport { throttle } from '../../utils/throttle'\n\n/**\n * Composable to share Scroll logic.\n *\n * @param props - Composable props.\n * @param context - Component setup context.\n * @param scrollEl - The scrolling container reference.\n * @returns A throttled version of the function to store the scroll data.\n * @public\n */\nexport function useScroll(\n props: {\n /**\n * Distance to the end of the scroll that when reached will emit the\n * `scroll:about-to-end` event.\n *\n * @public\n */\n distanceToBottom: number\n /**\n * Positive vertical distance to still consider that the element is the first one visible.\n * For example, if set to 100, after scrolling 100 pixels, the first rendered element\n * will still be considered the first one.\n */\n firstElementThresholdPx: number\n /**\n * Time duration to ignore the subsequent scroll events after an emission.\n * Higher values will decrease events precision but can prevent performance issues.\n *\n * @public\n */\n throttleMs: number\n /**\n * If true (default), sets the scroll position to the top when certain events are emitted.\n *\n * @public\n */\n resetOnChange: boolean\n /**\n * List of events that should reset the scroll when emitted.\n *\n * @public\n */\n resetOn: XEvent | XEvent[]\n },\n { emit }: SetupContext<any>,\n scrollEl: Ref<HTMLElement | undefined>,\n) {\n /**\n * Property for getting the client height of scroll.\n *\n * @internal\n */\n const clientHeight = ref(0)\n\n /**\n * Property for getting the current position of scroll.\n *\n * @internal\n */\n const currentPosition = ref(0)\n\n /**\n * Property for getting the previous position of scroll.\n *\n * @internal\n */\n const previousPosition = ref(0)\n\n /**\n * Property for getting the scroll height.\n *\n * @internal\n */\n const scrollHeight = ref(0)\n /**\n * Flag to know if the property clientHeight is changing or gets the final value.\n *\n * @internal\n */\n const isClientHeightChanging = ref(false)\n\n /**\n * Property for setting the direction of scroll.\n *\n * @internal\n */\n const scrollDirection: Ref<ScrollDirection> = ref('UP')\n\n /**\n * Restores the clientHeight flag when clientHeight property stops changing.\n * Also sets a new previous position, before update the current one.\n *\n * @internal\n */\n const restoreClientHeightFlag = (): void => {\n isClientHeightChanging.value = false\n previousPosition.value = currentPosition.value\n }\n\n const throtteledCall = throttle(restoreClientHeightFlag, 100)\n\n /**\n * Updates scroll related properties.\n *\n * @internal\n */\n const storeScrollData = () => {\n if (scrollEl.value) {\n scrollHeight.value = scrollEl.value.scrollHeight\n clientHeight.value = scrollEl.value.clientHeight\n currentPosition.value = scrollEl.value.scrollTop\n }\n }\n\n /**\n * Throttled version of the function that stores the DOM scroll related properties.\n * The duration of the throttle is configured through the `throttleMs` prop passed as parameter.\n *\n * @returns A throttled version of the function to store the scroll data.\n * @internal\n */\n const throttledStoreScrollData = computed(() => throttle(storeScrollData, props.throttleMs))\n\n /**\n * Returns end position of scroll.\n *\n * @returns A number for knowing end position of scroll.\n * @internal\n */\n const scrollEndPosition = computed(() => scrollHeight.value - clientHeight.value)\n\n /**\n * Returns distance missing to endPosition position.\n *\n * @returns A number for knowing the distance missing to endPosition position.\n * @internal\n */\n const distanceToEnd = computed(() => scrollEndPosition.value - currentPosition.value)\n\n /**\n * Returns `true` when there is no more content to scroll.\n *\n * @returns A boolean for knowing if the user scrolls to the end.\n * @internal\n */\n const hasScrollReachedEnd = computed(() => currentPosition.value === scrollEndPosition.value)\n\n /**\n * Returns `true` when the scroll is at the initial position.\n *\n * @returns A boolean for knowing if the user scrolls to the start.\n * @internal\n */\n const hasScrollReachedStart = computed(() => currentPosition.value === 0)\n\n /**\n * Returns `true` when the amount of pixels scrolled is greater than\n * the `distanceToBottom` prop passed as parameter.\n *\n * @returns A boolean for knowing if the user is about to reaching to the end.\n * @internal\n */\n const hasScrollAlmostReachedEnd = computed(\n () => !hasScrollReachedStart.value && props.distanceToBottom > distanceToEnd.value,\n )\n\n onMounted(() => {\n // eslint-disable-next-line ts/no-floating-promises\n nextTick().then(() => {\n if (!scrollEl.value) {\n // TODO Replace with Empathy's logger\n\n console.warn(\n '[useScroll]',\n\n 'Components using this composable must pass `scrollEl` as the HTML node that is scrolling.',\n )\n } else {\n storeScrollData()\n }\n })\n })\n\n /**\n * Change the isClientHeightChanging flag when the property clientHeight is changing and\n * calls throttleledCall method.\n *\n * @internal\n */\n watch(\n clientHeight,\n () => {\n isClientHeightChanging.value = true\n\n throtteledCall()\n },\n { immediate: true },\n )\n\n /**\n * Emits the `scroll` event.\n *\n * @param _newScrollPosition - The new position of scroll.\n * @param oldScrollPosition - The old position of scroll.\n * @internal\n */\n watch(currentPosition, (_newScrollPosition: number, oldScrollPosition: number) => {\n emit('scroll', currentPosition.value)\n previousPosition.value = oldScrollPosition\n })\n\n /**\n * Sets direction of scroll based in {@link ScrollDirection} when the current position\n * has changed.\n *\n * @internal\n */\n watch(currentPosition, () => {\n if (!isClientHeightChanging.value && currentPosition.value !== previousPosition.value) {\n scrollDirection.value = currentPosition.value > previousPosition.value ? 'DOWN' : 'UP'\n }\n })\n\n /**\n * Emits the 'scroll:almost-at-end' event when the user is about to reach to end.\n *\n * @param isScrollAlmostAtEnd - For knowing if the user is about to reach to end.\n * @internal\n */\n watch(hasScrollReachedStart, (isScrollAtStart: boolean) => {\n emit('scroll:at-start', isScrollAtStart)\n })\n\n /**\n * Sets direction of scroll based in {@link ScrollDirection} when the current position\n * has changed.\n *\n * @internal\n */\n watch(hasScrollAlmostReachedEnd, (isScrollAlmostAtEnd: boolean) => {\n emit('scroll:almost-at-end', isScrollAlmostAtEnd)\n })\n\n /**\n * Emits the 'scroll:at-end' event when the user reaches the end.\n *\n * @param isScrollAtEnd - For knowing if the user reaches at end.\n * @internal\n */\n watch(hasScrollReachedEnd, (isScrollAtEnd: boolean) => {\n emit('scroll:at-end', isScrollAtEnd)\n })\n\n /**\n * Emits the `scroll:direction-change` event when the scrolling direction has changed.\n *\n * @param direction - The new direction of scroll.\n * @internal\n */\n watch(scrollDirection, (direction: ScrollDirection) => {\n if (!isClientHeightChanging.value) {\n emit('scroll:direction-change', direction)\n }\n })\n\n /**\n * Resets the scroll position.\n *\n * @internal\n */\n const $x = use$x()\n const resetOnEvents = isArray(props.resetOn) ? props.resetOn : [props.resetOn]\n resetOnEvents.forEach(event =>\n // eslint-disable-next-line ts/no-misused-promises\n $x.on(event, false).subscribe(async () =>\n nextTick().then(() => {\n if (props.resetOnChange) {\n scrollEl.value?.scrollTo({ top: 0 })\n }\n }),\n ),\n )\n\n return { throttledStoreScrollData }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-scroll.js","sources":["../../../../src/components/scroll/use-scroll.ts"],"sourcesContent":["import type { Ref, SetupContext } from 'vue'\nimport type { XEvent } from '../../wiring/events.types'\nimport type { ScrollDirection } from './scroll.types'\nimport { isArray } from '@empathyco/x-utils'\nimport { computed, nextTick, onMounted, ref, watch } from 'vue'\nimport { use$x } from '../../composables/use-$x'\nimport { throttle } from '../../utils/throttle'\n\n/**\n * Composable to share Scroll logic.\n *\n * @param props - Composable props.\n * @param context - Component setup context.\n * @param scrollEl - The scrolling container reference.\n * @returns A throttled version of the function to store the scroll data.\n * @public\n */\nexport function useScroll(\n props: {\n /**\n * Distance to the end of the scroll that when reached will emit the\n * `scroll:about-to-end` event.\n *\n * @public\n */\n distanceToBottom: number\n /**\n * Positive vertical distance to still consider that the element is the first one visible.\n * For example, if set to 100, after scrolling 100 pixels, the first rendered element\n * will still be considered the first one.\n */\n firstElementThresholdPx: number\n /**\n * Time duration to ignore the subsequent scroll events after an emission.\n * Higher values will decrease events precision but can prevent performance issues.\n *\n * @public\n */\n throttleMs: number\n /**\n * If true (default), sets the scroll position to the top when certain events are emitted.\n *\n * @public\n */\n resetOnChange: boolean\n /**\n * List of events that should reset the scroll when emitted.\n *\n * @public\n */\n resetOn: XEvent | XEvent[]\n },\n { emit }: SetupContext<any>,\n scrollEl: Ref<HTMLElement | undefined>,\n) {\n /**\n * Property for getting the client height of scroll.\n *\n * @internal\n */\n const clientHeight = ref(0)\n\n /**\n * Property for getting the current position of scroll.\n *\n * @internal\n */\n const currentPosition = ref(0)\n\n /**\n * Property for getting the previous position of scroll.\n *\n * @internal\n */\n const previousPosition = ref(0)\n\n /**\n * Property for getting the scroll height.\n *\n * @internal\n */\n const scrollHeight = ref(0)\n /**\n * Flag to know if the property clientHeight is changing or gets the final value.\n *\n * @internal\n */\n const isClientHeightChanging = ref(false)\n\n /**\n * Property for setting the direction of scroll.\n *\n * @internal\n */\n const scrollDirection: Ref<ScrollDirection> = ref('UP')\n\n /**\n * Restores the clientHeight flag when clientHeight property stops changing.\n * Also sets a new previous position, before update the current one.\n *\n * @internal\n */\n const restoreClientHeightFlag = (): void => {\n isClientHeightChanging.value = false\n previousPosition.value = currentPosition.value\n }\n\n const throtteledCall = throttle(restoreClientHeightFlag, 100)\n\n /**\n * Updates scroll related properties.\n *\n * @internal\n */\n const storeScrollData = () => {\n if (scrollEl.value) {\n scrollHeight.value = scrollEl.value.scrollHeight\n clientHeight.value = scrollEl.value.clientHeight\n currentPosition.value = scrollEl.value.scrollTop\n }\n }\n\n /**\n * Throttled version of the function that stores the DOM scroll related properties.\n * The duration of the throttle is configured through the `throttleMs` prop passed as parameter.\n *\n * @returns A throttled version of the function to store the scroll data.\n * @internal\n */\n const throttledStoreScrollData = computed(() => throttle(storeScrollData, props.throttleMs))\n\n /**\n * Returns end position of scroll.\n *\n * @returns A number for knowing end position of scroll.\n * @internal\n */\n const scrollEndPosition = computed(() => scrollHeight.value - clientHeight.value)\n\n /**\n * Returns distance missing to endPosition position.\n *\n * @returns A number for knowing the distance missing to endPosition position.\n * @internal\n */\n const distanceToEnd = computed(() => scrollEndPosition.value - currentPosition.value)\n\n /**\n * Returns `true` when there is no more content to scroll.\n *\n * @returns A boolean for knowing if the user scrolls to the end.\n * @internal\n */\n const hasScrollReachedEnd = computed(() => currentPosition.value === scrollEndPosition.value)\n\n /**\n * Returns `true` when the scroll is at the initial position.\n *\n * @returns A boolean for knowing if the user scrolls to the start.\n * @internal\n */\n const hasScrollReachedStart = computed(() => currentPosition.value === 0)\n\n /**\n * Returns `true` when the amount of pixels scrolled is greater than\n * the `distanceToBottom` prop passed as parameter.\n *\n * @returns A boolean for knowing if the user is about to reaching to the end.\n * @internal\n */\n const hasScrollAlmostReachedEnd = computed(\n () => !hasScrollReachedStart.value && props.distanceToBottom > distanceToEnd.value,\n )\n\n onMounted(() => {\n // eslint-disable-next-line ts/no-floating-promises\n nextTick().then(() => {\n if (!scrollEl.value) {\n console.warn(\n '[useScroll]',\n 'Components using this composable must pass `scrollEl` as the HTML node that is scrolling.',\n )\n } else {\n storeScrollData()\n }\n })\n })\n\n /**\n * Change the isClientHeightChanging flag when the property clientHeight is changing and\n * calls throttleledCall method.\n *\n * @internal\n */\n watch(\n clientHeight,\n () => {\n isClientHeightChanging.value = true\n\n throtteledCall()\n },\n { immediate: true },\n )\n\n /**\n * Emits the `scroll` event.\n *\n * @param _newScrollPosition - The new position of scroll.\n * @param oldScrollPosition - The old position of scroll.\n * @internal\n */\n watch(currentPosition, (_newScrollPosition: number, oldScrollPosition: number) => {\n emit('scroll', currentPosition.value)\n previousPosition.value = oldScrollPosition\n })\n\n /**\n * Sets direction of scroll based in {@link ScrollDirection} when the current position\n * has changed.\n *\n * @internal\n */\n watch(currentPosition, () => {\n if (!isClientHeightChanging.value && currentPosition.value !== previousPosition.value) {\n scrollDirection.value = currentPosition.value > previousPosition.value ? 'DOWN' : 'UP'\n }\n })\n\n /**\n * Emits the 'scroll:almost-at-end' event when the user is about to reach to end.\n *\n * @param isScrollAlmostAtEnd - For knowing if the user is about to reach to end.\n * @internal\n */\n watch(hasScrollReachedStart, (isScrollAtStart: boolean) => {\n emit('scroll:at-start', isScrollAtStart)\n })\n\n /**\n * Sets direction of scroll based in {@link ScrollDirection} when the current position\n * has changed.\n *\n * @internal\n */\n watch(hasScrollAlmostReachedEnd, (isScrollAlmostAtEnd: boolean) => {\n emit('scroll:almost-at-end', isScrollAlmostAtEnd)\n })\n\n /**\n * Emits the 'scroll:at-end' event when the user reaches the end.\n *\n * @param isScrollAtEnd - For knowing if the user reaches at end.\n * @internal\n */\n watch(hasScrollReachedEnd, (isScrollAtEnd: boolean) => {\n emit('scroll:at-end', isScrollAtEnd)\n })\n\n /**\n * Emits the `scroll:direction-change` event when the scrolling direction has changed.\n *\n * @param direction - The new direction of scroll.\n * @internal\n */\n watch(scrollDirection, (direction: ScrollDirection) => {\n if (!isClientHeightChanging.value) {\n emit('scroll:direction-change', direction)\n }\n })\n\n /**\n * Resets the scroll position.\n *\n * @internal\n */\n const $x = use$x()\n const resetOnEvents = isArray(props.resetOn) ? props.resetOn : [props.resetOn]\n resetOnEvents.forEach(event =>\n // eslint-disable-next-line ts/no-misused-promises\n $x.on(event, false).subscribe(async () =>\n nextTick().then(() => {\n if (props.resetOnChange) {\n scrollEl.value?.scrollTo({ top: 0 })\n }\n }),\n ),\n )\n\n return { throttledStoreScrollData }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -9,9 +9,7 @@ import { cancellablePromise, CancelSymbol } from '../../utils/cancellable-promis
|
|
|
9
9
|
* @public
|
|
10
10
|
* @returns An action to fetch and save some data, and an action to cancel the last request.
|
|
11
11
|
*/
|
|
12
|
-
function createFetchAndSaveActions({ fetch, onSuccess,
|
|
13
|
-
// TODO add logger
|
|
14
|
-
onError = console.error, onCancel, }) {
|
|
12
|
+
function createFetchAndSaveActions({ fetch, onSuccess, onError = console.error, onCancel, }) {
|
|
15
13
|
let cancelPreviousRequest;
|
|
16
14
|
/**
|
|
17
15
|
* Called asynchronously after a response has been received.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-and-save-action.utils.js","sources":["../../../../src/store/utils/fetch-and-save-action.utils.ts"],"sourcesContent":["import type { XActionContext } from '../actions.types'\nimport type { StatusMutations, StatusState } from './status-store.utils'\nimport { cancellablePromise, CancelSymbol } from '../../utils/cancellable-promise'\n\n/**\n * Utility to create an action that requests and save some data asynchronously, with the\n * option to cancel the request at any moment. This factory provides with the standard flow\n * for requesting, cancelling, handling errors for a module, while also taking care of its status.\n *\n * @param hooks - The {@link FetchAndSaveHooks} hooks to create the action.\n * @public\n * @returns An action to fetch and save some data, and an action to cancel the last request.\n */\nexport function createFetchAndSaveActions<\n // Using `object` type to ensure no actions/getters can be used.\n Context extends XActionContext<StatusState, object, StatusMutations, object>,\n Request,\n Response,\n>({\n fetch,\n onSuccess,\n
|
|
1
|
+
{"version":3,"file":"fetch-and-save-action.utils.js","sources":["../../../../src/store/utils/fetch-and-save-action.utils.ts"],"sourcesContent":["import type { XActionContext } from '../actions.types'\nimport type { StatusMutations, StatusState } from './status-store.utils'\nimport { cancellablePromise, CancelSymbol } from '../../utils/cancellable-promise'\n\n/**\n * Utility to create an action that requests and save some data asynchronously, with the\n * option to cancel the request at any moment. This factory provides with the standard flow\n * for requesting, cancelling, handling errors for a module, while also taking care of its status.\n *\n * @param hooks - The {@link FetchAndSaveHooks} hooks to create the action.\n * @public\n * @returns An action to fetch and save some data, and an action to cancel the last request.\n */\nexport function createFetchAndSaveActions<\n // Using `object` type to ensure no actions/getters can be used.\n Context extends XActionContext<StatusState, object, StatusMutations, object>,\n Request,\n Response,\n>({\n fetch,\n onSuccess,\n onError = console.error,\n onCancel,\n}: FetchAndSaveHooks<Context, Request, Response>): FetchAndSaveActions<Context, Request> {\n let cancelPreviousRequest: undefined | (() => void)\n\n /**\n * Called asynchronously after a response has been received.\n *\n * @param context - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the\n * actions, provided by Vuex.\n * @param response - The fetch response.\n * @returns A Promise that resolves after handling the response.\n */\n async function handleResponse(context: Context, response: Response): Promise<void> {\n return Promise.resolve(onSuccess(context, response)).then(() => {\n context.commit('setStatus', 'success')\n })\n }\n\n /**\n * Called immediately after a request has been cancelled.\n *\n * @param context - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the\n * actions, provided by Vuex.\n */\n function handleCancel(context: Context): void {\n cancelPreviousRequest = undefined\n context.commit('setStatus', 'success')\n onCancel?.()\n }\n\n /**\n * Called asynchronously whenever an error happens in the fetch and save flow.\n *\n * @param context - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the\n * actions, provided by Vuex.\n * @param error - The error information.\n */\n function handleError(context: Context, error: unknown): void {\n if (error !== CancelSymbol) {\n context.commit('setStatus', 'error')\n onError(error)\n }\n }\n\n /** @see FetchAndSaveActions.fetchAndSave */\n async function fetchAndSave(context: Context, request: Request): Promise<void> {\n cancelPrevious()\n context.commit('setStatus', 'loading')\n const { promise, cancel } = cancellablePromise(fetch(context, request), () => {\n handleCancel(context)\n })\n\n cancelPreviousRequest = cancel\n return promise\n .then(async response => handleResponse(context, response))\n .catch(error => handleError(context, error))\n }\n\n /** @see FetchAndSaveActions.cancelPrevious */\n function cancelPrevious(): void {\n cancelPreviousRequest?.()\n }\n\n return {\n fetchAndSave,\n cancelPrevious,\n }\n}\n\n/**\n * Options to use with the {@link createFetchAndSaveActions} factory.\n *\n * @public\n */\nexport interface FetchAndSaveHooks<\n // Using `object` type to ensure no actions/getters can be used.\n Context extends XActionContext<StatusState, object, StatusMutations, object>,\n Request,\n Response,\n> {\n /**\n * Retrieves and returns asynchronously some data.\n *\n * @param context - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the\n * actions, provided by Vuex.\n * @param request - The request object used for fetching.\n * @returns A Promise resolved with the response of the fetch request.\n */\n fetch: (context: Context, request: Request) => Promise<Response>\n /**\n * Asynchronous callback executed when the {@link FetchAndSaveHooks.fetch} is\n * performed successfully.\n *\n * @param context - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the\n * actions, provided by Vuex.\n * @param response - The data returned by {@link FetchAndSaveHooks.fetch}.\n */\n onSuccess: (context: Context, response: Response) => void\n /**\n * Asynchronous callback executed when either the {@link FetchAndSaveHooks.fetch}\n * or {@link FetchAndSaveHooks.onSuccess} methods fail.\n *\n * @param error - The error that triggered this callback.\n */\n onError?: (error: unknown) => void\n /**\n * Synchronous callback executed when the request is cancelled. This can happen mainly for two\n * reasons:\n * - The {@link FetchAndSaveActions.cancelPrevious} action is dispatched.\n * - A new {@link FetchAndSaveActions.fetchAndSave} is dispatched before the previous one was\n * resolved.\n */\n onCancel?: () => void\n}\n\n/**\n * Actions returned from the {@link createFetchAndSaveActions}.\n *\n * @public\n */\nexport interface FetchAndSaveActions<\n // Using `object` type to ensure no actions/getters can be used.\n Context extends XActionContext<StatusState, object, StatusMutations, object>,\n Request,\n> {\n /**\n * Action that requests and saves the response.\n *\n * @param context - The {@link https://vuex.vuejs.org/guide/actions.html | context} of the\n * actions, provided by Vuex.\n * @returns A promise that resolves after saving the response.\n */\n fetchAndSave: (context: Context, request: Request) => void | Promise<void>\n /**\n * Action that cancels the previous request call if it stills in progress.\n */\n cancelPrevious: () => void\n}\n"],"names":[],"mappings":";;AAIA;;;;;;;;AAQG;AACa,SAAA,yBAAyB,CAKvC,EACA,KAAK,EACL,SAAS,EACT,OAAO,GAAG,OAAO,CAAC,KAAK,EACvB,QAAQ,GACsC,EAAA;AAC9C,IAAA,IAAI,qBAA+C,CAAA;AAEnD;;;;;;;AAOG;AACH,IAAA,eAAe,cAAc,CAAC,OAAgB,EAAE,QAAkB,EAAA;AAChE,QAAA,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAK;AAC7D,YAAA,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;AACxC,SAAC,CAAC,CAAA;KACH;AAED;;;;;AAKG;IACH,SAAS,YAAY,CAAC,OAAgB,EAAA;QACpC,qBAAqB,GAAG,SAAS,CAAA;AACjC,QAAA,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACtC,QAAQ,IAAI,CAAA;KACb;AAED;;;;;;AAMG;AACH,IAAA,SAAS,WAAW,CAAC,OAAgB,EAAE,KAAc,EAAA;QACnD,IAAI,KAAK,KAAK,YAAY,EAAE;AAC1B,YAAA,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;YACpC,OAAO,CAAC,KAAK,CAAC,CAAA;AACf,SAAA;KACF;;AAGD,IAAA,eAAe,YAAY,CAAC,OAAgB,EAAE,OAAgB,EAAA;AAC5D,QAAA,cAAc,EAAE,CAAA;AAChB,QAAA,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;AACtC,QAAA,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,MAAK;YAC3E,YAAY,CAAC,OAAO,CAAC,CAAA;AACvB,SAAC,CAAC,CAAA;QAEF,qBAAqB,GAAG,MAAM,CAAA;AAC9B,QAAA,OAAO,OAAO;AACX,aAAA,IAAI,CAAC,OAAM,QAAQ,KAAI,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACzD,aAAA,KAAK,CAAC,KAAK,IAAI,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAA;KAC/C;;AAGD,IAAA,SAAS,cAAc,GAAA;QACrB,qBAAqB,IAAI,CAAA;KAC1B;IAED,OAAO;QACL,YAAY;QACZ,cAAc;KACf,CAAA;AACH;;;;"}
|
|
@@ -26,7 +26,6 @@ function useFiltersInjection(props) {
|
|
|
26
26
|
const propOrInjectedFilters = computed(() => {
|
|
27
27
|
return (props.filters ??
|
|
28
28
|
injectedFilters?.value ??
|
|
29
|
-
//TODO: add here logger
|
|
30
29
|
console.warn('It is necessary to pass a prop or inject the list of filters'));
|
|
31
30
|
});
|
|
32
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-filters-injection.js","sources":["../../../../../src/x-modules/facets/composables/use-filters-injection.ts"],"sourcesContent":["import type { Filter, HierarchicalFilter } from '@empathyco/x-types'\nimport type { Ref } from 'vue'\nimport { isHierarchicalFilter } from '@empathyco/x-types'\nimport { computed, inject } from 'vue'\nimport { isArrayEmpty } from '../../../utils/array'\n\n/**\n * Composable to share filters injection logic.\n *\n * @param props - Composable props.\n * @returns An array of filters.\n * @public\n */\nexport function useFiltersInjection(props: {\n /** The list of filters to be rendered as slots. */\n filters?: Filter[]\n /**\n This prop is used in the `HierarchicalFilter` component and only in that case. It is necessary\n to make the `renderedFilters` to return only the filters of each level of the hierarchy.\n */\n parentId?: Filter['id']\n}) {\n /**\n * The injected filters array.\n *\n * @public\n */\n const injectedFilters = inject<Ref<Filter[]> | undefined>('filters', undefined)\n\n /**\n * An array of filters formed by those that are passed through prop or injected.\n *\n * @returns An array of filters.\n *\n * @internal\n */\n const propOrInjectedFilters = computed((): void | Filter[] => {\n return (\n props.filters ??\n injectedFilters?.value ??\n
|
|
1
|
+
{"version":3,"file":"use-filters-injection.js","sources":["../../../../../src/x-modules/facets/composables/use-filters-injection.ts"],"sourcesContent":["import type { Filter, HierarchicalFilter } from '@empathyco/x-types'\nimport type { Ref } from 'vue'\nimport { isHierarchicalFilter } from '@empathyco/x-types'\nimport { computed, inject } from 'vue'\nimport { isArrayEmpty } from '../../../utils/array'\n\n/**\n * Composable to share filters injection logic.\n *\n * @param props - Composable props.\n * @returns An array of filters.\n * @public\n */\nexport function useFiltersInjection(props: {\n /** The list of filters to be rendered as slots. */\n filters?: Filter[]\n /**\n This prop is used in the `HierarchicalFilter` component and only in that case. It is necessary\n to make the `renderedFilters` to return only the filters of each level of the hierarchy.\n */\n parentId?: Filter['id']\n}) {\n /**\n * The injected filters array.\n *\n * @public\n */\n const injectedFilters = inject<Ref<Filter[]> | undefined>('filters', undefined)\n\n /**\n * An array of filters formed by those that are passed through prop or injected.\n *\n * @returns An array of filters.\n *\n * @internal\n */\n const propOrInjectedFilters = computed((): void | Filter[] => {\n return (\n props.filters ??\n injectedFilters?.value ??\n console.warn('It is necessary to pass a prop or inject the list of filters')\n )\n })\n\n /**\n * In the case that the filters are {@link @empathyco/x-types#HierarchicalFilter}, this method\n * removes from the filter list passed as a param, the filters that are not part of the level of\n * the hierarchy, depending on the value of the `parentId` prop. In case this prop is undefined,\n * then only the first level of filters hierarchy are returned. In the case the prop `parentId` is\n * defined, then only the filters with the same `parentId` are returned.\n *\n * @param filters - The list of the filters to apply the filter.\n * @returns The list of the filters filtered by parentId.\n * @internal\n */\n const filterByParentId = (filters: Filter[]): Filter[] => {\n if (!isArrayEmpty(filters) && isHierarchicalFilter(filters[0])) {\n return (filters as HierarchicalFilter[]).filter(\n filter => filter.parentId === (props.parentId ?? null),\n )\n } else {\n return filters\n }\n }\n\n /**\n * The prop or injected filters array, filtered by parentId if they are\n * {@link @empathyco/x-types#HierarchicalFilter}.\n *\n * @returns An array of filters.\n *\n * @internal\n */\n return computed<Filter[]>(() => filterByParentId(propOrInjectedFilters.value as Filter[]))\n}\n"],"names":[],"mappings":";;;;AAMA;;;;;;AAMG;AACG,SAAU,mBAAmB,CAAC,KAQnC,EAAA;AACC;;;;AAIG;IACH,MAAM,eAAe,GAAG,MAAM,CAA4B,SAAS,EAAE,SAAS,CAAC,CAAA;AAE/E;;;;;;AAMG;AACH,IAAA,MAAM,qBAAqB,GAAG,QAAQ,CAAC,MAAsB;QAC3D,QACE,KAAK,CAAC,OAAO;AACb,YAAA,eAAe,EAAE,KAAK;AACtB,YAAA,OAAO,CAAC,IAAI,CAAC,8DAA8D,CAAC,EAC7E;AACH,KAAC,CAAC,CAAA;AAEF;;;;;;;;;;AAUG;AACH,IAAA,MAAM,gBAAgB,GAAG,CAAC,OAAiB,KAAc;AACvD,QAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9D,OAAQ,OAAgC,CAAC,MAAM,CAC7C,MAAM,IAAI,MAAM,CAAC,QAAQ,MAAM,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CACvD,CAAA;AACF,SAAA;AAAM,aAAA;AACL,YAAA,OAAO,OAAO,CAAA;AACf,SAAA;AACH,KAAC,CAAA;AAED;;;;;;;AAOG;AACH,IAAA,OAAO,QAAQ,CAAW,MAAM,gBAAgB,CAAC,qBAAqB,CAAC,KAAiB,CAAC,CAAC,CAAA;AAC5F;;;;"}
|
|
@@ -134,7 +134,6 @@ class DefaultExternalTaggingService {
|
|
|
134
134
|
*/
|
|
135
135
|
showWarningMessage() {
|
|
136
136
|
if (this.storageKey !== 'url') {
|
|
137
|
-
//TODO: add here logger
|
|
138
137
|
console.warn('No product id was provided but the storage was not configured to use the url');
|
|
139
138
|
}
|
|
140
139
|
}
|
|
@@ -162,7 +161,6 @@ class DefaultExternalTaggingService {
|
|
|
162
161
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
163
162
|
}
|
|
164
163
|
catch (_error) {
|
|
165
|
-
//TODO: add here logger
|
|
166
164
|
console.warn(`There was a problem with url ${url}`);
|
|
167
165
|
return url;
|
|
168
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-tagging.service.js","sources":["../../../../../src/x-modules/tagging/service/external-tagging.service.ts"],"sourcesContent":["import type { StorageService } from '@empathyco/x-storage-service'\nimport type { Result } from '@empathyco/x-types'\nimport type { Store } from 'vuex'\nimport type { RootXStoreState } from '../../../store/index'\nimport type { ExternalTaggingService } from './types'\nimport { BrowserStorageService } from '@empathyco/x-storage-service'\nimport { XPlugin } from '../../../plugins/index'\n\n/**\n * Default implementation for the {@link ExternalTaggingService}.\n *\n * @public\n */\nexport class DefaultExternalTaggingService implements ExternalTaggingService {\n /**\n * Session id key to use as key in the storage for result clicks.\n *\n * @public\n */\n public static readonly RESULT_CLICKED_ID_KEY = 'add-to-cart'\n\n /**\n * Session id key to use as key in the storage for add to carts.\n *\n * @public\n */\n public static readonly ADD_TO_CART_ID_KEY = 'checkout'\n\n /**\n * Global instance of the {@link ExternalTaggingService}.\n */\n public static instance: ExternalTaggingService = new DefaultExternalTaggingService()\n\n public constructor(\n protected localStorageService: StorageService = new BrowserStorageService(localStorage, 'x'),\n protected sessionStorageService: StorageService = new BrowserStorageService(\n sessionStorage,\n 'x',\n ),\n ) {}\n\n protected get store(): Store<RootXStoreState> {\n return XPlugin.store\n }\n\n protected get storageKey(): string {\n return this.store.state.x.tagging.config.storageKey as string\n }\n\n protected get storageTTLMs(): number {\n return this.store.state.x.tagging.config.storageTTLMs as number\n }\n\n /**\n * Stores in the local storage the information from the Result clicked by the user\n * in order to be able to track the add to cart later on the result's PDP.\n *\n * @param result - The result to store.\n *\n * @public\n */\n storeResultClicked(result: Result): void {\n const key = result[this.storageKey as keyof Result] as string\n const storageId = this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY, key)\n if (storageId) {\n this.localStorageService.setItem(storageId, result, this.storageTTLMs)\n }\n }\n\n /**\n * Stores in the local storage the information from the Result added to the cart\n * by the user in order to be able to track the checkout later on when the checkout\n * process has been completed by shopper.\n *\n * @param result - The result to store.\n *\n * @public\n */\n storeAddToCart(result: Result): void {\n const key = result[this.storageKey as keyof Result] as string\n const storageId = this.getStorageId(DefaultExternalTaggingService.ADD_TO_CART_ID_KEY, key)\n if (storageId) {\n this.localStorageService.setItem(storageId, result, this.storageTTLMs)\n }\n }\n\n /**\n * Checks if the local storage contains a result information for the given id and moves\n * the result info from the local storage to the session storage.\n *\n * @param id - The id of the result to move to the session storage.\n *\n * @public\n */\n moveToSessionStorage(id?: string): void {\n const storageId = this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY, id)\n if (storageId) {\n // eslint-disable-next-line ts/no-unsafe-assignment\n const result = this.localStorageService.removeItem(storageId)\n if (result) {\n this.sessionStorageService.setItem(storageId, result)\n }\n }\n }\n\n /**\n * Checks if the session storage contains a result information for a given id or the current url.\n * If exists, it tracks the add to cart and saves the add to cart information into session\n * storage.\n *\n * @param id - The id of the result to track.\n *\n * @public\n */\n trackAddToCart(id?: string): void {\n const storageId =\n this.storageKey === 'url'\n ? this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY)\n : this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY, id)\n if (storageId) {\n const result = this.sessionStorageService.getItem<Result>(storageId)\n if (result?.tagging?.add2cart) {\n result.tagging.add2cart.params.location = 'pdp'\n void this.store.dispatch('x/tagging/track', result.tagging.add2cart)\n /**\n * Done after tracking the add to cart to avoid tracking the checkout without\n * an add to cart, in case the tracking fails.\n */\n this.storeAddToCart(result)\n }\n }\n }\n\n /**\n * Calculates the browser storage key for the given id.\n *\n * @param keyPrefix - The key prefix to use in the storage.\n * @param id - The id to be used for the storage key.\n *\n * @returns The complete key to be used for storage.\n *\n * @internal\n */\n protected getStorageId(keyPrefix: string, id?: string): string | null {\n if (this.storageKey === 'url') {\n let url = id ?? window.location.href\n url = url.replace(/\\s|\\+/g, '%20')\n const pathName = this.getPathName(url)\n return `${keyPrefix}-${pathName}`\n } else if (id) {\n return `${keyPrefix}-${id}`\n } else {\n this.showWarningMessage()\n return null\n }\n }\n\n /**\n * Logs a warning message in case the tracking cannot be done.\n *\n * @internal\n */\n protected showWarningMessage(): void {\n if (this.storageKey !== 'url') {\n //TODO: add here logger\n\n console.warn('No product id was provided but the storage was not configured to use the url')\n }\n }\n\n /**\n * Returns the pathname for a given url.\n *\n * @param url - The url to get the pathname from.\n *\n * @returns The pathname of the url.\n *\n * @internal\n */\n protected getPathName(url: string): string {\n let urlObject: URL\n try {\n // Check if the url is relative or absolute path\n // eslint-disable-next-line regexp/no-unused-capturing-group\n if (/^(\\.\\.\\/|\\.\\/|\\/)/.test(url)) {\n urlObject = new URL(url, location.origin)\n } else {\n urlObject = new URL(url)\n }\n return urlObject.pathname\n // eslint-disable-next-line unused-imports/no-unused-vars\n } catch (_error) {\n //TODO: add here logger\n\n console.warn(`There was a problem with url ${url}`)\n return url\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"external-tagging.service.js","sources":["../../../../../src/x-modules/tagging/service/external-tagging.service.ts"],"sourcesContent":["import type { StorageService } from '@empathyco/x-storage-service'\nimport type { Result } from '@empathyco/x-types'\nimport type { Store } from 'vuex'\nimport type { RootXStoreState } from '../../../store/index'\nimport type { ExternalTaggingService } from './types'\nimport { BrowserStorageService } from '@empathyco/x-storage-service'\nimport { XPlugin } from '../../../plugins/index'\n\n/**\n * Default implementation for the {@link ExternalTaggingService}.\n *\n * @public\n */\nexport class DefaultExternalTaggingService implements ExternalTaggingService {\n /**\n * Session id key to use as key in the storage for result clicks.\n *\n * @public\n */\n public static readonly RESULT_CLICKED_ID_KEY = 'add-to-cart'\n\n /**\n * Session id key to use as key in the storage for add to carts.\n *\n * @public\n */\n public static readonly ADD_TO_CART_ID_KEY = 'checkout'\n\n /**\n * Global instance of the {@link ExternalTaggingService}.\n */\n public static instance: ExternalTaggingService = new DefaultExternalTaggingService()\n\n public constructor(\n protected localStorageService: StorageService = new BrowserStorageService(localStorage, 'x'),\n protected sessionStorageService: StorageService = new BrowserStorageService(\n sessionStorage,\n 'x',\n ),\n ) {}\n\n protected get store(): Store<RootXStoreState> {\n return XPlugin.store\n }\n\n protected get storageKey(): string {\n return this.store.state.x.tagging.config.storageKey as string\n }\n\n protected get storageTTLMs(): number {\n return this.store.state.x.tagging.config.storageTTLMs as number\n }\n\n /**\n * Stores in the local storage the information from the Result clicked by the user\n * in order to be able to track the add to cart later on the result's PDP.\n *\n * @param result - The result to store.\n *\n * @public\n */\n storeResultClicked(result: Result): void {\n const key = result[this.storageKey as keyof Result] as string\n const storageId = this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY, key)\n if (storageId) {\n this.localStorageService.setItem(storageId, result, this.storageTTLMs)\n }\n }\n\n /**\n * Stores in the local storage the information from the Result added to the cart\n * by the user in order to be able to track the checkout later on when the checkout\n * process has been completed by shopper.\n *\n * @param result - The result to store.\n *\n * @public\n */\n storeAddToCart(result: Result): void {\n const key = result[this.storageKey as keyof Result] as string\n const storageId = this.getStorageId(DefaultExternalTaggingService.ADD_TO_CART_ID_KEY, key)\n if (storageId) {\n this.localStorageService.setItem(storageId, result, this.storageTTLMs)\n }\n }\n\n /**\n * Checks if the local storage contains a result information for the given id and moves\n * the result info from the local storage to the session storage.\n *\n * @param id - The id of the result to move to the session storage.\n *\n * @public\n */\n moveToSessionStorage(id?: string): void {\n const storageId = this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY, id)\n if (storageId) {\n // eslint-disable-next-line ts/no-unsafe-assignment\n const result = this.localStorageService.removeItem(storageId)\n if (result) {\n this.sessionStorageService.setItem(storageId, result)\n }\n }\n }\n\n /**\n * Checks if the session storage contains a result information for a given id or the current url.\n * If exists, it tracks the add to cart and saves the add to cart information into session\n * storage.\n *\n * @param id - The id of the result to track.\n *\n * @public\n */\n trackAddToCart(id?: string): void {\n const storageId =\n this.storageKey === 'url'\n ? this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY)\n : this.getStorageId(DefaultExternalTaggingService.RESULT_CLICKED_ID_KEY, id)\n if (storageId) {\n const result = this.sessionStorageService.getItem<Result>(storageId)\n if (result?.tagging?.add2cart) {\n result.tagging.add2cart.params.location = 'pdp'\n void this.store.dispatch('x/tagging/track', result.tagging.add2cart)\n /**\n * Done after tracking the add to cart to avoid tracking the checkout without\n * an add to cart, in case the tracking fails.\n */\n this.storeAddToCart(result)\n }\n }\n }\n\n /**\n * Calculates the browser storage key for the given id.\n *\n * @param keyPrefix - The key prefix to use in the storage.\n * @param id - The id to be used for the storage key.\n *\n * @returns The complete key to be used for storage.\n *\n * @internal\n */\n protected getStorageId(keyPrefix: string, id?: string): string | null {\n if (this.storageKey === 'url') {\n let url = id ?? window.location.href\n url = url.replace(/\\s|\\+/g, '%20')\n const pathName = this.getPathName(url)\n return `${keyPrefix}-${pathName}`\n } else if (id) {\n return `${keyPrefix}-${id}`\n } else {\n this.showWarningMessage()\n return null\n }\n }\n\n /**\n * Logs a warning message in case the tracking cannot be done.\n *\n * @internal\n */\n protected showWarningMessage(): void {\n if (this.storageKey !== 'url') {\n console.warn('No product id was provided but the storage was not configured to use the url')\n }\n }\n\n /**\n * Returns the pathname for a given url.\n *\n * @param url - The url to get the pathname from.\n *\n * @returns The pathname of the url.\n *\n * @internal\n */\n protected getPathName(url: string): string {\n let urlObject: URL\n try {\n // Check if the url is relative or absolute path\n // eslint-disable-next-line regexp/no-unused-capturing-group\n if (/^(\\.\\.\\/|\\.\\/|\\/)/.test(url)) {\n urlObject = new URL(url, location.origin)\n } else {\n urlObject = new URL(url)\n }\n return urlObject.pathname\n // eslint-disable-next-line unused-imports/no-unused-vars\n } catch (_error) {\n console.warn(`There was a problem with url ${url}`)\n return url\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
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.96",
|
|
4
4
|
"description": "Empathy X Components",
|
|
5
5
|
"author": "Empathy Systems Corporation S.L.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -77,14 +77,13 @@
|
|
|
77
77
|
"vuex": "4.0.2"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@empathyco/x-adapter": "^8.1.0-alpha.
|
|
81
|
-
"@empathyco/x-adapter-platform": "^1.1.0-alpha.
|
|
82
|
-
"@empathyco/x-bus": "^1.0.3-alpha.
|
|
83
|
-
"@empathyco/x-deep-merge": "^2.0.3-alpha.
|
|
84
|
-
"@empathyco/x-
|
|
85
|
-
"@empathyco/x-
|
|
86
|
-
"@empathyco/x-
|
|
87
|
-
"@empathyco/x-utils": "^1.0.3-alpha.3",
|
|
80
|
+
"@empathyco/x-adapter": "^8.1.0-alpha.4",
|
|
81
|
+
"@empathyco/x-adapter-platform": "^1.1.0-alpha.19",
|
|
82
|
+
"@empathyco/x-bus": "^1.0.3-alpha.4",
|
|
83
|
+
"@empathyco/x-deep-merge": "^2.0.3-alpha.5",
|
|
84
|
+
"@empathyco/x-storage-service": "^2.0.3-alpha.3",
|
|
85
|
+
"@empathyco/x-types": "^10.1.0-alpha.14",
|
|
86
|
+
"@empathyco/x-utils": "^1.0.3-alpha.4",
|
|
88
87
|
"@vue/devtools-api": "~6.5.0",
|
|
89
88
|
"@vueuse/core": "~10.7.1",
|
|
90
89
|
"js-md5": "~0.8.3",
|
|
@@ -97,7 +96,7 @@
|
|
|
97
96
|
"@badeball/cypress-cucumber-preprocessor": "22.0.1",
|
|
98
97
|
"@bahmutov/cypress-esbuild-preprocessor": "2.2.0",
|
|
99
98
|
"@cucumber/messages": "27.2.0",
|
|
100
|
-
"@empathyco/x-tailwindcss": "2.0.0-alpha.
|
|
99
|
+
"@empathyco/x-tailwindcss": "^2.0.0-alpha.10",
|
|
101
100
|
"@microsoft/api-documenter": "7.23.0",
|
|
102
101
|
"@microsoft/api-extractor": "7.39.0",
|
|
103
102
|
"@testing-library/jest-dom": "5.17.0",
|
|
@@ -143,5 +142,5 @@
|
|
|
143
142
|
"access": "public",
|
|
144
143
|
"directory": "dist"
|
|
145
144
|
},
|
|
146
|
-
"gitHead": "
|
|
145
|
+
"gitHead": "ced24d1c1dfd020618a6346c586c5b9c114a6c70"
|
|
147
146
|
}
|
|
@@ -56202,7 +56202,7 @@
|
|
|
56202
56202
|
{
|
|
56203
56203
|
"kind": "Variable",
|
|
56204
56204
|
"canonicalReference": "@empathyco/x-components!ResultVariantSelector:var",
|
|
56205
|
-
"docComment": "/**\n * Component to show and select the available variants of a product for a given nest level. TODO:
|
|
56205
|
+
"docComment": "/**\n * Component to show and select the available variants of a product for a given nest level. TODO: Log warning on mount when result is not injected.\n *\n * @public\n */\n",
|
|
56206
56206
|
"excerptTokens": [
|
|
56207
56207
|
{
|
|
56208
56208
|
"kind": "Content",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-grid.vue?vue&type=script&lang.d.ts","sourceRoot":"","sources":["../../../src/components/base-grid.vue?vue&type=script&lang.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAQ7D;;;GAGG;AACH,UAAU,QAAQ;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED;;;;;;;;;GASG;;IAIC,sEAAsE;;;;;IAKtE;;;OAGG;;;;;IAKH;;;;OAIG;;;;;;;;;aAQI,WAAW;;;;;;IAzBlB,sEAAsE;;;;;IAKtE;;;OAGG;;;;;IAKH;;;;OAIG;;;;;;;;AApBP,
|
|
1
|
+
{"version":3,"file":"base-grid.vue?vue&type=script&lang.d.ts","sourceRoot":"","sources":["../../../src/components/base-grid.vue?vue&type=script&lang.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAQ7D;;;GAGG;AACH,UAAU,QAAQ;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED;;;;;;;;;GASG;;IAIC,sEAAsE;;;;;IAKtE;;;OAGG;;;;;IAKH;;;;OAIG;;;;;;;;;aAQI,WAAW;;;;;;IAzBlB,sEAAsE;;;;;IAKtE;;;OAGG;;;;;IAKH;;;;OAIG;;;;;;;;AApBP,wBAqIE"}
|
|
@@ -2,7 +2,7 @@ import type { Result, ResultVariant } from '@empathyco/x-types';
|
|
|
2
2
|
import type { Ref } from 'vue';
|
|
3
3
|
/**
|
|
4
4
|
* Component to show and select the available variants of a product for a given nest level.
|
|
5
|
-
* TODO:
|
|
5
|
+
* TODO: Log warning on mount when result is not injected.
|
|
6
6
|
*
|
|
7
7
|
* @public
|
|
8
8
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scroll.d.ts","sourceRoot":"","sources":["../../../../src/components/scroll/use-scroll.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAOvD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE;IACL;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,CAAA;IAC/B;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,aAAa,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC3B,EACD,EAAE,IAAI,EAAE,EAAE,YAAY,CAAC,GAAG,CAAC,EAC3B,QAAQ,EAAE,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;;
|
|
1
|
+
{"version":3,"file":"use-scroll.d.ts","sourceRoot":"","sources":["../../../../src/components/scroll/use-scroll.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAOvD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE;IACL;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,CAAA;IAC/B;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,aAAa,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC3B,EACD,EAAE,IAAI,EAAE,EAAE,YAAY,CAAC,GAAG,CAAC,EAC3B,QAAQ,EAAE,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;;EA4OvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-and-save-action.utils.d.ts","sourceRoot":"","sources":["../../../../src/store/utils/fetch-and-save-action.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGxE;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAEvC,OAAO,SAAS,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAC5E,OAAO,EACP,QAAQ,EACR,EACA,KAAK,EACL,SAAS,
|
|
1
|
+
{"version":3,"file":"fetch-and-save-action.utils.d.ts","sourceRoot":"","sources":["../../../../src/store/utils/fetch-and-save-action.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGxE;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAEvC,OAAO,SAAS,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAC5E,OAAO,EACP,QAAQ,EACR,EACA,KAAK,EACL,SAAS,EACT,OAAuB,EACvB,QAAQ,GACT,EAAE,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAkEvF;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB,CAEhC,OAAO,SAAS,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAC5E,OAAO,EACP,QAAQ;IAER;;;;;;;OAOG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAChE;;;;;;;OAOG;IACH,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IACzD;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB,CAElC,OAAO,SAAS,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAC5E,OAAO;IAEP;;;;;;OAMG;IACH,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E;;OAEG;IACH,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-filters-injection.d.ts","sourceRoot":"","sources":["../../../../../src/x-modules/facets/composables/use-filters-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAsB,MAAM,oBAAoB,CAAA;AAMpE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;CACxB,
|
|
1
|
+
{"version":3,"file":"use-filters-injection.d.ts","sourceRoot":"","sources":["../../../../../src/x-modules/facets/composables/use-filters-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAsB,MAAM,oBAAoB,CAAA;AAMpE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;CACxB,uCAqDA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-tagging.service.d.ts","sourceRoot":"","sources":["../../../../../src/x-modules/tagging/service/external-tagging.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAA;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAIrD;;;;GAIG;AACH,qBAAa,6BAA8B,YAAW,sBAAsB;IAqBxE,SAAS,CAAC,mBAAmB,EAAE,cAAc;IAC7C,SAAS,CAAC,qBAAqB,EAAE,cAAc;IArBjD;;;;OAIG;IACH,gBAAuB,qBAAqB,iBAAgB;IAE5D;;;;OAIG;IACH,gBAAuB,kBAAkB,cAAa;IAEtD;;OAEG;IACH,OAAc,QAAQ,EAAE,sBAAsB,CAAsC;gBAGxE,mBAAmB,GAAE,cAA6D,EAClF,qBAAqB,GAAE,cAGhC;IAGH,SAAS,KAAK,KAAK,IAAI,KAAK,CAAC,eAAe,CAAC,CAE5C;IAED,SAAS,KAAK,UAAU,IAAI,MAAM,CAEjC;IAED,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED;;;;;;;OAOG;IACH,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQxC;;;;;;;;OAQG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQpC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAWvC;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAmBjC;;;;;;;;;OASG;IACH,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAcrE;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"external-tagging.service.d.ts","sourceRoot":"","sources":["../../../../../src/x-modules/tagging/service/external-tagging.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAA;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAIrD;;;;GAIG;AACH,qBAAa,6BAA8B,YAAW,sBAAsB;IAqBxE,SAAS,CAAC,mBAAmB,EAAE,cAAc;IAC7C,SAAS,CAAC,qBAAqB,EAAE,cAAc;IArBjD;;;;OAIG;IACH,gBAAuB,qBAAqB,iBAAgB;IAE5D;;;;OAIG;IACH,gBAAuB,kBAAkB,cAAa;IAEtD;;OAEG;IACH,OAAc,QAAQ,EAAE,sBAAsB,CAAsC;gBAGxE,mBAAmB,GAAE,cAA6D,EAClF,qBAAqB,GAAE,cAGhC;IAGH,SAAS,KAAK,KAAK,IAAI,KAAK,CAAC,eAAe,CAAC,CAE5C;IAED,SAAS,KAAK,UAAU,IAAI,MAAM,CAEjC;IAED,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED;;;;;;;OAOG;IACH,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQxC;;;;;;;;OAQG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQpC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAWvC;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAmBjC;;;;;;;;;OASG;IACH,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAcrE;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAMpC;;;;;;;;OAQG;IACH,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAiB3C"}
|