UNPKG

@empathyco/x-components

Version:
127 lines (124 loc) 5.13 kB
import { useResizeObserver } from '@vueuse/core'; import { defineComponent, inject, ref, watch, computed, onMounted, onBeforeUnmount } from 'vue'; import { useXBus } from '../composables/use-x-bus.js'; import { AnimationProp } from '../types/animation-prop.js'; import { toKebabCase } from '../utils/string.js'; import { LIST_ITEMS_KEY } from './decorators/injection.consts.js'; /** * Grid component that is able to render different items based on their modelName value. In order * to achieve this, it exposes a scopedSlot for each different modelName. In case the items used * do not have modelName property, the default slot is used instead. It has a required property: * the `items` to render; and an optional one: the number `columns` the grid is divided in. If the * number of columns is not specified, the grid automatically fills the rows with as many columns * as it can fit. * * @public */ var _sfc_main = defineComponent({ name: 'BaseGrid', props: { /** Animation component that will be used to animate the base grid. */ animation: { type: AnimationProp, default: 'ul', }, /** * Number of columns the grid is divided into. By default, its value is 0, setting the grid * columns mode to auto-fill. */ columns: { type: Number, default: 0, }, /** * The list of items to be rendered. * * @remarks The items must have an ID property. */ items: { type: Array, }, }, setup(props, { slots }) { const xBus = useXBus(); /** It injects {@link ListItem} provided by an ancestor. */ const injectedListItems = inject(LIST_ITEMS_KEY); const gridEl = ref(); const renderedColumnsNumber = ref(0); /** * Emits the {@link XEventsTypes.RenderedColumnsNumberChanged} * event whenever the number of columns rendered inside the grid changes. */ watch(renderedColumnsNumber, () => xBus.emit('RenderedColumnsNumberChanged', renderedColumnsNumber.value), { immediate: false }); /** * It returns the items passed as props or the injected ones. * * @returns List of grid items. */ const computedItems = computed(() => { return (props.items ?? injectedListItems?.value ?? console.warn('It is necessary to pass a prop or inject the list of filters')); }); /** * CSS class based on the column property value so items inside the grid can fill different * amount of columns or rows based on how many columns the grid is divided into. * * @returns CSS class with the column property value. */ const cssClasses = computed(() => `x-base-grid--cols-${props.columns || 'auto'}`); /** * CSSStyleDeclaration object specifying the number of columns the grid is divided into based on * the column property value. * * @returns A CSSStyleDeclaration to use as the style attribute. */ const style = computed(() => ({ gridTemplateColumns: props.columns ? `repeat(${props.columns}, minmax(0, 1fr))` : 'repeat(auto-fill, minmax(var(--x-size-min-width-grid-item, 150px), 1fr))', })); /** * Maps the item to an object containing: the `item`, its `CSS class` and its slot name. * * @returns An array of objects containing the item and its CSS class. */ const gridItems = computed(() => computedItems.value.map(item => { const slotName = toKebabCase(item.modelName); return { slotName, item, cssClass: `x-base-grid__${slotName}`, }; })); /** * Checks if a given value is an `ElementRef` object. * * @param value - The value to check. * @returns `true` if the value is an `ElementRef` object, `false` otherwise. */ const isElementRef = (value) => { return value && value.$el instanceof HTMLElement; }; /** Updates the number of columns rendered inside the grid. */ function updateRenderedColumnsNumber() { const { gridTemplateColumns } = getComputedStyle(isElementRef(gridEl.value) ? gridEl.value.$el : gridEl.value); renderedColumnsNumber.value = gridTemplateColumns.split(' ').length; } /** Initialises the rendered columns number and sets a ResizeObserver to keep it updated. */ let resizeObserver; onMounted(() => { resizeObserver = useResizeObserver(gridEl, updateRenderedColumnsNumber); }); onBeforeUnmount(() => resizeObserver?.stop()); return { gridItems, cssClasses, style, gridEl, slots, }; }, }); export { _sfc_main as default }; //# sourceMappingURL=base-grid.vue2.js.map