quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
1,052 lines (881 loc) • 29.2 kB
JavaScript
import { h, ref, computed, watch, getCurrentInstance } from 'vue'
import QTh from './QTh.js'
import QSeparator from '../separator/QSeparator.js'
import QIcon from '../icon/QIcon.js'
import QVirtualScroll from '../virtual-scroll/QVirtualScroll.js'
import QSelect from '../select/QSelect.js'
import QLinearProgress from '../linear-progress/QLinearProgress.js'
import QCheckbox from '../checkbox/QCheckbox.js'
import QBtn from '../btn/QBtn.js'
import getTableMiddle from './get-table-middle.js'
import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
import { commonVirtPropsList } from '../virtual-scroll/use-virtual-scroll.js'
import useFullscreen, { useFullscreenProps, useFullscreenEmits } from '../../composables/private/use-fullscreen.js'
import { useTableSort, useTableSortProps } from './table-sort.js'
import { useTableFilter, useTableFilterProps } from './table-filter.js'
import { useTablePaginationState, useTablePagination, useTablePaginationProps } from './table-pagination.js'
import { useTableRowSelection, useTableRowSelectionProps, useTableRowSelectionEmits } from './table-row-selection.js'
import { useTableRowExpand, useTableRowExpandProps, useTableRowExpandEmits } from './table-row-expand.js'
import { useTableColumnSelection, useTableColumnSelectionProps } from './table-column-selection.js'
import { injectProp, injectMultipleProps } from '../../utils/private/inject-obj-prop.js'
import { createComponent } from '../../utils/private/create.js'
const bottomClass = 'q-table__bottom row items-center'
const commonVirtPropsObj = {}
commonVirtPropsList.forEach(p => { commonVirtPropsObj[ p ] = {} })
export default createComponent({
name: 'QTable',
props: {
rows: {
type: Array,
default: () => []
},
rowKey: {
type: [ String, Function ],
default: 'id'
},
columns: Array,
loading: Boolean,
iconFirstPage: String,
iconPrevPage: String,
iconNextPage: String,
iconLastPage: String,
title: String,
hideHeader: Boolean,
grid: Boolean,
gridHeader: Boolean,
dense: Boolean,
flat: Boolean,
bordered: Boolean,
square: Boolean,
separator: {
type: String,
default: 'horizontal',
validator: v => [ 'horizontal', 'vertical', 'cell', 'none' ].includes(v)
},
wrapCells: Boolean,
virtualScroll: Boolean,
virtualScrollTarget: {
default: void 0
},
...commonVirtPropsObj,
noDataLabel: String,
noResultsLabel: String,
loadingLabel: String,
selectedRowsLabel: Function,
rowsPerPageLabel: String,
paginationLabel: Function,
color: {
type: String,
default: 'grey-8'
},
titleClass: [ String, Array, Object ],
tableStyle: [ String, Array, Object ],
tableClass: [ String, Array, Object ],
tableHeaderStyle: [ String, Array, Object ],
tableHeaderClass: [ String, Array, Object ],
cardContainerClass: [ String, Array, Object ],
cardContainerStyle: [ String, Array, Object ],
cardStyle: [ String, Array, Object ],
cardClass: [ String, Array, Object ],
hideBottom: Boolean,
hideSelectedBanner: Boolean,
hideNoData: Boolean,
hidePagination: Boolean,
onRowClick: Function,
onRowDblclick: Function,
onRowContextmenu: Function,
...useDarkProps,
...useFullscreenProps,
...useTableColumnSelectionProps,
...useTableFilterProps,
...useTablePaginationProps,
...useTableRowExpandProps,
...useTableRowSelectionProps,
...useTableSortProps
},
emits: [
'request', 'virtualScroll',
...useFullscreenEmits,
...useTableRowExpandEmits,
...useTableRowSelectionEmits
],
setup (props, { slots, emit }) {
const vm = getCurrentInstance()
const { proxy: { $q } } = vm
const isDark = useDark(props, $q)
const { inFullscreen, toggleFullscreen } = useFullscreen()
const getRowKey = computed(() => (
typeof props.rowKey === 'function'
? props.rowKey
: row => row[ props.rowKey ]
))
const rootRef = ref(null)
const virtScrollRef = ref(null)
const hasVirtScroll = computed(() => props.grid !== true && props.virtualScroll === true)
const cardDefaultClass = computed(() =>
' q-table__card'
+ (isDark.value === true ? ' q-table__card--dark q-dark' : '')
+ (props.square === true ? ' q-table--square' : '')
+ (props.flat === true ? ' q-table--flat' : '')
+ (props.bordered === true ? ' q-table--bordered' : '')
)
const __containerClass = computed(() =>
`q-table__container q-table--${ props.separator }-separator column no-wrap`
+ (props.grid === true ? ' q-table--grid' : cardDefaultClass.value)
+ (isDark.value === true ? ' q-table--dark' : '')
+ (props.dense === true ? ' q-table--dense' : '')
+ (props.wrapCells === false ? ' q-table--no-wrap' : '')
+ (inFullscreen.value === true ? ' fullscreen scroll' : '')
)
const containerClass = computed(() =>
__containerClass.value + (props.loading === true ? ' q-table--loading' : '')
)
watch(
() => props.tableStyle + props.tableClass + props.tableHeaderStyle + props.tableHeaderClass + __containerClass.value,
() => { hasVirtScroll.value === true && virtScrollRef.value !== null && virtScrollRef.value.reset() }
)
const {
innerPagination,
computedPagination,
isServerSide,
requestServerInteraction,
setPagination
} = useTablePaginationState(vm, getCellValue)
const { computedFilterMethod } = useTableFilter(props, setPagination)
const { isRowExpanded, setExpanded, updateExpanded } = useTableRowExpand(props, emit)
const filteredSortedRows = computed(() => {
let rows = props.rows
if (isServerSide.value === true || rows.length === 0) {
return rows
}
const { sortBy, descending } = computedPagination.value
if (props.filter) {
rows = computedFilterMethod.value(rows, props.filter, computedCols.value, getCellValue)
}
if (columnToSort.value !== null) {
rows = computedSortMethod.value(
props.rows === rows ? rows.slice() : rows,
sortBy,
descending
)
}
return rows
})
const filteredSortedRowsNumber = computed(() => filteredSortedRows.value.length)
const computedRows = computed(() => {
let rows = filteredSortedRows.value
if (isServerSide.value === true) {
return rows
}
const { rowsPerPage } = computedPagination.value
if (rowsPerPage !== 0) {
if (firstRowIndex.value === 0 && props.rows !== rows) {
if (rows.length > lastRowIndex.value) {
rows = rows.slice(0, lastRowIndex.value)
}
}
else {
rows = rows.slice(firstRowIndex.value, lastRowIndex.value)
}
}
return rows
})
const {
hasSelectionMode,
singleSelection,
multipleSelection,
allRowsSelected,
someRowsSelected,
rowsSelectedNumber,
isRowSelected,
clearSelection,
updateSelection
} = useTableRowSelection(props, emit, computedRows, getRowKey)
const { colList, computedCols, computedColsMap, computedColspan } = useTableColumnSelection(props, computedPagination, hasSelectionMode)
const { columnToSort, computedSortMethod, sort } = useTableSort(props, computedPagination, colList, setPagination)
const {
firstRowIndex,
lastRowIndex,
isFirstPage,
isLastPage,
pagesNumber,
computedRowsPerPageOptions,
computedRowsNumber,
firstPage,
prevPage,
nextPage,
lastPage
} = useTablePagination(vm, innerPagination, computedPagination, isServerSide, setPagination, filteredSortedRowsNumber)
const nothingToDisplay = computed(() => computedRows.value.length === 0)
const virtProps = computed(() => {
const acc = {}
commonVirtPropsList
.forEach(p => { acc[ p ] = props[ p ] })
if (acc.virtualScrollItemSize === void 0) {
acc.virtualScrollItemSize = props.dense === true ? 28 : 48
}
return acc
})
function resetVirtualScroll () {
hasVirtScroll.value === true && virtScrollRef.value.reset()
}
function getBody () {
if (props.grid === true) {
return getGridBody()
}
const header = props.hideHeader !== true ? getTHead : null
if (hasVirtScroll.value === true) {
const topRow = slots[ 'top-row' ]
const bottomRow = slots[ 'bottom-row' ]
const virtSlots = {
default: props => getTBodyTR(props.item, slots.body, props.index)
}
if (topRow !== void 0) {
const topContent = h('tbody', topRow({ cols: computedCols.value }))
virtSlots.before = header === null
? () => topContent
: () => [ header() ].concat(topContent)
}
else if (header !== null) {
virtSlots.before = header
}
if (bottomRow !== void 0) {
virtSlots.after = () => h('tbody', bottomRow({ cols: computedCols.value }))
}
return h(QVirtualScroll, {
ref: virtScrollRef,
class: props.tableClass,
style: props.tableStyle,
...virtProps.value,
scrollTarget: props.virtualScrollTarget,
items: computedRows.value,
type: '__qtable',
tableColspan: computedColspan.value,
onVirtualScroll: onVScroll
}, virtSlots)
}
const child = [
getTBody()
]
if (header !== null) {
child.unshift(header())
}
return getTableMiddle({
class: [ 'q-table__middle scroll', props.tableClass ],
style: props.tableStyle
}, child)
}
function scrollTo (toIndex, edge) {
if (virtScrollRef.value !== null) {
virtScrollRef.value.scrollTo(toIndex, edge)
return
}
toIndex = parseInt(toIndex, 10)
const rowEl = rootRef.value.querySelector(`tbody tr:nth-of-type(${ toIndex + 1 })`)
if (rowEl !== null) {
const scrollTarget = rootRef.value.querySelector('.q-table__middle.scroll')
const offsetTop = rowEl.offsetTop - props.virtualScrollStickySizeStart
const direction = offsetTop < scrollTarget.scrollTop ? 'decrease' : 'increase'
scrollTarget.scrollTop = offsetTop
emit('virtualScroll', {
index: toIndex,
from: 0,
to: innerPagination.value.rowsPerPage - 1,
direction
})
}
}
function onVScroll (info) {
emit('virtualScroll', info)
}
function getProgress () {
return [
h(QLinearProgress, {
class: 'q-table__linear-progress',
color: props.color,
dark: isDark.value,
indeterminate: true,
trackColor: 'transparent'
})
]
}
function getTBodyTR (row, bodySlot, pageIndex) {
const
key = getRowKey.value(row),
selected = isRowSelected(key)
if (bodySlot !== void 0) {
return bodySlot(
getBodyScope({
key,
row,
pageIndex,
__trClass: selected ? 'selected' : ''
})
)
}
const
bodyCell = slots[ 'body-cell' ],
child = computedCols.value.map(col => {
const
bodyCellCol = slots[ `body-cell-${ col.name }` ],
slot = bodyCellCol !== void 0 ? bodyCellCol : bodyCell
return slot !== void 0
? slot(getBodyCellScope({ key, row, pageIndex, col }))
: h('td', {
class: col.__tdClass(row),
style: col.__tdStyle(row)
}, getCellValue(col, row))
})
if (hasSelectionMode.value === true) {
const slot = slots[ 'body-selection' ]
const content = slot !== void 0
? slot(getBodySelectionScope({ key, row, pageIndex }))
: [
h(QCheckbox, {
modelValue: selected,
color: props.color,
dark: isDark.value,
dense: props.dense,
'onUpdate:modelValue': (adding, evt) => {
updateSelection([ key ], [ row ], adding, evt)
}
})
]
child.unshift(
h('td', { class: 'q-table--col-auto-width' }, content)
)
}
const data = { key, class: { selected } }
if (props.onRowClick !== void 0) {
data.class[ 'cursor-pointer' ] = true
data.onClick = evt => {
emit('RowClick', evt, row, pageIndex)
}
}
if (props.onRowDblclick !== void 0) {
data.class[ 'cursor-pointer' ] = true
data.onDblclick = evt => {
emit('RowDblclick', evt, row, pageIndex)
}
}
if (props.onRowContextmenu !== void 0) {
data.class[ 'cursor-pointer' ] = true
data.onContextmenu = evt => {
emit('RowContextmenu', evt, row, pageIndex)
}
}
return h('tr', data, child)
}
function getTBody () {
const
body = slots.body,
topRow = slots[ 'top-row' ],
bottomRow = slots[ 'bottom-row' ]
let child = computedRows.value.map(
(row, pageIndex) => getTBodyTR(row, body, pageIndex)
)
if (topRow !== void 0) {
child = topRow({ cols: computedCols.value }).concat(child)
}
if (bottomRow !== void 0) {
child = child.concat(bottomRow({ cols: computedCols.value }))
}
return h('tbody', child)
}
function getBodyScope (data) {
injectBodyCommonScope(data)
data.cols = data.cols.map(
col => injectProp({ ...col }, 'value', () => getCellValue(col, data.row))
)
return data
}
function getBodyCellScope (data) {
injectBodyCommonScope(data)
injectProp(data, 'value', () => getCellValue(data.col, data.row))
return data
}
function getBodySelectionScope (data) {
injectBodyCommonScope(data)
return data
}
function injectBodyCommonScope (data) {
Object.assign(data, {
cols: computedCols.value,
colsMap: computedColsMap.value,
sort,
rowIndex: firstRowIndex.value + data.pageIndex,
color: props.color,
dark: isDark.value,
dense: props.dense
})
hasSelectionMode.value === true && injectProp(
data,
'selected',
() => isRowSelected(data.key),
(adding, evt) => {
updateSelection([ data.key ], [ data.row ], adding, evt)
}
)
injectProp(
data,
'expand',
() => isRowExpanded(data.key),
adding => { updateExpanded(data.key, adding) }
)
}
function getCellValue (col, row) {
const val = typeof col.field === 'function' ? col.field(row) : row[ col.field ]
return col.format !== void 0 ? col.format(val, row) : val
}
const marginalsScope = computed(() => ({
pagination: computedPagination.value,
pagesNumber: pagesNumber.value,
isFirstPage: isFirstPage.value,
isLastPage: isLastPage.value,
firstPage,
prevPage,
nextPage,
lastPage,
inFullscreen: inFullscreen.value,
toggleFullscreen
}))
function getTopDiv () {
const
top = slots.top,
topLeft = slots[ 'top-left' ],
topRight = slots[ 'top-right' ],
topSelection = slots[ 'top-selection' ],
hasSelection = hasSelectionMode.value === true
&& topSelection !== void 0
&& rowsSelectedNumber.value > 0,
topClass = 'q-table__top relative-position row items-center'
if (top !== void 0) {
return h('div', { class: topClass }, [ top(marginalsScope.value) ])
}
let child
if (hasSelection === true) {
child = topSelection(marginalsScope.value).slice()
}
else {
child = []
if (topLeft !== void 0) {
child.push(
h('div', { class: 'q-table__control' }, [
topLeft(marginalsScope.value)
])
)
}
else if (props.title) {
child.push(
h('div', { class: 'q-table__control' }, [
h('div', {
class: [ 'q-table__title', props.titleClass ]
}, props.title)
])
)
}
}
if (topRight !== void 0) {
child.push(
h('div', { class: 'q-table__separator col' })
)
child.push(
h('div', { class: 'q-table__control' }, [
topRight(marginalsScope.value)
])
)
}
if (child.length === 0) {
return
}
return h('div', { class: topClass }, child)
}
const headerSelectedValue = computed(() => (
someRowsSelected.value === true
? null
: allRowsSelected.value
))
function getTHead () {
const child = getTHeadTR()
if (props.loading === true && slots.loading === void 0) {
child.push(
h('tr', { class: 'q-table__progress' }, [
h('th', {
class: 'relative-position',
colspan: computedColspan.value
}, getProgress())
])
)
}
return h('thead', child)
}
function getTHeadTR () {
const
header = slots.header,
headerCell = slots[ 'header-cell' ]
if (header !== void 0) {
return header(
getHeaderScope({ header: true })
).slice()
}
const child = computedCols.value.map(col => {
const
headerCellCol = slots[ `header-cell-${ col.name }` ],
slot = headerCellCol !== void 0 ? headerCellCol : headerCell,
props = getHeaderScope({ col })
return slot !== void 0
? slot(props)
: h(QTh, {
key: col.name,
props
}, () => col.label)
})
if (singleSelection.value === true && props.grid !== true) {
child.unshift(
h('th', { class: 'q-table--col-auto-width' }, ' ')
)
}
else if (multipleSelection.value === true) {
const slot = slots[ 'header-selection' ]
const content = slot !== void 0
? slot(getHeaderScope({}))
: [
h(QCheckbox, {
color: props.color,
modelValue: headerSelectedValue.value,
dark: isDark.value,
dense: props.dense,
'onUpdate:modelValue': onMultipleSelectionSet
})
]
child.unshift(
h('th', { class: 'q-table--col-auto-width' }, content)
)
}
return [
h('tr', {
class: props.tableHeaderClass,
style: props.tableHeaderStyle
}, child)
]
}
function getHeaderScope (data) {
Object.assign(data, {
cols: computedCols.value,
sort,
colsMap: computedColsMap.value,
color: props.color,
dark: isDark.value,
dense: props.dense
})
if (multipleSelection.value === true) {
injectProp(
data,
'selected',
() => headerSelectedValue.value,
onMultipleSelectionSet
)
}
return data
}
function onMultipleSelectionSet (val) {
if (someRowsSelected.value === true) {
val = false
}
updateSelection(
computedRows.value.map(getRowKey.value),
computedRows.value,
val
)
}
const navIcon = computed(() => {
const ico = [
props.iconFirstPage || $q.iconSet.table.firstPage,
props.iconPrevPage || $q.iconSet.table.prevPage,
props.iconNextPage || $q.iconSet.table.nextPage,
props.iconLastPage || $q.iconSet.table.lastPage
]
return $q.lang.rtl === true ? ico.reverse() : ico
})
function getBottomDiv () {
if (props.hideBottom === true) {
return
}
if (nothingToDisplay.value === true) {
if (props.hideNoData === true) {
return
}
const message = props.loading === true
? props.loadingLabel || $q.lang.table.loading
: (props.filter ? props.noResultsLabel || $q.lang.table.noResults : props.noDataLabel || $q.lang.table.noData)
const noData = slots[ 'no-data' ]
const children = noData !== void 0
? [ noData({ message, icon: $q.iconSet.table.warning, filter: props.filter }) ]
: [
h(QIcon, {
class: 'q-table__bottom-nodata-icon',
name: $q.iconSet.table.warning
}),
message
]
return h('div', { class: bottomClass + ' q-table__bottom--nodata' }, children)
}
const bottom = slots.bottom
if (bottom !== void 0) {
return h('div', { class: bottomClass }, [ bottom(marginalsScope.value) ])
}
const child = props.hideSelectedBanner !== true && hasSelectionMode.value === true && rowsSelectedNumber.value > 0
? [
h('div', { class: 'q-table__control' }, [
h('div', [
(props.selectedRowsLabel || $q.lang.table.selectedRecords)(rowsSelectedNumber.value)
])
])
]
: []
if (props.hidePagination !== true) {
return h('div', {
class: bottomClass + ' justify-end'
}, getPaginationDiv(child))
}
if (child.length > 0) {
return h('div', { class: bottomClass }, child)
}
}
function onPagSelection (pag) {
setPagination({
page: 1,
rowsPerPage: pag.value
})
}
function getPaginationDiv (child) {
let control
const
{ rowsPerPage } = computedPagination.value,
paginationLabel = props.paginationLabel || $q.lang.table.pagination,
paginationSlot = slots.pagination,
hasOpts = props.rowsPerPageOptions.length > 1
child.push(
h('div', { class: 'q-table__separator col' })
)
if (hasOpts === true) {
child.push(
h('div', { class: 'q-table__control' }, [
h('span', { class: 'q-table__bottom-item' }, [
props.rowsPerPageLabel || $q.lang.table.recordsPerPage
]),
h(QSelect, {
class: 'q-table__select inline q-table__bottom-item',
color: props.color,
modelValue: rowsPerPage,
options: computedRowsPerPageOptions.value,
displayValue: rowsPerPage === 0
? $q.lang.table.allRows
: rowsPerPage,
dark: isDark.value,
borderless: true,
dense: true,
optionsDense: true,
optionsCover: true,
'onUpdate:modelValue': onPagSelection
})
])
)
}
if (paginationSlot !== void 0) {
control = paginationSlot(marginalsScope.value)
}
else {
control = [
h('span', rowsPerPage !== 0 ? { class: 'q-table__bottom-item' } : {}, [
rowsPerPage
? paginationLabel(firstRowIndex.value + 1, Math.min(lastRowIndex.value, computedRowsNumber.value), computedRowsNumber.value)
: paginationLabel(1, filteredSortedRowsNumber.value, computedRowsNumber.value)
])
]
if (rowsPerPage !== 0 && pagesNumber.value > 1) {
const btnProps = {
color: props.color,
round: true,
dense: true,
flat: true
}
if (props.dense === true) {
btnProps.size = 'sm'
}
pagesNumber.value > 2 && control.push(
h(QBtn, {
key: 'pgFirst',
...btnProps,
icon: navIcon.value[ 0 ],
disable: isFirstPage.value,
onClick: firstPage
})
)
control.push(
h(QBtn, {
key: 'pgPrev',
...btnProps,
icon: navIcon.value[ 1 ],
disable: isFirstPage.value,
onClick: prevPage
}),
h(QBtn, {
key: 'pgNext',
...btnProps,
icon: navIcon.value[ 2 ],
disable: isLastPage.value,
onClick: nextPage
})
)
pagesNumber.value > 2 && control.push(
h(QBtn, {
key: 'pgLast',
...btnProps,
icon: navIcon.value[ 3 ],
disable: isLastPage.value,
onClick: lastPage
})
)
}
}
child.push(
h('div', { class: 'q-table__control' }, control)
)
return child
}
function getGridHeader () {
const child = props.gridHeader === true
? [
h('table', { class: 'q-table' }, [
getTHead(h)
])
]
: (
props.loading === true && slots.loading === void 0
? getProgress(h)
: void 0
)
return h('div', { class: 'q-table__middle' }, child)
}
function getGridBody () {
const item = slots.item !== void 0
? slots.item
: scope => {
const child = scope.cols.map(
col => h('div', { class: 'q-table__grid-item-row' }, [
h('div', { class: 'q-table__grid-item-title' }, [ col.label ]),
h('div', { class: 'q-table__grid-item-value' }, [ col.value ])
])
)
if (hasSelectionMode.value === true) {
const slot = slots[ 'body-selection' ]
const content = slot !== void 0
? slot(scope)
: [
h(QCheckbox, {
modelValue: scope.selected,
color: props.color,
dark: isDark.value,
dense: props.dense,
'onUpdate:modelValue': (adding, evt) => {
updateSelection([ scope.key ], [ scope.row ], adding, evt)
}
})
]
child.unshift(
h('div', { class: 'q-table__grid-item-row' }, content),
h(QSeparator, { dark: isDark.value })
)
}
const data = {
class: [
'q-table__grid-item-card' + cardDefaultClass.value,
props.cardClass
],
style: props.cardStyle
}
if (
props.onRowClick !== void 0
|| props.onRowDblclick !== void 0
) {
data.class[ 0 ] += ' cursor-pointer'
if (props.onRowClick !== void 0) {
data.onClick = evt => {
emit('RowClick', evt, scope.row, scope.pageIndex)
}
}
if (props.onRowDblclick !== void 0) {
data.onDblclick = evt => {
emit('RowDblclick', evt, scope.row, scope.pageIndex)
}
}
}
return h('div', {
class: 'q-table__grid-item col-xs-12 col-sm-6 col-md-4 col-lg-3'
+ (scope.selected === true ? ' q-table__grid-item--selected' : '')
}, [
h('div', data, child)
])
}
return h('div', {
class: [
'q-table__grid-content row',
props.cardContainerClass
],
style: props.cardContainerStyle
}, computedRows.value.map((row, pageIndex) => {
return item(getBodyScope({
key: getRowKey.value(row),
row,
pageIndex
}))
}))
}
// expose public methods and needed computed props
Object.assign(vm.proxy, {
requestServerInteraction,
setPagination,
firstPage,
prevPage,
nextPage,
lastPage,
isRowSelected,
clearSelection,
isRowExpanded,
setExpanded,
sort,
resetVirtualScroll,
scrollTo,
getCellValue
})
injectMultipleProps(vm.proxy, {
filteredSortedRows: () => filteredSortedRows.value,
computedRows: () => computedRows.value,
computedRowsNumber: () => computedRowsNumber.value
})
return () => {
const child = [ getTopDiv() ]
const data = { ref: rootRef, class: containerClass.value }
if (props.grid === true) {
child.push(getGridHeader())
}
else {
Object.assign(data, {
class: [ data.class, props.cardClass ],
style: props.cardStyle
})
}
child.push(
getBody(),
getBottomDiv()
)
if (props.loading === true && slots.loading !== void 0) {
child.push(
slots.loading()
)
}
return h('div', data, child)
}
}
})