UNPKG

@uniquedj95/vtable

Version:

An advanced datatable for Ionic vue framework

780 lines (772 loc) 34.4 kB
'use strict'; var get = require('lodash/get'); var isEmpty = require('lodash/isEmpty'); var orderBy = require('lodash/orderBy'); var vue = require('vue'); var range = require('lodash/range'); var vue$1 = require('@ionic/vue'); var icons = require('ionicons/icons'); var lodash = require('lodash'); /** * Retrieves an array of rows either from a getter function or the provided default rows. * * @param getter - An optional function to retrieve rows asynchronously. * @param defaultRows - An array of default rows (empty by default). * @param indexed - If true, adds an 'index' property to each row. * @returns An array of rows. */ async function getRows(defaultRows, indexed = false, getter) { let rows = defaultRows; if (typeof getter === 'function') rows = await getter(); return indexed ? rows.map((r, i) => ({ ...r, index: i + 1 })) : rows; } /** * A function that sort table rows based on specified sort queries * * @param rows An array of data * @param query an array of sort queries * @returns sorted array */ function sortRows(rows, query) { if (isEmpty(query)) return rows; const orders = query.map(({ order }) => order); return orderBy(rows.slice(), query.map(({ column }) => (row) => { let value = get(row, column.path); if (!value || isEmpty(value)) return ""; if (typeof column.preSort === "function") value = column.preSort(value); if (typeof value === "number" || column.sortCaseSensitive) return value; return value.toString().toLowerCase(); }), orders); } /** * Builds pagination information summary * * @param paginator The current pagination filter * @param totalRows Total filtered rows * @returns string */ function buildPaginationInfo(paginator, totalRows) { const { page, pageSize, totalPages } = paginator; const from = (page * pageSize) - (pageSize - 1); const to = (page === totalPages) ? totalRows : page * pageSize; return totalRows ? `Showing ${from} to ${to} of ${totalRows} entries` : "No data available"; } /** * Calculates the range of visible page numbers for pagination. * * @param paginator - The pagination settings. * @param totalRows - The total number of rows. * @param pages - An array of current visible page numbers. * @returns The updated pagination settings. */ function calculatePageRange(paginator, totalRows, pages) { // Calculate the total number of pages paginator.totalPages = Math.ceil(totalRows / paginator.pageSize); // If total pages are within visibleBtns, show all pages if (paginator.totalPages <= paginator.visibleBtns) { paginator.start = 1; paginator.end = paginator.totalPages; return paginator; } // Return if start and end page numbers are already visible if ((pages.includes(paginator.page - 1) || paginator.page === 1) && (pages.includes(paginator.page + 1) || paginator.page === paginator.totalPages)) { return paginator; } // Calculate the range of visible page numbers paginator.start = paginator.page === 1 ? 1 : paginator.page - 1; paginator.end = paginator.start + paginator.visibleBtns - 5; // Adjust start and end if they go out of bounds if (paginator.start <= 3) { paginator.end += 3 - paginator.start; paginator.start = 1; } if (paginator.end >= paginator.totalPages - 2) { paginator.start -= paginator.end - (paginator.totalPages - 2); paginator.end = paginator.totalPages; } // Ensure start is within valid range paginator.start = Math.max(paginator.start, 1); return paginator; } /** * Paginates an array of rows based on the provided pagination settings. * * @param rows - The array of rows to be paginated. * @param paginator - The pagination settings. * @returns The paginated array of rows. */ function getActiveRows(rows, paginator) { if (isEmpty(rows)) return rows; const { page, pageSize } = paginator; const start = (page - 1) * pageSize; return rows.slice(start, start + pageSize); } /** * Initializes sort queries based on column configurations. * * @param columns - An array of table columns. * @returns An array of initial sort queries. */ function initializeSortQueries(columns) { return columns.reduce((acc, column) => { if (column.initialSort) acc.push({ column, order: column.initialSortOrder || "asc" }); return acc; }, []); } /** * Updates the array of sort queries based on a specific column. * * @param sortQueries - The current array of sort queries. * @param column - The column for which to update the sort query. * @returns The updated array of sort queries. */ function updateSortQueries(sortQueries, column) { const i = sortQueries.findIndex(q => q.column.path === column.path); if (i >= 0) sortQueries[i].order = sortQueries[i].order === 'asc' ? 'desc' : 'asc'; else sortQueries = [{ column, order: 'asc' }]; return sortQueries; } /** * Filters an array of rows based on a query string. * * @param rows - The array of rows to be filtered. * @param query - The query string for filtering. * @returns The filtered array of rows. */ function filterRows(rows, query) { if (!query || isEmpty(rows)) return rows; return rows.slice().filter(row => Object.values(row).some(v => v && JSON.stringify(v).toLowerCase().includes(query.toLowerCase()))); } /** * Determines if a table column is drillable based on the provided column configuration, value, and row. * * @param column - The table column configuration object. * @param value - The value in the table cell. * @param row - The entire row data. * @returns A boolean indicating whether the column is drillable. */ function isDrillable(column, value, row) { return typeof column.drillable === 'function' ? column.drillable(value, row) : !!column.drillable && !isEmpty(value); } const SelectInput = vue.defineComponent({ name: "SelectInput", props: { value: { type: Object, default: () => ({}), }, label: { type: String, default: "" }, placeholder: { type: String, default: "Select Option" }, options: { type: Array, default: () => [], }, asyncOptions: { type: Function, required: false, }, disabled: { type: Boolean, default: false }, multiple: { type: Boolean, default: false }, required: { type: Boolean, default: false }, validate: { type: Function, required: false } }, emits: ["select"], setup(props, { emit }) { const selectedOption = vue.ref(); const canShowOptions = vue.ref(false); const filter = vue.ref(''); const filteredOptions = vue.ref([]); const errs = vue.ref(""); const errorClass = vue.computed(() => errs.value ? "box-input-error" : ""); const marginTop = vue.computed(() => props.label ? "ion-margin-top" : ""); const tags = vue.computed(() => { if (props.multiple) return filteredOptions.value.filter(({ isChecked }) => isChecked); return selectedOption.value ? [selectedOption.value] : []; }); const showPlaceholder = vue.computed(() => { return !filter.value && lodash.isEmpty(tags.value) && !canShowOptions.value; }); const model = vue.computed({ get: () => props.value, set: (value) => emit("select", value) }); const setDefaults = () => { selectedOption.value = undefined; if (lodash.isEmpty(model.value)) return; if (Array.isArray(model.value) && props.multiple) { model.value.forEach(option => { const index = filteredOptions.value.findIndex(({ value }) => value === option.value); if (index === -1) { filteredOptions.value.push({ ...option, isChecked: true }); } else { filteredOptions.value[index].isChecked = true; } }); } selectedOption.value = filteredOptions.value.find(option => { if (Array.isArray(model.value)) return option.value === model.value[0].value; return option.value === model.value.value; }); if (lodash.isEmpty(selectedOption.value)) { selectedOption.value = Array.isArray(model.value) ? model.value[0] : model.value; } }; const filterOptions = async () => { const filtered = typeof props.asyncOptions === 'function' ? await props.asyncOptions(filter.value) : props.options.filter(({ label }) => label.toLowerCase().includes(filter.value.toLowerCase())); tags.value.forEach(tag => { const index = filtered.findIndex(f => f.value === tag.value); if (index === -1) filtered.push(tag); else filtered[index].isChecked = true; }); filteredOptions.value = filtered; }; const validate = async () => { if (props.required && lodash.isEmpty(model.value)) { return errs.value = "This field is required"; } if (typeof props.validate === 'function') { const errors = await props.validate(model.value); if (errors && errors.length) { errs.value = errors.join(', '); } } return errs.value = ""; }; const onCloseOptions = () => { canShowOptions.value = false; model.value = props.multiple ? tags.value : !lodash.isEmpty(tags.value) ? tags.value[0] : {}; filter.value = ''; validate(); }; const showOptions = () => { if (props.disabled) return; canShowOptions.value = true; errs.value = ''; }; const selectOption = (item) => { if (!props.multiple) { selectedOption.value = item; return onCloseOptions(); } model.value = props.multiple ? tags.value : !lodash.isEmpty(tags.value) ? tags.value[0] : {}; filter.value = ''; }; const diselectOption = (tag) => { if (props.multiple) return tag.isChecked = false; return selectedOption.value = undefined; }; const onReset = () => { filter.value = ''; selectedOption.value = undefined; filteredOptions.value.forEach(option => option.isChecked = false); }; vue.watch(() => props.value, () => setDefaults()); vue.watch([filter, () => props.options, () => props.asyncOptions], async () => { await filterOptions(); setDefaults(); }); vue.onMounted(async () => { await filterOptions(); setDefaults(); addEventListener('click', (e) => { const isClosest = e.target.closest('.inner-input-box'); if (!isClosest && canShowOptions.value) { onCloseOptions(); } }); }); vue.onBeforeUnmount(() => removeEventListener('click', e => console.log(e))); return () => [ props.label && vue.h(vue$1.IonLabel, { class: "ion-padding-bottom bold" }, props.label), vue.h("div", { class: `outer-input-box box-input ${errorClass.value} ${marginTop.value}` }, vue.h("div", { class: "inner-input-box" }, [ vue.h("div", { style: { display: 'flex', flexWrap: 'wrap', width: '100%' }, onClick: showOptions }, [ ...tags.value.map(tag => vue.h(vue$1.IonChip, [ vue.h(vue$1.IonLabel, tag.label), vue.h(vue$1.IonIcon, { icon: icons.closeCircle, color: 'danger', onClick: () => diselectOption(tag), style: { zIndex: 90 } }) ])), vue.h(vue$1.IonInput, { disabled: props.disabled, placeholder: showPlaceholder.value ? props.placeholder : '', class: "search-input", value: filter.value, onIonInput: (e) => filter.value = e.target.value }) ]), canShowOptions.value && vue.h("div", { class: "input-options" }, vue.h(vue$1.IonList, filteredOptions.value.map((option, i) => vue.h(vue$1.IonItem, { lines: i + 1 === filteredOptions.value.length ? 'none' : undefined, onClick: () => selectOption(option) }, [ props.multiple && vue.h(vue$1.IonCheckbox, { class: "input-option-checkbox", slot: "start", value: option.isChecked, onIonInput: (e) => option.isChecked = e.target.checked }), vue.h(vue$1.IonLabel, option.label) ])))), vue.h("div", { class: "input-icon" }, [ (filter.value || tags.value.length) && vue.h(vue$1.IonIcon, { icon: icons.close, onClick: onReset }), vue.h(vue$1.IonIcon, { icon: canShowOptions.value ? icons.chevronUp : icons.chevronDown, onClick: canShowOptions.value ? onCloseOptions : showOptions }) ].filter(Boolean)) ])), errs.value && vue.h(vue$1.IonNote, { color: "danger" }, errs.value) ]; } }); const DateRangePicker = vue.defineComponent({ props: { range: { type: Object, default: () => ({ startDate: "", endDate: "" }), }, }, emits: ["rangeChange"], setup(props, { emit }) { const start = vue.ref(props.range.startDate); const end = vue.ref(props.range.endDate); const cRange = vue.computed(() => ({ startDate: start.value, endDate: end.value })); vue.watch(cRange, (v) => emit("rangeChange", v)); return () => vue.h(vue$1.IonGrid, { class: 'ion-no-padding ion-no-margin' }, vue.h(vue$1.IonRow, [ vue.h(vue$1.IonCol, { size: "6" }, vue.h(vue$1.IonInput, { type: 'date', class: 'box-input', value: start.value, onIonInput: (e) => start.value = e.target.value, style: { width: "100%" } })), vue.h(vue$1.IonCol, { size: '1', style: { display: "flex", justifyContent: "center " } }, vue.h(vue$1.IonIcon, { icon: icons.arrowForward, style: { fontSize: '24px', padding: '.5rem' } })), vue.h(vue$1.IonCol, { size: "5" }, vue.h(vue$1.IonInput, { type: 'date', class: 'box-input', value: end.value, onIonInput: (e) => end.value = e.target.value, style: { width: "100%" } })), ])); }, }); const DataTable = vue.defineComponent({ name: "DataTable", props: { rows: { type: Array, default: () => [] }, asyncRows: { type: Function, required: false }, columns: { type: Array, default: () => [] }, actionsButtons: { type: Array, default: () => [] }, rowActionsButtons: { type: Array, default: () => [] }, customFilters: { type: Array, default: () => [] }, color: { type: String, }, config: { type: Object, default: () => ({}) }, loading: { type: Boolean, default: false } }, emits: ["customFilter", "queryChange", "drilldown"], setup(props, { emit, slots }) { const isLoading = vue.ref(false); const tableRows = vue.ref([]); const filteredRows = vue.ref([]); const totalFilteredRows = vue.computed(() => filteredRows.value.length); const totalColumns = vue.computed(() => isEmpty(props.rowActionsButtons) ? tableColumns.value.length : tableColumns.value.length + 1); const paginationPages = vue.computed(() => filters.pagination.enabled ? range(filters.pagination.start, filters.pagination.end + 1) : []); const tableColumns = vue.computed(() => props.config.showIndices ? [{ path: "index", label: "#", initialSort: true, initialSortOrder: "asc" }, ...props.columns] : props.columns); const filters = vue.reactive({ search: "", sort: [], pagination: { enabled: props.config?.pagination?.enabled ?? true, page: props.config?.pagination?.page ?? 1, pageSize: props.config?.pagination?.pageSize ?? 10, start: props.config?.pagination?.start ?? 1, end: props.config?.pagination?.end ?? 1, totalPages: props.config?.pagination?.totalPages ?? 1, visibleBtns: props.config?.pagination?.visibleBtns ?? 7, pageSizeOptions: props.config?.pagination?.pageSizeOptions ?? [5, 10, 20, 50, 100] } }); const activeRows = vue.ref([]); const showFilterSection = vue.computed(() => { return props.config.showSearchField !== false || props.customFilters.length > 0 || props.actionsButtons.length > 0; }); const customFiltersValues = vue.reactive(props.customFilters.reduce((acc, filter) => { acc[filter.id] = filter.value; return acc; }, {})); const init = async () => { isLoading.value = true; tableRows.value = await getRows(props.rows, props.config.showIndices || false, props.asyncRows); filters.sort = initializeSortQueries(tableColumns.value); handleFilters(filters.pagination); isLoading.value = false; }; const handleFilters = (paginator, search, sortColumn) => { filters.search = search ?? ""; if (sortColumn) filters.sort = updateSortQueries(filters.sort, sortColumn); const _filteredRows = filterRows(tableRows.value, filters.search); filteredRows.value = sortRows(_filteredRows, filters.sort); if (filters.pagination.enabled) { filters.pagination = calculatePageRange(paginator, totalFilteredRows.value, paginationPages.value); activeRows.value = getActiveRows(filteredRows.value, filters.pagination); } else { activeRows.value = filteredRows.value; } }; vue.watch(customFiltersValues, () => { if (props.config.showSubmitButton === false) { emit("customFilter", customFiltersValues); } }, { immediate: true, deep: true }); vue.watch(() => props.rows, () => init(), { deep: true, immediate: true }); vue.onMounted(() => init()); const renderSearchbar = () => { if (props.config.showSearchField !== false) { return vue.h(vue$1.IonCol, { size: '4' }, [ vue.h(vue$1.IonSearchbar, { placeholder: 'search here...', class: 'box ion-no-padding', value: filters.search, onIonInput: (e) => handleFilters({ ...filters.pagination, page: 1 }, e.target.value), }) ]); } return null; }; const renderSelectFilter = (filter) => vue.h(vue$1.IonCol, { size: `${filter.gridSize}` || '3' }, vue.h(SelectInput, { options: filter.options, placeholder: filter.label || filter.placeholder || 'Select Item', value: filter.value, multiple: filter.multiple, onSelect: (v) => { if (typeof filter.onUpdate === "function") filter.onUpdate(v); customFiltersValues[filter.id] = v; } })); const renderDateRangeFilter = (filter) => vue.h(vue$1.IonCol, { size: `${filter.gridSize}` || '6' }, vue.h(DateRangePicker, { range: (vue.computed(() => filter.value || { startDate: "", endDate: "" })).value, onRangeChange: async (newRange) => { if (typeof filter.onUpdate === "function") filter.onUpdate(newRange); customFiltersValues[filter.id] = newRange; } })); const renderDefaultFilter = (filter) => vue.h(vue$1.IonCol, { size: '4' }, vue.h(vue$1.IonInput, { class: 'box', type: filter.type, placeholder: filter.placeholder, value: (vue.computed(() => filter.value || "")).value, onIonInput: async (e) => { const value = e.target.value; if (typeof filter.onUpdate === "function") filter.onUpdate(value); customFiltersValues[filter.id] = value; } })); const renderCustomFilters = () => { return props.customFilters.map(filter => { if (filter.slotName && typeof slots[filter.slotName] === "function") { return vue.h(vue$1.IonCol, { size: `${filter.gridSize || '3'}` }, slots[filter.slotName]({ filter })); } if (filter.type === 'dateRange') return renderDateRangeFilter(filter); if (filter.type === 'select') return renderSelectFilter(filter); return renderDefaultFilter(filter); }); }; const renderSubmitButton = () => { if (props.customFilters.length > 0 && props.config.showSubmitButton !== false) { return vue.h(vue$1.IonCol, { size: '2' }, [ vue.h(vue$1.IonButton, { color: "primary", class: "ion-no-margin", onClick: () => emit("customFilter", customFiltersValues) }, 'Submit') ]); } return null; }; const renderActionsButtons = () => { return props.actionsButtons.map(btn => vue.h(vue$1.IonButton, { class: 'ion-float-right', color: btn.color || 'primary', size: btn.size ?? "default", onClick: () => btn.action(activeRows.value, tableRows.value, filters, tableColumns.value) }, btn.icon ? vue.h(vue$1.IonIcon, { icon: btn.icon }) : btn.label)); }; const renderFilterSection = () => { return showFilterSection.value && vue.h(vue$1.IonGrid, { style: { width: '100%', fontWeight: 500 } }, vue.h(vue$1.IonRow, [ vue.h(vue$1.IonCol, { size: '7' }, vue.h(vue$1.IonRow, [ renderSearchbar(), ...renderCustomFilters(), renderSubmitButton(), ])), vue.h(vue$1.IonCol, { size: '5', class: "ion-padding-end" }, renderActionsButtons()) ])); }; const renderPagination = () => { return filters.pagination.enabled && filters.pagination.totalPages > 1 && vue.h(vue$1.IonGrid, { style: { width: '100%', textAlign: 'left', color: 'black' }, class: 'ion-padding' }, vue.h(vue$1.IonRow, [ vue.h(vue$1.IonCol, { size: '4' }, renderPaginationControls()), vue.h(vue$1.IonCol, { size: '5', class: "text-center" }, [ renderGoToPageInput(), renderItemsPerPageSelect() ]), vue.h(vue$1.IonCol, { size: '3' }, renderPaginationInfo()) ])); }; const renderPaginationControls = () => { const { page, start, end, totalPages } = filters.pagination; const handleClick = (page) => { return handleFilters({ ...filters.pagination, page }); }; const controls = [ renderPageControlButton({ icon: icons.caretBack, disabled: page === start, onClick: () => handleClick(page - 1) }), ]; if (start > 3) { controls.push(renderPageControlButton({ label: '1', onClick: () => handleClick(1) })); controls.push(renderPageControlButton({ label: '...', disabled: true })); } paginationPages.value.forEach(label => { controls.push(renderPageControlButton({ label, onClick: () => handleClick(label) })); }); if (end < totalPages - 2) { controls.push(renderPageControlButton({ label: '...', disabled: true })); controls.push(renderPageControlButton({ label: totalPages, onClick: () => handleClick(totalPages) })); } controls.push(renderPageControlButton({ icon: icons.caretForward, disabled: page === end || isEmpty(filteredRows.value), onClick: () => handleClick(page + 1) })); return controls; }; const renderPageControlButton = ({ disabled, label, icon, onClick }) => { return vue.h(vue$1.IonButton, { onClick, disabled, size: 'small', color: filters.pagination.page === label ? 'primary' : 'light', }, icon ? vue.h(vue$1.IonIcon, { icon }) : label || "Button"); }; const renderGoToPageInput = () => { return vue.h(vue$1.IonItem, { class: "box go-to-input ion-hide-xl-down", lines: "none" }, [ vue.h(vue$1.IonLabel, { class: 'ion-margin-end' }, "Go to page"), vue.h(vue$1.IonInput, { type: "number", min: 1, max: filters.pagination.totalPages, value: filters.pagination.page, style: { paddingRight: '15px' }, debounce: 500, onIonChange: (e) => { const page = e.target.value; if (page > 0 && page <= filters.pagination.totalPages) { handleFilters({ ...filters.pagination, page }); } } }), ]); }; const renderItemsPerPageSelect = () => { return vue.h(vue$1.IonItem, { class: "box per-page-input", lines: "none" }, [ vue.h(vue$1.IonLabel, "Items per page"), vue.h(vue$1.IonSelect, { value: filters.pagination.pageSize, onIonChange: (e) => handleFilters({ ...filters.pagination, pageSize: e.target.value, page: 1 }), }, [ ...filters.pagination.pageSizeOptions.map(value => vue.h(vue$1.IonSelectOption, { value, key: value }, value)), vue.h(vue$1.IonSelectOption, { value: totalFilteredRows.value }, "All") ]), ]); }; const renderPaginationInfo = () => { return vue.h(vue$1.IonCol, { size: '4', class: "pagination-info" }, (vue.computed(() => { return buildPaginationInfo(filters.pagination, totalFilteredRows.value); })).value); }; const renderTableHeader = () => vue.h("thead", { class: props.color || "" }, vue.h("tr", [ ...tableColumns.value.map(column => renderTableHeaderCell(column)), !isEmpty(props.rowActionsButtons) && vue.h('th', 'Actions') ])); const renderSortIcon = (column) => { const style = { marginRight: "5px", float: "right", cursor: 'pointer' }; const icon = vue.computed(() => { const query = filters.sort.find(s => s.column.path === column.path); return !query ? icons.swapVertical : query.order == "asc" ? icons.arrowUp : icons.arrowDown; }); return vue.h(vue$1.IonIcon, { icon: icon.value, style }); }; const renderTableHeaderCell = (column) => { const style = { minWidth: /index/i.test(column.path) ? '80px' : '190px', ...column.thStyles }; const onClick = () => handleFilters(filters.pagination, filters.search, column); return vue.h("th", { key: column.label, style, class: column.thClasses?.join(" "), onClick }, [ vue.h("span", column.label), column.sortable !== false && renderSortIcon(column), ]); }; const renderTableBody = () => { return vue.h("tbody", { class: "table-body" }, isLoading.value || props.loading ? renderLoadingRows() : isEmpty(filteredRows.value) ? renderNoDataRow() : renderDataRows()); }; const renderLoadingRows = () => { return range(0, 9).map(i => vue.h("tr", { key: i }, vue.h('td', { colspan: totalColumns.value }, vue.h(vue$1.IonSkeletonText, { animated: true, style: { width: '100%' } })))); }; const renderNoDataRow = () => { return vue.h('tr', vue.h('td', { colspan: totalColumns.value }, vue.h('div', { class: 'no-data-table' }, 'No data available'))); }; const handleRowClick = async (row, rowIndex) => { const defaultActionBtn = props.rowActionsButtons.find(btn => btn.default); if (defaultActionBtn) await defaultActionBtn.action(row, rowIndex); }; const renderDataRows = () => { return activeRows.value.map((row, rowIndex) => vue.h('tr', { key: row, onClick: () => handleRowClick(row, rowIndex) }, [ ...renderDataRowCells(row), renderRowActionCells(row, rowIndex) ])); }; const renderDataRowCells = (row) => { return tableColumns.value.map((column, key) => { const classes = ["data-cell", ...column.tdClasses ?? []].join(" "); return vue.h('td', { key, class: classes, style: column.tdStyles }, renderCellContent(row, column)); }); }; const renderCellContent = (row, column) => { let value = get(row, column.path); if (typeof column.formatter === 'function' && value) value = column.formatter(value, row); if (isDrillable(column, value, row)) { return vue.h('a', { onClick: () => emit("drilldown", { column, row }) }, renderCellValue(value)); } else { return renderCellValue(value); } }; const renderCellValue = (value) => { return Array.isArray(value) ? value.length : value; }; const renderRowActionCells = (row, rowIndex) => { if (!isEmpty(props.rowActionsButtons)) { return vue.h('td', props.rowActionsButtons.map(btn => { const canShowBtn = typeof btn.condition === 'function' ? btn.condition(row) : true; return canShowBtn ? renderRowActionButton(row, rowIndex, btn) : null; })); } return null; }; const renderRowActionButton = (row, rowIndex, btn) => { return vue.h(vue$1.IonButton, { key: btn.icon, size: btn.size ?? 'small', color: btn.color || 'primary', onClick: () => btn.action(row, rowIndex) }, btn.icon ? vue.h(vue$1.IonIcon, { icon: btn.icon }) : btn.label || "Button"); }; const renderTable = () => { return vue.h("div", { class: "responsive-table ion-padding-horizontal" }, vue.h("table", { class: "table bordered-table striped-table" }, [ renderTableHeader(), renderTableBody() ])); }; return () => [ renderFilterSection(), renderTable(), renderPagination(), ]; } }); // The Install function used by Vue to register the plugin const VTable = { install(app, options) { app.config.globalProperties.$globalTableOptions = options; app.provide("globalTableOptions", options); app.component('DataTable', DataTable); } }; exports.DataTable = DataTable; exports.VTable = VTable; exports.buildPaginationInfo = buildPaginationInfo; exports.calculatePageRange = calculatePageRange; exports.filterRows = filterRows; exports.getActiveRows = getActiveRows; exports.getRows = getRows; exports.initializeSortQueries = initializeSortQueries; exports.isDrillable = isDrillable; exports.sortRows = sortRows; exports.updateSortQueries = updateSortQueries; //# sourceMappingURL=index.js.map