@empathyco/x-components
Version:
Empathy X Components
152 lines (149 loc) • 5.88 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 { useState } from '../../../composables/use-state.js';
import { AnimationProp } from '../../../types/animation-prop.js';
import { groupItemsBy } from '../../../utils/array.js';
import { relatedPromptsXModule } from '../x-module.js';
/**
* Component that inserts groups of related prompts in different positions of the injected search
* items list, based on the provided configuration.
*
* @public
*/
var _sfc_main = defineComponent({
name: 'RelatedPromptsList',
xModule: relatedPromptsXModule.name,
props: {
/**
* Animation component that will be used to animate the related prompts groups.
*/
animation: {
type: AnimationProp,
default: 'ul',
},
/**
* The first index to insert a group of related prompts at.
*/
offset: {
type: Number,
default: 24,
},
/**
* The items cycle size to keep inserting related prompts groups at.
*/
frequency: {
type: Number,
default: 24,
},
/**
* The maximum amount of related prompts to add in a single group.
*/
maxRelatedPromptsPerGroup: {
type: Number,
default: 4,
},
/**
* The maximum number of groups to insert into the injected list items list.
*/
maxGroups: {
type: Number,
default: undefined,
},
/**
* 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 }) {
/**
* The state related prompts.
*/
const { query, status, relatedPrompts } = useState('relatedPrompts');
/**
* 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 related prompts based on the given config.
*
* @returns A list of related prompts groups.
*/
const relatedPromptsGroups = computed(() => Object.values(groupItemsBy(relatedPrompts.value, (_, index) => Math.floor(index / props.maxRelatedPromptsPerGroup)))
.slice(0, props.maxGroups)
.map((relatedPrompts, index) => ({
modelName: 'RelatedPromptsGroup',
id: `related-prompts-group-${index}`,
relatedPrompts,
})));
/**
* It injects {@link ListItem} provided by an ancestor as injectedListItems.
*/
const injectedListItems = inject(LIST_ITEMS_KEY);
/**
* Checks if the related prompts are outdated taking into account the injected query.
*
* @returns True if the related prompts are outdated, false if not.
*/
const relatedPromptsAreOutdated = 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 related prompts groups inserted.
*/
const items = computed(() => {
if (!injectedListItems?.value) {
return relatedPromptsGroups.value;
}
if (relatedPromptsAreOutdated.value) {
return injectedListItems.value;
}
if (hasNotEnoughListItems.value) {
return injectedListItems.value.concat(relatedPromptsGroups.value[0] ?? []);
}
return relatedPromptsGroups?.value.reduce((items, relatedPromptsGroup, index) => {
const targetIndex = props.offset + props.frequency * index;
if (targetIndex <= items.length) {
items.splice(targetIndex, 0, relatedPromptsGroup);
}
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=related-prompts-list.vue.js.map