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