@empathyco/x-components
Version:
Empathy X Components
132 lines (129 loc) • 5.67 kB
JavaScript
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