UNPKG

@empathyco/x-components

Version:
132 lines (129 loc) 5.67 kB
import { defineComponent, inject, computed, provide, h } from 'vue'; import { QUERY_KEY, HAS_MORE_ITEMS_KEY, LIST_ITEMS_KEY } from '../../../components/decorators/injection.consts.js'; import ItemsList from '../../../components/items-list.vue.js'; import { useGetter } from '../../../composables/use-getter.js'; import { useState } from '../../../composables/use-state.js'; import { AnimationProp } from '../../../types/animation-prop.js'; import { groupItemsBy } from '../../../utils/array.js'; import { nextQueriesXModule } from '../x-module.js'; /** * Component that inserts groups of next queries in different positions of the injected search * items list, based on the provided configuration. * * @public */ var _sfc_main = defineComponent({ name: 'NextQueriesList', xModule: nextQueriesXModule.name, props: { /** Animation component that will be used to animate the next queries groups. */ animation: { type: AnimationProp, default: 'ul', }, /** The first index to insert a group of next queries at. */ offset: { type: Number, default: 24, }, /** The items cycle size to keep inserting next queries groups at. */ frequency: { type: Number, default: 24, }, /** The maximum amount of next queries to add in a single group. */ maxNextQueriesPerGroup: { type: Number, default: 4, }, /** The maximum number of groups to insert into the injected list items list. */ maxGroups: Number, /** * Determines if a group is added to the injected items list in case the number * of items is smaller than the offset. */ showOnlyAfterOffset: { type: Boolean, default: false, }, }, setup(props, { slots }) { const { query, status } = useState('nextQueries'); /** The state next queries. */ const nextQueries = useGetter('nextQueries').nextQueries; /** Injected query, updated when the related request(s) have succeeded. */ const injectedQuery = inject(QUERY_KEY); /** Indicates if there are more available results than the injected. */ const hasMoreItems = inject(HAS_MORE_ITEMS_KEY); /** * The grouped next queries based on the given config. * * @returns A list of next queries groups. */ const nextQueriesGroups = computed(() => Object.values(groupItemsBy(nextQueries?.value, (_, index) => Math.floor(index / props.maxNextQueriesPerGroup))) .slice(0, props.maxGroups) .map(nextQueries => ({ modelName: 'NextQueriesGroup', id: nextQueries.map(nextQuery => nextQuery.query).join(','), nextQueries, }))); /** It injects {@link ListItem} provided by an ancestor as injectedListItems. */ const injectedListItems = inject(LIST_ITEMS_KEY); /** * Checks if the next queries are outdated taking into account the injected query. * * @returns True if the next queries are outdated, false if not. */ const nextQueriesAreOutdated = computed(() => !!injectedQuery?.value && (query.value !== injectedQuery.value || status.value !== 'success')); /** * Checks if the number of items is smaller than the offset so a group * should be added to the injected items list. * * @returns True if a group should be added, false if not. */ const hasNotEnoughListItems = computed(() => !props.showOnlyAfterOffset && !hasMoreItems?.value && injectedListItems !== undefined && injectedListItems.value.length > 0 && props.offset > injectedListItems.value.length); /** * New list of {@link ListItem}s to render. * * @returns The new list of {@link ListItem}s with the next queries groups inserted. */ const items = computed(() => { if (!injectedListItems?.value) { return nextQueriesGroups.value; } if (nextQueriesAreOutdated.value) { return injectedListItems.value; } if (hasNotEnoughListItems.value) { return injectedListItems.value.concat(nextQueriesGroups.value[0] ?? []); } return nextQueriesGroups?.value.reduce((items, nextQueriesGroup, index) => { const targetIndex = props.offset + props.frequency * index; if (targetIndex <= items.length) { items.splice(targetIndex, 0, nextQueriesGroup); } return items; }, [...injectedListItems.value]); }); /** * The computed list items of the entity that uses the mixin. * * @remarks It should be overridden in the component that uses the mixin and it's intended to be * filled with items from the state. Vue doesn't allow mixins as abstract classes. * @returns An empty array as fallback in case it is not overridden. */ provide(LIST_ITEMS_KEY, items); return () => { const innerProps = { items: items.value, animation: props.animation }; // https://vue-land.github.io/faq/forwarding-slots#passing-all-slots return slots.default?.(innerProps)[0] ?? h(ItemsList, innerProps, slots); }; }, }); export { _sfc_main as default }; //# sourceMappingURL=next-queries-list.vue.js.map