Fixed #3802 - Improve folder structure for nuxt configurations

This commit is contained in:
mertsincan 2023-03-26 06:22:57 +01:00
parent 851950270b
commit f5fe822afb
563 changed files with 1703 additions and 1095 deletions

View file

@ -0,0 +1,462 @@
<template>
<td v-if="loading" :style="containerStyle" :class="containerClass">
<component :is="column.children.loading" :data="rowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" :loadingOptions="loadingOptions" />
</td>
<td v-else :style="containerStyle" :class="containerClass" @click="onClick" @keydown="onKeyDown" role="cell">
<span v-if="responsiveLayout === 'stack'" class="p-column-title">{{ columnProp('header') }}</span>
<component v-if="column.children && column.children.body && !d_editing" :is="column.children.body" :data="rowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" :editorInitCallback="editorInitCallback" />
<component
v-else-if="column.children && column.children.editor && d_editing"
:is="column.children.editor"
:data="editingRowData"
:column="column"
:field="field"
:index="rowIndex"
:frozenRow="frozenRow"
:editorSaveCallback="editorSaveCallback"
:editorCancelCallback="editorCancelCallback"
/>
<component v-else-if="column.children && column.children.body && !column.children.editor && d_editing" :is="column.children.body" :data="editingRowData" :column="column" :field="field" :index="rowIndex" :frozenRow="frozenRow" />
<template v-else-if="columnProp('selectionMode')">
<DTRadioButton v-if="columnProp('selectionMode') === 'single'" :value="rowData" :name="name" :checked="selected" @change="toggleRowWithRadio($event, rowIndex)" />
<DTCheckbox v-else-if="columnProp('selectionMode') === 'multiple'" :value="rowData" :checked="selected" :aria-selected="selected ? true : undefined" @change="toggleRowWithCheckbox($event, rowIndex)" />
</template>
<template v-else-if="columnProp('rowReorder')">
<i :class="['p-datatable-reorderablerow-handle', columnProp('rowReorderIcon') || 'pi pi-bars']"></i>
</template>
<template v-else-if="columnProp('expander')">
<button v-ripple class="p-row-toggler p-link" type="button" :aria-expanded="isRowExpanded" :aria-controls="ariaControls" :aria-label="expandButtonAriaLabel" @click="toggleRow">
<span :class="rowTogglerIcon"></span>
</button>
</template>
<template v-else-if="editMode === 'row' && columnProp('rowEditor')">
<button v-if="!d_editing" v-ripple class="p-row-editor-init p-link" type="button" :aria-label="initButtonAriaLabel" @click="onRowEditInit">
<span class="p-row-editor-init-icon pi pi-fw pi-pencil"></span>
</button>
<button v-if="d_editing" v-ripple class="p-row-editor-save p-link" type="button" :aria-label="saveButtonAriaLabel" @click="onRowEditSave">
<span class="p-row-editor-save-icon pi pi-fw pi-check"></span>
</button>
<button v-if="d_editing" v-ripple class="p-row-editor-cancel p-link" type="button" :aria-label="cancelButtonAriaLabel" @click="onRowEditCancel">
<span class="p-row-editor-cancel-icon pi pi-fw pi-times"></span>
</button>
</template>
<template v-else>{{ resolveFieldData() }}</template>
</td>
</template>
<script>
import OverlayEventBus from 'primevue/overlayeventbus';
import Ripple from 'primevue/ripple';
import { DomHandler, ObjectUtils } from 'primevue/utils';
import RowCheckbox from './RowCheckbox.vue';
import RowRadioButton from './RowRadioButton.vue';
export default {
name: 'BodyCell',
emits: ['cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'row-edit-init', 'row-edit-save', 'row-edit-cancel', 'row-toggle', 'radio-change', 'checkbox-change', 'editing-meta-change'],
props: {
rowData: {
type: Object,
default: null
},
column: {
type: Object,
default: null
},
frozenRow: {
type: Boolean,
default: false
},
rowIndex: {
type: Number,
default: null
},
index: {
type: Number,
default: null
},
rowTogglerIcon: {
type: Array,
default: null
},
selected: {
type: Boolean,
default: false
},
editing: {
type: Boolean,
default: false
},
editingMeta: {
type: Object,
default: null
},
editMode: {
type: String,
default: null
},
responsiveLayout: {
type: String,
default: 'stack'
},
virtualScrollerContentProps: {
type: Object,
default: null
},
ariaControls: {
type: String,
default: null
},
name: {
type: String,
default: null
}
},
documentEditListener: null,
selfClick: false,
overlayEventListener: null,
data() {
return {
d_editing: this.editing,
styleObject: {},
isRowExpanded: false
};
},
watch: {
editing(newValue) {
this.d_editing = newValue;
},
'$data.d_editing': function (newValue) {
this.$emit('editing-meta-change', { data: this.rowData, field: this.field || `field_${this.index}`, index: this.rowIndex, editing: newValue });
}
},
mounted() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
if (this.d_editing && (this.editMode === 'cell' || (this.editMode === 'row' && this.columnProp('rowEditor')))) {
setTimeout(() => {
const focusableEl = DomHandler.getFirstFocusableElement(this.$el);
focusableEl && focusableEl.focus();
}, 1);
}
},
beforeUnmount() {
if (this.overlayEventListener) {
OverlayEventBus.off('overlay-click', this.overlayEventListener);
this.overlayEventListener = null;
}
},
methods: {
columnProp(prop) {
return ObjectUtils.getVNodeProp(this.column, prop);
},
resolveFieldData() {
return ObjectUtils.resolveFieldData(this.rowData, this.field);
},
toggleRow(event) {
this.isRowExpanded = !this.isRowExpanded;
this.$emit('row-toggle', {
originalEvent: event,
data: this.rowData
});
},
toggleRowWithRadio(event, index) {
this.$emit('radio-change', { originalEvent: event.originalEvent, index: index, data: event.data });
},
toggleRowWithCheckbox(event, index) {
this.$emit('checkbox-change', { originalEvent: event.originalEvent, index: index, data: event.data });
},
isEditable() {
return this.column.children && this.column.children.editor != null;
},
bindDocumentEditListener() {
if (!this.documentEditListener) {
this.documentEditListener = (event) => {
if (!this.selfClick) {
this.completeEdit(event, 'outside');
}
this.selfClick = false;
};
document.addEventListener('click', this.documentEditListener);
}
},
unbindDocumentEditListener() {
if (this.documentEditListener) {
document.removeEventListener('click', this.documentEditListener);
this.documentEditListener = null;
this.selfClick = false;
}
},
switchCellToViewMode() {
this.d_editing = false;
this.unbindDocumentEditListener();
OverlayEventBus.off('overlay-click', this.overlayEventListener);
this.overlayEventListener = null;
},
onClick(event) {
if (this.editMode === 'cell' && this.isEditable()) {
this.selfClick = true;
if (!this.d_editing) {
this.d_editing = true;
this.bindDocumentEditListener();
this.$emit('cell-edit-init', { originalEvent: event, data: this.rowData, field: this.field, index: this.rowIndex });
this.overlayEventListener = (e) => {
if (this.$el && this.$el.contains(e.target)) {
this.selfClick = true;
}
};
OverlayEventBus.on('overlay-click', this.overlayEventListener);
}
}
},
completeEdit(event, type) {
const completeEvent = {
originalEvent: event,
data: this.rowData,
newData: this.editingRowData,
value: this.rowData[this.field],
newValue: this.editingRowData[this.field],
field: this.field,
index: this.rowIndex,
type: type,
defaultPrevented: false,
preventDefault: function () {
this.defaultPrevented = true;
}
};
this.$emit('cell-edit-complete', completeEvent);
if (!completeEvent.defaultPrevented) {
this.switchCellToViewMode();
}
},
onKeyDown(event) {
if (this.editMode === 'cell') {
switch (event.code) {
case 'Enter':
this.completeEdit(event, 'enter');
break;
case 'Escape':
this.switchCellToViewMode();
this.$emit('cell-edit-cancel', { originalEvent: event, data: this.rowData, field: this.field, index: this.rowIndex });
break;
case 'Tab':
this.completeEdit(event, 'tab');
if (event.shiftKey) this.moveToPreviousCell(event);
else this.moveToNextCell(event);
break;
default:
break;
}
}
},
moveToPreviousCell(event) {
let currentCell = this.findCell(event.target);
let targetCell = this.findPreviousEditableColumn(currentCell);
if (targetCell) {
DomHandler.invokeElementMethod(targetCell, 'click');
event.preventDefault();
}
},
moveToNextCell(event) {
let currentCell = this.findCell(event.target);
let targetCell = this.findNextEditableColumn(currentCell);
if (targetCell) {
DomHandler.invokeElementMethod(targetCell, 'click');
event.preventDefault();
}
},
findCell(element) {
if (element) {
let cell = element;
while (cell && !DomHandler.hasClass(cell, 'p-cell-editing')) {
cell = cell.parentElement;
}
return cell;
} else {
return null;
}
},
findPreviousEditableColumn(cell) {
let prevCell = cell.previousElementSibling;
if (!prevCell) {
let previousRow = cell.parentElement.previousElementSibling;
if (previousRow) {
prevCell = previousRow.lastElementChild;
}
}
if (prevCell) {
if (DomHandler.hasClass(prevCell, 'p-editable-column')) return prevCell;
else return this.findPreviousEditableColumn(prevCell);
} else {
return null;
}
},
findNextEditableColumn(cell) {
let nextCell = cell.nextElementSibling;
if (!nextCell) {
let nextRow = cell.parentElement.nextElementSibling;
if (nextRow) {
nextCell = nextRow.firstElementChild;
}
}
if (nextCell) {
if (DomHandler.hasClass(nextCell, 'p-editable-column')) return nextCell;
else return this.findNextEditableColumn(nextCell);
} else {
return null;
}
},
isEditingCellValid() {
return DomHandler.find(this.$el, '.p-invalid').length === 0;
},
onRowEditInit(event) {
this.$emit('row-edit-init', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
},
onRowEditSave(event) {
this.$emit('row-edit-save', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
},
onRowEditCancel(event) {
this.$emit('row-edit-cancel', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
},
editorInitCallback(event) {
this.$emit('row-edit-init', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
},
editorSaveCallback(event) {
if (this.editMode === 'row') {
this.$emit('row-edit-save', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
} else {
this.completeEdit(event, 'enter');
}
},
editorCancelCallback(event) {
if (this.editMode === 'row') {
this.$emit('row-edit-cancel', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
} else {
this.switchCellToViewMode();
this.$emit('cell-edit-cancel', { originalEvent: event, data: this.rowData, field: this.field, index: this.rowIndex });
}
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let align = this.columnProp('alignFrozen');
if (align === 'right') {
let right = 0;
let next = this.$el.nextElementSibling;
if (next) {
right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right || 0);
}
this.styleObject.right = right + 'px';
} else {
let left = 0;
let prev = this.$el.previousElementSibling;
if (prev) {
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left || 0);
}
this.styleObject.left = left + 'px';
}
}
},
getVirtualScrollerProp(option) {
return this.virtualScrollerContentProps ? this.virtualScrollerContentProps[option] : null;
}
},
computed: {
editingRowData() {
return this.editingMeta[this.rowIndex] ? this.editingMeta[this.rowIndex].data : this.rowData;
},
field() {
return this.columnProp('field');
},
containerClass() {
return [
this.columnProp('bodyClass'),
this.columnProp('class'),
{
'p-selection-column': this.columnProp('selectionMode') != null,
'p-editable-column': this.isEditable(),
'p-cell-editing': this.d_editing,
'p-frozen-column': this.columnProp('frozen')
}
];
},
containerStyle() {
let bodyStyle = this.columnProp('bodyStyle');
let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject] : [columnStyle, bodyStyle];
},
loading() {
return this.getVirtualScrollerProp('loading');
},
loadingOptions() {
const getLoaderOptions = this.getVirtualScrollerProp('getLoaderOptions');
return (
getLoaderOptions &&
getLoaderOptions(this.rowIndex, {
cellIndex: this.index,
cellFirst: this.index === 0,
cellLast: this.index === this.getVirtualScrollerProp('columns').length - 1,
cellEven: this.index % 2 === 0,
cellOdd: this.index % 2 !== 0,
column: this.column,
field: this.field
})
);
},
expandButtonAriaLabel() {
return this.$primevue.config.locale.aria ? (this.isRowExpanded ? this.$primevue.config.locale.aria.expandRow : this.$primevue.config.locale.aria.collapseRow) : undefined;
},
initButtonAriaLabel() {
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.editRow : undefined;
},
saveButtonAriaLabel() {
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.saveEdit : undefined;
},
cancelButtonAriaLabel() {
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.cancelEdit : undefined;
}
},
components: {
DTRadioButton: RowRadioButton,
DTCheckbox: RowCheckbox
},
directives: {
ripple: Ripple
}
};
</script>

View file

@ -0,0 +1,599 @@
<template>
<div :class="containerClass">
<div v-if="display === 'row'" class="p-fluid p-column-filter-element" v-bind="filterInputProps">
<component :is="filterElement" :field="field" :filterModel="filters[field]" :filterCallback="filterCallback" />
</div>
<button
v-if="showMenuButton"
ref="icon"
type="button"
class="p-column-filter-menu-button p-link"
:aria-label="filterMenuButtonAriaLabel"
aria-haspopup="true"
:aria-expanded="overlayVisible"
:aria-controls="overlayId"
:class="{ 'p-column-filter-menu-button-open': overlayVisible, 'p-column-filter-menu-button-active': hasFilter() }"
@click="toggleMenu()"
@keydown="onToggleButtonKeyDown($event)"
>
<span class="pi pi-filter-icon pi-filter"></span>
</button>
<button v-if="showClearButton && display === 'row'" :class="{ 'p-hidden-space': !hasRowFilter() }" type="button" class="p-column-filter-clear-button p-link" @click="clearFilter()"><span class="pi pi-filter-slash"></span></button>
<Portal>
<transition name="p-connected-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave">
<div
v-if="overlayVisible"
:ref="overlayRef"
:id="overlayId"
v-focustrap="{ autoFocus: true }"
:aria-modal="overlayVisible"
role="dialog"
:class="overlayClass"
@keydown.escape="hide"
@click="onContentClick"
@mousedown="onContentMouseDown"
>
<component :is="filterHeaderTemplate" :field="field" :filterModel="filters[field]" :filterCallback="filterCallback" />
<template v-if="display === 'row'">
<ul class="p-column-filter-row-items">
<li
v-for="(matchMode, i) of matchModes"
:key="matchMode.label"
class="p-column-filter-row-item"
@click="onRowMatchModeChange(matchMode.value)"
@keydown="onRowMatchModeKeyDown($event)"
@keydown.enter.prevent="onRowMatchModeChange(matchMode.value)"
:class="{ 'p-highlight': isRowMatchModeSelected(matchMode.value) }"
:tabindex="i === 0 ? '0' : null"
>
{{ matchMode.label }}
</li>
<li class="p-column-filter-separator"></li>
<li class="p-column-filter-row-item" @click="clearFilter()" @keydown="onRowMatchModeKeyDown($event)" @keydown.enter="onRowClearItemClick()">{{ noFilterLabel }}</li>
</ul>
</template>
<template v-else>
<div v-if="isShowOperator" class="p-column-filter-operator">
<CFDropdown
:options="operatorOptions"
:modelValue="operator"
:aria-label="filterOperatorAriaLabel"
class="p-column-filter-operator-dropdown"
optionLabel="label"
optionValue="value"
@update:modelValue="onOperatorChange($event)"
></CFDropdown>
</div>
<div class="p-column-filter-constraints">
<div v-for="(fieldConstraint, i) of fieldConstraints" :key="i" class="p-column-filter-constraint">
<CFDropdown
v-if="isShowMatchModes"
:options="matchModes"
:modelValue="fieldConstraint.matchMode"
class="p-column-filter-matchmode-dropdown"
optionLabel="label"
optionValue="value"
:aria-label="filterConstraintAriaLabel"
@update:modelValue="onMenuMatchModeChange($event, i)"
></CFDropdown>
<component v-if="display === 'menu'" :is="filterElement" :field="field" :filterModel="fieldConstraint" :filterCallback="filterCallback" />
<div>
<CFButton
v-if="showRemoveIcon"
type="button"
icon="pi pi-trash"
class="p-column-filter-remove-button p-button-text p-button-danger p-button-sm"
@click="removeConstraint(i)"
:label="removeRuleButtonLabel"
></CFButton>
</div>
</div>
</div>
<div v-if="isShowAddConstraint" class="p-column-filter-add-rule">
<CFButton type="button" :label="addRuleButtonLabel" icon="pi pi-plus" class="p-column-filter-add-button p-button-text p-button-sm" @click="addConstraint()"></CFButton>
</div>
<div class="p-column-filter-buttonbar">
<CFButton v-if="!filterClearTemplate && showClearButton" type="button" class="p-button-outlined p-button-sm" :label="clearButtonLabel" @click="clearFilter"></CFButton>
<component v-else :is="filterClearTemplate" :field="field" :filterModel="filters[field]" :filterCallback="clearFilter" />
<template v-if="showApplyButton">
<CFButton v-if="!filterApplyTemplate" type="button" class="p-button-sm" :label="applyButtonLabel" @click="applyFilter()"></CFButton>
<component v-else :is="filterApplyTemplate" :field="field" :filterModel="filters[field]" :filterCallback="applyFilter" />
</template>
</div>
</template>
<component :is="filterFooterTemplate" :field="field" :filterModel="filters[field]" :filterCallback="filterCallback" />
</div>
</transition>
</Portal>
</div>
</template>
<script>
import { FilterOperator } from 'primevue/api';
import Button from 'primevue/button';
import Dropdown from 'primevue/dropdown';
import FocusTrap from 'primevue/focustrap';
import OverlayEventBus from 'primevue/overlayeventbus';
import Portal from 'primevue/portal';
import { ConnectedOverlayScrollHandler, DomHandler, UniqueComponentId, ZIndexUtils } from 'primevue/utils';
export default {
name: 'ColumnFilter',
emits: ['filter-change', 'filter-apply', 'operator-change', 'matchmode-change', 'constraint-add', 'constraint-remove', 'filter-clear', 'apply-click'],
props: {
field: {
type: String,
default: null
},
type: {
type: String,
default: 'text'
},
display: {
type: String,
default: null
},
showMenu: {
type: Boolean,
default: true
},
matchMode: {
type: String,
default: null
},
showOperator: {
type: Boolean,
default: true
},
showClearButton: {
type: Boolean,
default: true
},
showApplyButton: {
type: Boolean,
default: true
},
showMatchModes: {
type: Boolean,
default: true
},
showAddButton: {
type: Boolean,
default: true
},
matchModeOptions: {
type: Array,
default: null
},
maxConstraints: {
type: Number,
default: 2
},
filterElement: null,
filterHeaderTemplate: null,
filterFooterTemplate: null,
filterClearTemplate: null,
filterApplyTemplate: null,
filters: {
type: Object,
default: null
},
filtersStore: {
type: Object,
default: null
},
filterMenuClass: {
type: String,
default: null
},
filterMenuStyle: {
type: null,
default: null
},
filterInputProps: {
type: null,
default: null
}
},
data() {
return {
overlayVisible: false,
defaultMatchMode: null,
defaultOperator: null
};
},
overlay: null,
selfClick: false,
overlayEventListener: null,
beforeUnmount() {
if (this.overlayEventListener) {
OverlayEventBus.off('overlay-click', this.overlayEventListener);
this.overlayEventListener = null;
}
if (this.overlay) {
ZIndexUtils.clear(this.overlay);
this.onOverlayHide();
}
},
mounted() {
if (this.filters && this.filters[this.field]) {
let fieldFilters = this.filters[this.field];
if (fieldFilters.operator) {
this.defaultMatchMode = fieldFilters.constraints[0].matchMode;
this.defaultOperator = fieldFilters.operator;
} else {
this.defaultMatchMode = this.filters[this.field].matchMode;
}
}
},
methods: {
clearFilter() {
let _filters = { ...this.filters };
if (_filters[this.field].operator) {
_filters[this.field].constraints.splice(1);
_filters[this.field].operator = this.defaultOperator;
_filters[this.field].constraints[0] = { value: null, matchMode: this.defaultMatchMode };
} else {
_filters[this.field].value = null;
_filters[this.field].matchMode = this.defaultMatchMode;
}
this.$emit('filter-clear');
this.$emit('filter-change', _filters);
this.$emit('filter-apply');
this.hide();
},
applyFilter() {
this.$emit('apply-click', { field: this.field, constraints: this.filters[this.field] });
this.$emit('filter-apply');
this.hide();
},
hasFilter() {
if (this.filtersStore) {
let fieldFilter = this.filtersStore[this.field];
if (fieldFilter) {
if (fieldFilter.operator) return !this.isFilterBlank(fieldFilter.constraints[0].value);
else return !this.isFilterBlank(fieldFilter.value);
}
}
return false;
},
hasRowFilter() {
return this.filters[this.field] && !this.isFilterBlank(this.filters[this.field].value);
},
isFilterBlank(filter) {
if (filter !== null && filter !== undefined) {
if ((typeof filter === 'string' && filter.trim().length == 0) || (filter instanceof Array && filter.length == 0)) return true;
else return false;
}
return true;
},
toggleMenu() {
this.overlayVisible = !this.overlayVisible;
},
onToggleButtonKeyDown(event) {
switch (event.code) {
case 'Enter':
case 'Space':
this.toggleMenu();
event.preventDefault();
break;
case 'Escape':
this.overlayVisible = false;
break;
}
},
onRowMatchModeChange(matchMode) {
let _filters = { ...this.filters };
_filters[this.field].matchMode = matchMode;
this.$emit('matchmode-change', { field: this.field, matchMode: matchMode });
this.$emit('filter-change', _filters);
this.$emit('filter-apply');
this.hide();
},
onRowMatchModeKeyDown(event) {
let item = event.target;
switch (event.code) {
case 'ArrowDown':
var nextItem = this.findNextItem(item);
if (nextItem) {
item.removeAttribute('tabindex');
nextItem.tabIndex = '0';
nextItem.focus();
}
event.preventDefault();
break;
case 'ArrowUp':
var prevItem = this.findPrevItem(item);
if (prevItem) {
item.removeAttribute('tabindex');
prevItem.tabIndex = '0';
prevItem.focus();
}
event.preventDefault();
break;
}
},
isRowMatchModeSelected(matchMode) {
return this.filters[this.field].matchMode === matchMode;
},
onOperatorChange(value) {
let _filters = { ...this.filters };
_filters[this.field].operator = value;
this.$emit('filter-change', _filters);
this.$emit('operator-change', { field: this.field, operator: value });
if (!this.showApplyButton) {
this.$emit('filter-apply');
}
},
onMenuMatchModeChange(value, index) {
let _filters = { ...this.filters };
_filters[this.field].constraints[index].matchMode = value;
this.$emit('matchmode-change', { field: this.field, matchMode: value, index: index });
if (!this.showApplyButton) {
this.$emit('filter-apply');
}
},
addConstraint() {
let _filters = { ...this.filters };
let newConstraint = { value: null, matchMode: this.defaultMatchMode };
_filters[this.field].constraints.push(newConstraint);
this.$emit('constraint-add', { field: this.field, constraing: newConstraint });
this.$emit('filter-change', _filters);
if (!this.showApplyButton) {
this.$emit('filter-apply');
}
},
removeConstraint(index) {
let _filters = { ...this.filters };
let removedConstraint = _filters[this.field].constraints.splice(index, 1);
this.$emit('constraint-remove', { field: this.field, constraing: removedConstraint });
this.$emit('filter-change', _filters);
if (!this.showApplyButton) {
this.$emit('filter-apply');
}
},
filterCallback() {
this.$emit('filter-apply');
},
findNextItem(item) {
let nextItem = item.nextElementSibling;
if (nextItem) return DomHandler.hasClass(nextItem, 'p-column-filter-separator') ? this.findNextItem(nextItem) : nextItem;
else return item.parentElement.firstElementChild;
},
findPrevItem(item) {
let prevItem = item.previousElementSibling;
if (prevItem) return DomHandler.hasClass(prevItem, 'p-column-filter-separator') ? this.findPrevItem(prevItem) : prevItem;
else return item.parentElement.lastElementChild;
},
hide() {
this.overlayVisible = false;
DomHandler.focus(this.$refs.icon);
},
onContentClick(event) {
this.selfClick = true;
OverlayEventBus.emit('overlay-click', {
originalEvent: event,
target: this.overlay
});
},
onContentMouseDown() {
this.selfClick = true;
},
onOverlayEnter(el) {
if (this.filterMenuStyle) {
DomHandler.applyStyle(this.overlay, this.filterMenuStyle);
}
ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay);
DomHandler.absolutePosition(this.overlay, this.$refs.icon);
this.bindOutsideClickListener();
this.bindScrollListener();
this.bindResizeListener();
this.overlayEventListener = (e) => {
if (!this.isOutsideClicked(e.target)) {
this.selfClick = true;
}
};
OverlayEventBus.on('overlay-click', this.overlayEventListener);
},
onOverlayLeave() {
this.onOverlayHide();
},
onOverlayAfterLeave(el) {
ZIndexUtils.clear(el);
},
onOverlayHide() {
this.unbindOutsideClickListener();
this.unbindResizeListener();
this.unbindScrollListener();
this.overlay = null;
OverlayEventBus.off('overlay-click', this.overlayEventListener);
this.overlayEventListener = null;
},
overlayRef(el) {
this.overlay = el;
},
isOutsideClicked(target) {
return !this.isTargetClicked(target) && this.overlay && !(this.overlay.isSameNode(target) || this.overlay.contains(target));
},
isTargetClicked(target) {
return this.$refs.icon && (this.$refs.icon.isSameNode(target) || this.$refs.icon.contains(target));
},
bindOutsideClickListener() {
if (!this.outsideClickListener) {
this.outsideClickListener = (event) => {
if (this.overlayVisible && !this.selfClick && this.isOutsideClicked(event.target)) {
this.overlayVisible = false;
}
this.selfClick = false;
};
document.addEventListener('click', this.outsideClickListener);
}
},
unbindOutsideClickListener() {
if (this.outsideClickListener) {
document.removeEventListener('click', this.outsideClickListener);
this.outsideClickListener = null;
this.selfClick = false;
}
},
bindScrollListener() {
if (!this.scrollHandler) {
this.scrollHandler = new ConnectedOverlayScrollHandler(this.$refs.icon, () => {
if (this.overlayVisible) {
this.hide();
}
});
}
this.scrollHandler.bindScrollListener();
},
unbindScrollListener() {
if (this.scrollHandler) {
this.scrollHandler.unbindScrollListener();
}
},
bindResizeListener() {
if (!this.resizeListener) {
this.resizeListener = () => {
if (this.overlayVisible && !DomHandler.isTouchDevice()) {
this.hide();
}
};
window.addEventListener('resize', this.resizeListener);
}
},
unbindResizeListener() {
if (this.resizeListener) {
window.removeEventListener('resize', this.resizeListener);
this.resizeListener = null;
}
}
},
computed: {
containerClass() {
return [
'p-column-filter p-fluid',
{
'p-column-filter-row': this.display === 'row',
'p-column-filter-menu': this.display === 'menu'
}
];
},
overlayClass() {
return [
this.filterMenuClass,
{
'p-column-filter-overlay p-component p-fluid': true,
'p-column-filter-overlay-menu': this.display === 'menu',
'p-input-filled': this.$primevue.config.inputStyle === 'filled',
'p-ripple-disabled': this.$primevue.config.ripple === false
}
];
},
showMenuButton() {
return this.showMenu && (this.display === 'row' ? this.type !== 'boolean' : true);
},
overlayId() {
return UniqueComponentId();
},
matchModes() {
return (
this.matchModeOptions ||
this.$primevue.config.filterMatchModeOptions[this.type].map((key) => {
return { label: this.$primevue.config.locale[key], value: key };
})
);
},
isShowMatchModes() {
return this.type !== 'boolean' && this.showMatchModes && this.matchModes;
},
operatorOptions() {
return [
{ label: this.$primevue.config.locale.matchAll, value: FilterOperator.AND },
{ label: this.$primevue.config.locale.matchAny, value: FilterOperator.OR }
];
},
noFilterLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.noFilter : undefined;
},
isShowOperator() {
return this.showOperator && this.filters[this.field].operator;
},
operator() {
return this.filters[this.field].operator;
},
fieldConstraints() {
return this.filters[this.field].constraints || [this.filters[this.field]];
},
showRemoveIcon() {
return this.fieldConstraints.length > 1;
},
removeRuleButtonLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.removeRule : undefined;
},
addRuleButtonLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.addRule : undefined;
},
isShowAddConstraint() {
return this.showAddButton && this.filters[this.field].operator && this.fieldConstraints && this.fieldConstraints.length < this.maxConstraints;
},
clearButtonLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.clear : undefined;
},
applyButtonLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.apply : undefined;
},
filterMenuButtonAriaLabel() {
return this.$primevue.config.locale ? (this.overlayVisible ? this.$primevue.config.locale.showFilterMenu : this.$primevue.config.locale.hideFilterMenu) : undefined;
},
filterOperatorAriaLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.filterOperator : undefined;
},
filterConstraintAriaLabel() {
return this.$primevue.config.locale ? this.$primevue.config.locale.filterConstraint : undefined;
}
},
components: {
CFDropdown: Dropdown,
CFButton: Button,
Portal: Portal
},
directives: {
focustrap: FocusTrap
}
};
</script>

1126
components/lib/datatable/DataTable.d.ts vendored Executable file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
<template>
<td :style="containerStyle" :class="containerClass" role="cell" :colspan="columnProp('colspan')" :rowspan="columnProp('rowspan')">
<component v-if="column.children && column.children.footer" :is="column.children.footer" :column="column" />
{{ columnProp('footer') }}
</td>
</template>
<script>
import { DomHandler, ObjectUtils } from 'primevue/utils';
export default {
name: 'FooterCell',
props: {
column: {
type: null,
default: null
}
},
data() {
return {
styleObject: {}
};
},
mounted() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
methods: {
columnProp(prop) {
return ObjectUtils.getVNodeProp(this.column, prop);
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let align = this.columnProp('alignFrozen');
if (align === 'right') {
let right = 0;
let next = this.$el.nextElementSibling;
if (next) {
right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right || 0);
}
this.styleObject.right = right + 'px';
} else {
let left = 0;
let prev = this.$el.previousElementSibling;
if (prev) {
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left || 0);
}
this.styleObject.left = left + 'px';
}
}
}
},
computed: {
containerClass() {
return [
this.columnProp('footerClass'),
this.columnProp('class'),
{
'p-frozen-column': this.columnProp('frozen')
}
];
},
containerStyle() {
let bodyStyle = this.columnProp('footerStyle');
let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, bodyStyle, this.styleObject] : [columnStyle, bodyStyle];
}
}
};
</script>

View file

@ -0,0 +1,312 @@
<template>
<th
:style="containerStyle"
:class="containerClass"
:tabindex="columnProp('sortable') ? '0' : null"
role="columnheader"
:colspan="columnProp('colspan')"
:rowspan="columnProp('rowspan')"
:aria-sort="ariaSort"
@click="onClick"
@keydown="onKeyDown"
@mousedown="onMouseDown"
@dragstart="onDragStart"
@dragover="onDragOver"
@dragleave="onDragLeave"
@drop="onDrop"
>
<span v-if="resizableColumns && !columnProp('frozen')" class="p-column-resizer" @mousedown="onResizeStart"></span>
<div class="p-column-header-content">
<component v-if="column.children && column.children.header" :is="column.children.header" :column="column" />
<span v-if="columnProp('header')" class="p-column-title">{{ columnProp('header') }}</span>
<span v-if="columnProp('sortable')" :class="sortableColumnIcon"></span>
<span v-if="isMultiSorted()" class="p-sortable-column-badge">{{ getBadgeValue() }}</span>
<DTHeaderCheckbox v-if="columnProp('selectionMode') === 'multiple' && filterDisplay !== 'row'" :checked="allRowsSelected" @change="onHeaderCheckboxChange" :disabled="empty" />
<DTColumnFilter
v-if="filterDisplay === 'menu' && column.children && column.children.filter"
:field="columnProp('filterField') || columnProp('field')"
:type="columnProp('dataType')"
display="menu"
:showMenu="columnProp('showFilterMenu')"
:filterElement="column.children && column.children.filter"
:filterHeaderTemplate="column.children && column.children.filterheader"
:filterFooterTemplate="column.children && column.children.filterfooter"
:filterClearTemplate="column.children && column.children.filterclear"
:filterApplyTemplate="column.children && column.children.filterapply"
:filters="filters"
:filtersStore="filtersStore"
:filterInputProps="filterInputProps"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
:filterMenuStyle="columnProp('filterMenuStyle')"
:filterMenuClass="columnProp('filterMenuClass')"
:showOperator="columnProp('showFilterOperator')"
:showClearButton="columnProp('showClearButton')"
:showApplyButton="columnProp('showApplyButton')"
:showMatchModes="columnProp('showFilterMatchModes')"
:showAddButton="columnProp('showAddButton')"
:matchModeOptions="columnProp('filterMatchModeOptions')"
:maxConstraints="columnProp('maxConstraints')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
/>
</div>
</th>
</template>
<script>
import { DomHandler, ObjectUtils } from 'primevue/utils';
import ColumnFilter from './ColumnFilter.vue';
import HeaderCheckbox from './HeaderCheckbox.vue';
export default {
name: 'HeaderCell',
emits: [
'column-click',
'column-mousedown',
'column-dragstart',
'column-dragover',
'column-dragleave',
'column-drop',
'column-resizestart',
'checkbox-change',
'filter-change',
'filter-apply',
'operator-change',
'matchmode-change',
'constraint-add',
'constraint-remove',
'filter-clear',
'apply-click'
],
props: {
column: {
type: Object,
default: null
},
resizableColumns: {
type: Boolean,
default: false
},
groupRowsBy: {
type: [Array, String, Function],
default: null
},
sortMode: {
type: String,
default: 'single'
},
groupRowSortField: {
type: [String, Function],
default: null
},
sortField: {
type: [String, Function],
default: null
},
sortOrder: {
type: Number,
default: null
},
multiSortMeta: {
type: Array,
default: null
},
allRowsSelected: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
},
filterDisplay: {
type: String,
default: null
},
filters: {
type: Object,
default: null
},
filtersStore: {
type: Object,
default: null
},
filterColumn: {
type: Boolean,
default: false
},
reorderableColumns: {
type: Boolean,
default: false
},
filterInputProps: {
type: null,
default: null
}
},
data() {
return {
styleObject: {}
};
},
mounted() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
methods: {
columnProp(prop) {
return ObjectUtils.getVNodeProp(this.column, prop);
},
onClick(event) {
this.$emit('column-click', { originalEvent: event, column: this.column });
},
onKeyDown(event) {
if ((event.code === 'Enter' || event.code === 'Space') && event.currentTarget.nodeName === 'TH' && DomHandler.hasClass(event.currentTarget, 'p-sortable-column')) {
this.$emit('column-click', { originalEvent: event, column: this.column });
event.preventDefault();
}
},
onMouseDown(event) {
this.$emit('column-mousedown', { originalEvent: event, column: this.column });
},
onDragStart(event) {
this.$emit('column-dragstart', event);
},
onDragOver(event) {
this.$emit('column-dragover', event);
},
onDragLeave(event) {
this.$emit('column-dragleave', event);
},
onDrop(event) {
this.$emit('column-drop', event);
},
onResizeStart(event) {
this.$emit('column-resizestart', event);
},
getMultiSortMetaIndex() {
return this.multiSortMeta.findIndex((meta) => meta.field === this.columnProp('field') || meta.field === this.columnProp('sortField'));
},
getBadgeValue() {
let index = this.getMultiSortMetaIndex();
return this.groupRowsBy && this.groupRowsBy === this.groupRowSortField && index > -1 ? index : index + 1;
},
isMultiSorted() {
return this.sortMode === 'multiple' && this.columnProp('sortable') && this.getMultiSortMetaIndex() > -1;
},
isColumnSorted() {
return this.sortMode === 'single' ? this.sortField && (this.sortField === this.columnProp('field') || this.sortField === this.columnProp('sortField')) : this.isMultiSorted();
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let align = this.columnProp('alignFrozen');
if (align === 'right') {
let right = 0;
let next = this.$el.nextElementSibling;
if (next) {
right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right || 0);
}
this.styleObject.right = right + 'px';
} else {
let left = 0;
let prev = this.$el.previousElementSibling;
if (prev) {
left = DomHandler.getOuterWidth(prev) + parseFloat(prev.style.left || 0);
}
this.styleObject.left = left + 'px';
}
let filterRow = this.$el.parentElement.nextElementSibling;
if (filterRow) {
let index = DomHandler.index(this.$el);
filterRow.children[index].style.left = this.styleObject.left;
filterRow.children[index].style.right = this.styleObject.right;
}
}
},
onHeaderCheckboxChange(event) {
this.$emit('checkbox-change', event);
}
},
computed: {
containerClass() {
return [
this.filterColumn ? this.columnProp('filterHeaderClass') : this.columnProp('headerClass'),
this.columnProp('class'),
{
'p-sortable-column': this.columnProp('sortable'),
'p-resizable-column': this.resizableColumns,
'p-highlight': this.isColumnSorted(),
'p-filter-column': this.filterColumn,
'p-frozen-column': this.columnProp('frozen'),
'p-reorderable-column': this.reorderableColumns
}
];
},
containerStyle() {
let headerStyle = this.filterColumn ? this.columnProp('filterHeaderStyle') : this.columnProp('headerStyle');
let columnStyle = this.columnProp('style');
return this.columnProp('frozen') ? [columnStyle, headerStyle, this.styleObject] : [columnStyle, headerStyle];
},
sortableColumnIcon() {
let sorted = false;
let sortOrder = null;
if (this.sortMode === 'single') {
sorted = this.sortField && (this.sortField === this.columnProp('field') || this.sortField === this.columnProp('sortField'));
sortOrder = sorted ? this.sortOrder : 0;
} else if (this.sortMode === 'multiple') {
let metaIndex = this.getMultiSortMetaIndex();
if (metaIndex > -1) {
sorted = true;
sortOrder = this.multiSortMeta[metaIndex].order;
}
}
return [
'p-sortable-column-icon pi pi-fw',
{
'pi-sort-alt': !sorted,
'pi-sort-amount-up-alt': sorted && sortOrder > 0,
'pi-sort-amount-down': sorted && sortOrder < 0
}
];
},
ariaSort() {
if (this.columnProp('sortable')) {
const sortIcon = this.sortableColumnIcon;
if (sortIcon[1]['pi-sort-amount-down']) return 'descending';
else if (sortIcon[1]['pi-sort-amount-up-alt']) return 'ascending';
else return 'none';
} else {
return null;
}
}
},
components: {
DTHeaderCheckbox: HeaderCheckbox,
DTColumnFilter: ColumnFilter
}
};
</script>

View file

@ -0,0 +1,51 @@
<template>
<div :class="['p-checkbox p-component', { 'p-checkbox-focused': focused, 'p-disabled': disabled }]" @click="onClick" @keydown.space.prevent="onClick">
<div class="p-hidden-accessible">
<input ref="input" type="checkbox" :checked="checked" :disabled="disabled" :tabindex="disabled ? null : '0'" :aria-label="headerCheckboxAriaLabel" @focus="onFocus($event)" @blur="onBlur($event)" />
</div>
<div ref="box" :class="['p-checkbox-box p-component', { 'p-highlight': checked, 'p-disabled': disabled, 'p-focus': focused }]">
<span :class="['p-checkbox-icon', { 'pi pi-check': checked }]"></span>
</div>
</div>
</template>
<script>
import { DomHandler } from 'primevue/utils';
export default {
name: 'HeaderCheckbox',
emits: ['change'],
props: {
checked: null,
disabled: null
},
data() {
return {
focused: false
};
},
methods: {
onClick(event) {
if (!this.disabled) {
this.$emit('change', {
originalEvent: event,
checked: !this.checked
});
DomHandler.focus(this.$refs.input);
}
},
onFocus() {
this.focused = true;
},
onBlur() {
this.focused = false;
}
},
computed: {
headerCheckboxAriaLabel() {
return this.$primevue.config.locale.aria ? (this.checked ? this.$primevue.config.locale.aria.selectAll : this.$primevue.config.locale.aria.unselectAll) : undefined;
}
}
};
</script>

View file

@ -0,0 +1,65 @@
<template>
<div :class="['p-checkbox p-component', { 'p-checkbox-focused': focused }]" @click="onClick">
<div class="p-hidden-accessible">
<input ref="input" type="checkbox" :checked="checked" :disabled="$attrs.disabled" :tabindex="$attrs.disabled ? null : '0'" :aria-label="checkboxAriaLabel" @focus="onFocus($event)" @blur="onBlur($event)" @keydown="onKeydown" />
</div>
<div ref="box" :class="['p-checkbox-box p-component', { 'p-highlight': checked, 'p-disabled': $attrs.disabled, 'p-focus': focused }]">
<span :class="['p-checkbox-icon', { 'pi pi-check': checked }]"></span>
</div>
</div>
</template>
<script>
import { DomHandler } from 'primevue/utils';
export default {
name: 'RowCheckbox',
emits: ['change'],
props: {
value: null,
checked: null
},
data() {
return {
focused: false
};
},
methods: {
onClick(event) {
if (!this.$attrs.disabled) {
this.$emit('change', {
originalEvent: event,
data: this.value
});
DomHandler.focus(this.$refs.input);
}
event.preventDefault();
},
onFocus() {
this.focused = true;
},
onBlur() {
this.focused = false;
},
onKeydown(event) {
switch (event.code) {
case 'Space': {
this.onClick(event);
break;
}
default:
break;
}
}
},
computed: {
checkboxAriaLabel() {
return this.$primevue.config.locale.aria ? (this.checked ? this.$primevue.config.locale.aria.selectRow : this.$primevue.config.locale.aria.unselectRow) : undefined;
}
}
};
</script>

View file

@ -0,0 +1,50 @@
<template>
<div :class="['p-radiobutton p-component', { 'p-radiobutton-focused': focused }]" @click="onClick">
<div class="p-hidden-accessible">
<input ref="input" type="radio" :checked="checked" :disabled="$attrs.disabled" :name="name" tabindex="0" @focus="onFocus($event)" @blur="onBlur($event)" @keydown.space.prevent="onClick" />
</div>
<div ref="box" :class="['p-radiobutton-box p-component', { 'p-highlight': checked, 'p-disabled': $attrs.disabled, 'p-focus': focused }]">
<div class="p-radiobutton-icon"></div>
</div>
</div>
</template>
<script>
import { DomHandler } from 'primevue/utils';
export default {
name: 'RowRadioButton',
inheritAttrs: false,
emits: ['change'],
props: {
value: null,
checked: null,
name: null
},
data() {
return {
focused: false
};
},
methods: {
onClick(event) {
if (!this.disabled) {
if (!this.checked) {
this.$emit('change', {
originalEvent: event,
data: this.value
});
DomHandler.focus(this.$refs.input);
}
}
},
onFocus() {
this.focused = true;
},
onBlur() {
this.focused = false;
}
}
};
</script>

View file

@ -0,0 +1,587 @@
<template>
<tbody :ref="bodyRef" class="p-datatable-tbody" role="rowgroup" :style="bodyStyle">
<template v-if="!empty">
<template v-for="(rowData, index) of value" :key="getRowKey(rowData, getRowIndex(index)) + '_subheader'">
<tr v-if="templates['groupheader'] && rowGroupMode === 'subheader' && shouldRenderRowGroupHeader(value, rowData, getRowIndex(index))" class="p-rowgroup-header" :style="rowGroupHeaderStyle" role="row">
<td :colspan="columnsLength - 1">
<button v-if="expandableRowGroups" class="p-row-toggler p-link" @click="onRowGroupToggle($event, rowData)" type="button">
<span :class="rowGroupTogglerIcon(rowData)"></span>
</button>
<component :is="templates['groupheader']" :data="rowData" :index="getRowIndex(index)" />
</td>
</tr>
<tr
v-if="expandableRowGroups ? isRowGroupExpanded(rowData) : true"
:key="getRowKey(rowData, getRowIndex(index))"
:class="getRowClass(rowData)"
:style="getRowStyle(rowData)"
:tabindex="setRowTabindex(index)"
role="row"
:aria-selected="selectionMode ? isSelected(rowData) : null"
@click="onRowClick($event, rowData, getRowIndex(index))"
@dblclick="onRowDblClick($event, rowData, getRowIndex(index))"
@contextmenu="onRowRightClick($event, rowData, getRowIndex(index))"
@touchend="onRowTouchEnd($event)"
@keydown="onRowKeyDown($event, rowData, getRowIndex(index))"
@mousedown="onRowMouseDown($event)"
@dragstart="onRowDragStart($event, getRowIndex(index))"
@dragover="onRowDragOver($event, getRowIndex(index))"
@dragleave="onRowDragLeave($event)"
@dragend="onRowDragEnd($event)"
@drop="onRowDrop($event)"
>
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
<DTBodyCell
v-if="shouldRenderBodyCell(value, col, getRowIndex(index))"
:rowData="rowData"
:column="col"
:rowIndex="getRowIndex(index)"
:index="i"
:selected="isSelected(rowData)"
:rowTogglerIcon="columnProp(col, 'expander') ? rowTogglerIcon(rowData) : null"
:frozenRow="frozenRow"
:rowspan="rowGroupMode === 'rowspan' ? calculateRowGroupSize(value, col, getRowIndex(index)) : null"
:editMode="editMode"
:editing="editMode === 'row' && isRowEditing(rowData)"
:editingMeta="editingMeta"
:responsiveLayout="responsiveLayout"
:virtualScrollerContentProps="virtualScrollerContentProps"
:ariaControls="expandedRowId + '_' + index + '_expansion'"
:name="nameAttributeSelector"
@radio-change="onRadioChange($event)"
@checkbox-change="onCheckboxChange($event)"
@row-toggle="onRowToggle($event)"
@cell-edit-init="onCellEditInit($event)"
@cell-edit-complete="onCellEditComplete($event)"
@cell-edit-cancel="onCellEditCancel($event)"
@row-edit-init="onRowEditInit($event)"
@row-edit-save="onRowEditSave($event)"
@row-edit-cancel="onRowEditCancel($event)"
@editing-meta-change="onEditingMetaChange"
/>
</template>
</tr>
<tr v-if="templates['expansion'] && expandedRows && isRowExpanded(rowData)" :key="getRowKey(rowData, getRowIndex(index)) + '_expansion'" :id="expandedRowId + '_' + index + '_expansion'" class="p-datatable-row-expansion" role="row">
<td :colspan="columnsLength">
<component :is="templates['expansion']" :data="rowData" :index="getRowIndex(index)" />
</td>
</tr>
<tr v-if="templates['groupfooter'] && rowGroupMode === 'subheader' && shouldRenderRowGroupFooter(value, rowData, getRowIndex(index))" :key="getRowKey(rowData, getRowIndex(index)) + '_subfooter'" class="p-rowgroup-footer" role="row">
<td :colspan="columnsLength - 1">
<component :is="templates['groupfooter']" :data="rowData" :index="getRowIndex(index)" />
</td>
</tr>
</template>
</template>
<tr v-else class="p-datatable-emptymessage" role="row">
<td :colspan="columnsLength">
<component v-if="templates.empty" :is="templates.empty" />
</td>
</tr>
</tbody>
</template>
<script>
import { DomHandler, ObjectUtils, UniqueComponentId } from 'primevue/utils';
import BodyCell from './BodyCell.vue';
export default {
name: 'TableBody',
emits: [
'rowgroup-toggle',
'row-click',
'row-dblclick',
'row-rightclick',
'row-touchend',
'row-keydown',
'row-mousedown',
'row-dragstart',
'row-dragover',
'row-dragleave',
'row-dragend',
'row-drop',
'row-toggle',
'radio-change',
'checkbox-change',
'cell-edit-init',
'cell-edit-complete',
'cell-edit-cancel',
'row-edit-init',
'row-edit-save',
'row-edit-cancel',
'editing-meta-change'
],
props: {
value: {
type: Array,
default: null
},
columns: {
type: null,
default: null
},
frozenRow: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
},
rowGroupMode: {
type: String,
default: null
},
groupRowsBy: {
type: [Array, String, Function],
default: null
},
expandableRowGroups: {
type: Boolean,
default: false
},
expandedRowGroups: {
type: Array,
default: null
},
dataKey: {
type: String,
default: null
},
expandedRowIcon: {
type: String,
default: null
},
collapsedRowIcon: {
type: String,
default: null
},
expandedRows: {
type: Array,
default: null
},
expandedRowKeys: {
type: null,
default: null
},
selection: {
type: [Array, Object],
default: null
},
selectionKeys: {
type: null,
default: null
},
selectionMode: {
type: String,
default: null
},
contextMenu: {
type: Boolean,
default: false
},
contextMenuSelection: {
type: Object,
default: null
},
rowClass: {
type: null,
default: null
},
rowStyle: {
type: null,
default: null
},
editMode: {
type: String,
default: null
},
compareSelectionBy: {
type: String,
default: 'deepEquals'
},
editingRows: {
type: Array,
default: null
},
editingRowKeys: {
type: null,
default: null
},
editingMeta: {
type: Object,
default: null
},
templates: {
type: null,
default: null
},
scrollable: {
type: Boolean,
default: false
},
responsiveLayout: {
type: String,
default: 'stack'
},
virtualScrollerContentProps: {
type: Object,
default: null
},
isVirtualScrollerDisabled: {
type: Boolean,
default: false
}
},
data() {
return {
rowGroupHeaderStyleObject: {},
tabindexArray: [],
isARowSelected: false
};
},
mounted() {
if (this.frozenRow) {
this.updateFrozenRowStickyPosition();
}
if (this.scrollable && this.rowGroupMode === 'subheader') {
this.updateFrozenRowGroupHeaderStickyPosition();
}
},
updated() {
if (this.frozenRow) {
this.updateFrozenRowStickyPosition();
}
if (this.scrollable && this.rowGroupMode === 'subheader') {
this.updateFrozenRowGroupHeaderStickyPosition();
}
},
methods: {
columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop);
},
shouldRenderRowGroupHeader(value, rowData, i) {
let currentRowFieldData = ObjectUtils.resolveFieldData(rowData, this.groupRowsBy);
let prevRowData = value[i - 1];
if (prevRowData) {
let previousRowFieldData = ObjectUtils.resolveFieldData(prevRowData, this.groupRowsBy);
return currentRowFieldData !== previousRowFieldData;
} else {
return true;
}
},
getRowKey(rowData, index) {
return this.dataKey ? ObjectUtils.resolveFieldData(rowData, this.dataKey) : index;
},
getRowIndex(index) {
const getItemOptions = this.getVirtualScrollerProp('getItemOptions');
return getItemOptions ? getItemOptions(index).index : index;
},
getRowStyle(rowData) {
if (this.rowStyle) {
return this.rowStyle(rowData);
}
},
getRowClass(rowData) {
let rowStyleClass = [];
if (this.selectionMode) {
rowStyleClass.push('p-selectable-row');
}
if (this.selection) {
rowStyleClass.push({
'p-highlight': this.isSelected(rowData)
});
}
if (this.contextMenuSelection) {
rowStyleClass.push({
'p-highlight-contextmenu': this.isSelectedWithContextMenu(rowData)
});
}
if (this.rowClass) {
let rowClassValue = this.rowClass(rowData);
if (rowClassValue) {
rowStyleClass.push(rowClassValue);
}
}
return rowStyleClass;
},
shouldRenderRowGroupFooter(value, rowData, i) {
if (this.expandableRowGroups && !this.isRowGroupExpanded(rowData)) {
return false;
} else {
let currentRowFieldData = ObjectUtils.resolveFieldData(rowData, this.groupRowsBy);
let nextRowData = value[i + 1];
if (nextRowData) {
let nextRowFieldData = ObjectUtils.resolveFieldData(nextRowData, this.groupRowsBy);
return currentRowFieldData !== nextRowFieldData;
} else {
return true;
}
}
},
shouldRenderBodyCell(value, column, i) {
if (this.rowGroupMode) {
if (this.rowGroupMode === 'subheader') {
return this.groupRowsBy !== this.columnProp(column, 'field');
} else if (this.rowGroupMode === 'rowspan') {
if (this.isGrouped(column)) {
let prevRowData = value[i - 1];
if (prevRowData) {
let currentRowFieldData = ObjectUtils.resolveFieldData(value[i], this.columnProp(column, 'field'));
let previousRowFieldData = ObjectUtils.resolveFieldData(prevRowData, this.columnProp(column, 'field'));
return currentRowFieldData !== previousRowFieldData;
} else {
return true;
}
} else {
return true;
}
}
} else {
return !this.columnProp(column, 'hidden');
}
},
calculateRowGroupSize(value, column, index) {
if (this.isGrouped(column)) {
let currentRowFieldData = ObjectUtils.resolveFieldData(value[index], this.columnProp(column, 'field'));
let nextRowFieldData = currentRowFieldData;
let groupRowSpan = 0;
while (currentRowFieldData === nextRowFieldData) {
groupRowSpan++;
let nextRowData = value[++index];
if (nextRowData) {
nextRowFieldData = ObjectUtils.resolveFieldData(nextRowData, this.columnProp(column, 'field'));
} else {
break;
}
}
return groupRowSpan === 1 ? null : groupRowSpan;
} else {
return null;
}
},
rowTogglerIcon(rowData) {
const icon = this.isRowExpanded(rowData) ? this.expandedRowIcon : this.collapsedRowIcon;
return ['p-row-toggler-icon pi', icon];
},
rowGroupTogglerIcon(rowData) {
const icon = this.isRowGroupExpanded(rowData) ? this.expandedRowIcon : this.collapsedRowIcon;
return ['p-row-toggler-icon pi', icon];
},
isGrouped(column) {
if (this.groupRowsBy && this.columnProp(column, 'field')) {
if (Array.isArray(this.groupRowsBy)) return this.groupRowsBy.indexOf(column.props.field) > -1;
else return this.groupRowsBy === column.props.field;
} else {
return false;
}
},
isRowEditing(rowData) {
if (rowData && this.editingRows) {
if (this.dataKey) return this.editingRowKeys ? this.editingRowKeys[ObjectUtils.resolveFieldData(rowData, this.dataKey)] !== undefined : false;
else return this.findIndex(rowData, this.editingRows) > -1;
}
return false;
},
isRowExpanded(rowData) {
if (rowData && this.expandedRows) {
if (this.dataKey) return this.expandedRowKeys ? this.expandedRowKeys[ObjectUtils.resolveFieldData(rowData, this.dataKey)] !== undefined : false;
else return this.findIndex(rowData, this.expandedRows) > -1;
}
return false;
},
isRowGroupExpanded(rowData) {
if (this.expandableRowGroups && this.expandedRowGroups) {
let groupFieldValue = ObjectUtils.resolveFieldData(rowData, this.groupRowsBy);
return this.expandedRowGroups.indexOf(groupFieldValue) > -1;
}
return false;
},
isSelected(rowData) {
if (rowData && this.selection) {
if (this.dataKey) {
return this.selectionKeys ? this.selectionKeys[ObjectUtils.resolveFieldData(rowData, this.dataKey)] !== undefined : false;
} else {
if (this.selection instanceof Array) return this.findIndexInSelection(rowData) > -1;
else return this.equals(rowData, this.selection);
}
}
return false;
},
isSelectedWithContextMenu(rowData) {
if (rowData && this.contextMenuSelection) {
return this.equals(rowData, this.contextMenuSelection, this.dataKey);
}
return false;
},
findIndexInSelection(rowData) {
return this.findIndex(rowData, this.selection);
},
findIndex(rowData, collection) {
let index = -1;
if (collection && collection.length) {
for (let i = 0; i < collection.length; i++) {
if (this.equals(rowData, collection[i])) {
index = i;
break;
}
}
}
return index;
},
equals(data1, data2) {
return this.compareSelectionBy === 'equals' ? data1 === data2 : ObjectUtils.equals(data1, data2, this.dataKey);
},
onRowGroupToggle(event, data) {
this.$emit('rowgroup-toggle', { originalEvent: event, data: data });
},
onRowClick(event, rowData, rowIndex) {
this.$emit('row-click', { originalEvent: event, data: rowData, index: rowIndex });
},
onRowDblClick(event, rowData, rowIndex) {
this.$emit('row-dblclick', { originalEvent: event, data: rowData, index: rowIndex });
},
onRowRightClick(event, rowData, rowIndex) {
this.$emit('row-rightclick', { originalEvent: event, data: rowData, index: rowIndex });
},
onRowTouchEnd(event) {
this.$emit('row-touchend', event);
},
onRowKeyDown(event, rowData, rowIndex) {
this.$emit('row-keydown', { originalEvent: event, data: rowData, index: rowIndex });
},
onRowMouseDown(event) {
this.$emit('row-mousedown', event);
},
onRowDragStart(event, rowIndex) {
this.$emit('row-dragstart', { originalEvent: event, index: rowIndex });
},
onRowDragOver(event, rowIndex) {
this.$emit('row-dragover', { originalEvent: event, index: rowIndex });
},
onRowDragLeave(event) {
this.$emit('row-dragleave', event);
},
onRowDragEnd(event) {
this.$emit('row-dragend', event);
},
onRowDrop(event) {
this.$emit('row-drop', event);
},
onRowToggle(event) {
this.$emit('row-toggle', event);
},
onRadioChange(event) {
this.$emit('radio-change', event);
},
onCheckboxChange(event) {
this.$emit('checkbox-change', event);
},
onCellEditInit(event) {
this.$emit('cell-edit-init', event);
},
onCellEditComplete(event) {
this.$emit('cell-edit-complete', event);
},
onCellEditCancel(event) {
this.$emit('cell-edit-cancel', event);
},
onRowEditInit(event) {
this.$emit('row-edit-init', event);
},
onRowEditSave(event) {
this.$emit('row-edit-save', event);
},
onRowEditCancel(event) {
this.$emit('row-edit-cancel', event);
},
onEditingMetaChange(event) {
this.$emit('editing-meta-change', event);
},
updateFrozenRowStickyPosition() {
this.$el.style.top = DomHandler.getOuterHeight(this.$el.previousElementSibling) + 'px';
},
updateFrozenRowGroupHeaderStickyPosition() {
let tableHeaderHeight = DomHandler.getOuterHeight(this.$el.previousElementSibling);
this.rowGroupHeaderStyleObject.top = tableHeaderHeight + 'px';
},
getVirtualScrollerProp(option, options) {
options = options || this.virtualScrollerContentProps;
return options ? options[option] : null;
},
bodyRef(el) {
// For VirtualScroller
const contentRef = this.getVirtualScrollerProp('contentRef');
contentRef && contentRef(el);
},
setRowTabindex(index) {
if (this.selection === null && (this.selectionMode === 'single' || this.selectionMode === 'multiple')) {
return index === 0 ? 0 : -1;
}
return -1;
}
},
computed: {
columnsLength() {
let hiddenColLength = 0;
this.columns.forEach((column) => {
if (this.columnProp(column, 'hidden')) hiddenColLength++;
});
return this.columns ? this.columns.length - hiddenColLength : 0;
},
rowGroupHeaderStyle() {
if (this.scrollable) {
return { top: this.rowGroupHeaderStyleObject.top };
}
return null;
},
bodyStyle() {
return this.getVirtualScrollerProp('contentStyle');
},
expandedRowId() {
return UniqueComponentId();
},
nameAttributeSelector() {
return UniqueComponentId();
}
},
components: {
DTBodyCell: BodyCell
}
};
</script>

View file

@ -0,0 +1,90 @@
<template>
<tfoot v-if="hasFooter" class="p-datatable-tfoot" role="rowgroup">
<tr v-if="!columnGroup" role="row">
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
<DTFooterCell v-if="!columnProp(col, 'hidden')" :column="col" />
</template>
</tr>
<template v-else>
<tr v-for="(row, i) of getFooterRows()" :key="i" role="row">
<template v-for="(col, j) of getFooterColumns(row)" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || j">
<DTFooterCell v-if="!columnProp(col, 'hidden')" :column="col" />
</template>
</tr>
</template>
</tfoot>
</template>
<script>
import { ObjectUtils } from 'primevue/utils';
import FooterCell from './FooterCell.vue';
export default {
name: 'TableFooter',
props: {
columnGroup: {
type: null,
default: null
},
columns: {
type: null,
default: null
}
},
methods: {
columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop);
},
getFooterRows() {
let rows = [];
let columnGroup = this.columnGroup;
if (columnGroup.children && columnGroup.children.default) {
for (let child of columnGroup.children.default()) {
if (child.type.name === 'Row') {
rows.push(child);
} else if (child.children && child.children instanceof Array) {
rows = child.children;
}
}
return rows;
}
},
getFooterColumns(row) {
let cols = [];
if (row.children && row.children.default) {
row.children.default().forEach((child) => {
if (child.children && child.children instanceof Array) cols = [...cols, ...child.children];
else if (child.type.name === 'Column') cols.push(child);
});
return cols;
}
}
},
computed: {
hasFooter() {
let hasFooter = false;
if (this.columnGroup) {
hasFooter = true;
} else if (this.columns) {
for (let col of this.columns) {
if (this.columnProp(col, 'footer') || (col.children && col.children.footer)) {
hasFooter = true;
break;
}
}
}
return hasFooter;
}
},
components: {
DTFooterCell: FooterCell
}
};
</script>

View file

@ -0,0 +1,263 @@
<template>
<thead class="p-datatable-thead" role="rowgroup">
<template v-if="!columnGroup">
<tr role="row">
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
<DTHeaderCell
v-if="!columnProp(col, 'hidden') && (rowGroupMode !== 'subheader' || groupRowsBy !== columnProp(col, 'field'))"
:column="col"
@column-click="$emit('column-click', $event)"
@column-mousedown="$emit('column-mousedown', $event)"
@column-dragstart="$emit('column-dragstart', $event)"
@column-dragover="$emit('column-dragover', $event)"
@column-dragleave="$emit('column-dragleave', $event)"
@column-drop="$emit('column-drop', $event)"
:groupRowsBy="groupRowsBy"
:groupRowSortField="groupRowSortField"
:reorderableColumns="reorderableColumns"
:resizableColumns="resizableColumns"
@column-resizestart="$emit('column-resizestart', $event)"
:sortMode="sortMode"
:sortField="sortField"
:sortOrder="sortOrder"
:multiSortMeta="multiSortMeta"
:allRowsSelected="allRowsSelected"
:empty="empty"
@checkbox-change="$emit('checkbox-change', $event)"
:filters="filters"
:filterDisplay="filterDisplay"
:filtersStore="filtersStore"
:filterInputProps="filterInputProps"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
/>
</template>
</tr>
<tr v-if="filterDisplay === 'row'" role="row">
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
<th v-if="!columnProp(col, 'hidden') && (rowGroupMode !== 'subheader' || groupRowsBy !== columnProp(col, 'field'))" :style="getFilterColumnHeaderStyle(col)" :class="getFilterColumnHeaderClass(col)">
<DTHeaderCheckbox v-if="columnProp(col, 'selectionMode') === 'multiple'" :checked="allRowsSelected" :disabled="empty" @change="$emit('checkbox-change', $event)" />
<DTColumnFilter
v-if="col.children && col.children.filter"
:field="columnProp(col, 'filterField') || columnProp(col, 'field')"
:type="columnProp(col, 'dataType')"
display="row"
:showMenu="columnProp(col, 'showFilterMenu')"
:filterElement="col.children && col.children.filter"
:filterHeaderTemplate="col.children && col.children.filterheader"
:filterFooterTemplate="col.children && col.children.filterfooter"
:filterClearTemplate="col.children && col.children.filterclear"
:filterApplyTemplate="col.children && col.children.filterapply"
:filters="filters"
:filtersStore="filtersStore"
:filterInputProps="filterInputProps"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
:filterMenuStyle="columnProp(col, 'filterMenuStyle')"
:filterMenuClass="columnProp(col, 'filterMenuClass')"
:showOperator="columnProp(col, 'showFilterOperator')"
:showClearButton="columnProp(col, 'showClearButton')"
:showApplyButton="columnProp(col, 'showApplyButton')"
:showMatchModes="columnProp(col, 'showFilterMatchModes')"
:showAddButton="columnProp(col, 'showAddButton')"
:matchModeOptions="columnProp(col, 'filterMatchModeOptions')"
:maxConstraints="columnProp(col, 'maxConstraints')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
/>
</th>
</template>
</tr>
</template>
<template v-else>
<tr v-for="(row, i) of getHeaderRows()" :key="i" role="row">
<template v-for="(col, j) of getHeaderColumns(row)" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || j">
<DTHeaderCell
v-if="!columnProp(col, 'hidden') && (rowGroupMode !== 'subheader' || groupRowsBy !== columnProp(col, 'field')) && typeof col.children !== 'string'"
:column="col"
@column-click="$emit('column-click', $event)"
@column-mousedown="$emit('column-mousedown', $event)"
:groupRowsBy="groupRowsBy"
:groupRowSortField="groupRowSortField"
:sortMode="sortMode"
:sortField="sortField"
:sortOrder="sortOrder"
:multiSortMeta="multiSortMeta"
:allRowsSelected="allRowsSelected"
:empty="empty"
@checkbox-change="$emit('checkbox-change', $event)"
:filters="filters"
:filterDisplay="filterDisplay"
:filtersStore="filtersStore"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
/>
</template>
</tr>
</template>
</thead>
</template>
<script>
import { ObjectUtils } from 'primevue/utils';
import ColumnFilter from './ColumnFilter.vue';
import HeaderCell from './HeaderCell.vue';
import HeaderCheckbox from './HeaderCheckbox.vue';
export default {
name: 'TableHeader',
emits: [
'column-click',
'column-mousedown',
'column-dragstart',
'column-dragover',
'column-dragleave',
'column-drop',
'column-resizestart',
'checkbox-change',
'filter-change',
'filter-apply',
'operator-change',
'matchmode-change',
'constraint-add',
'constraint-remove',
'filter-clear',
'apply-click'
],
props: {
columnGroup: {
type: null,
default: null
},
columns: {
type: null,
default: null
},
rowGroupMode: {
type: String,
default: null
},
groupRowsBy: {
type: [Array, String, Function],
default: null
},
resizableColumns: {
type: Boolean,
default: false
},
allRowsSelected: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
},
sortMode: {
type: String,
default: 'single'
},
groupRowSortField: {
type: [String, Function],
default: null
},
sortField: {
type: [String, Function],
default: null
},
sortOrder: {
type: Number,
default: null
},
multiSortMeta: {
type: Array,
default: null
},
filterDisplay: {
type: String,
default: null
},
filters: {
type: Object,
default: null
},
filtersStore: {
type: Object,
default: null
},
reorderableColumns: {
type: Boolean,
default: false
},
filterInputProps: {
type: null,
default: null
}
},
methods: {
columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop);
},
getFilterColumnHeaderClass(column) {
return [
'p-filter-column',
this.columnProp(column, 'filterHeaderClass'),
this.columnProp(column, 'class'),
{
'p-frozen-column': this.columnProp(column, 'frozen')
}
];
},
getFilterColumnHeaderStyle(column) {
return [this.columnProp(column, 'filterHeaderStyle'), this.columnProp(column, 'style')];
},
getHeaderRows() {
let rows = [];
let columnGroup = this.columnGroup;
if (columnGroup.children && columnGroup.children.default) {
for (let child of columnGroup.children.default()) {
if (child.type.name === 'Row') {
rows.push(child);
} else if (child.children && child.children instanceof Array) {
rows = child.children;
}
}
return rows;
}
},
getHeaderColumns(row) {
let cols = [];
if (row.children && row.children.default) {
row.children.default().forEach((child) => {
if (child.children && child.children instanceof Array) cols = [...cols, ...child.children];
else if (child.type.name === 'Column') cols.push(child);
});
return cols;
}
}
},
components: {
DTHeaderCell: HeaderCell,
DTHeaderCheckbox: HeaderCheckbox,
DTColumnFilter: ColumnFilter
}
};
</script>

View file

@ -0,0 +1,25 @@
<template>
<tbody class="p-datatable-tbody">
<tr v-for="n in rows" :key="n" role="row">
<td v-for="(col, i) of columns" :key="col.props.columnKey || col.props.field || i">
<component v-if="col.children && col.children.loading" :is="col.children.loading" :column="col" :index="i" />
</td>
</tr>
</tbody>
</template>
<script>
export default {
name: 'TableLoadingBody',
props: {
columns: {
type: null,
default: null
},
rows: {
type: null,
default: null
}
}
};
</script>

View file

@ -0,0 +1,9 @@
{
"main": "./datatable.cjs.js",
"module": "./datatable.esm.js",
"unpkg": "./datatable.min.js",
"types": "./DataTable.d.ts",
"browser": {
"./sfc": "./DataTable.vue"
}
}