Vulture/VApp/node_modules/vuetify/lib/components/VPagination/VPagination.mjs

340 lines
12 KiB
JavaScript
Raw Normal View History

import { createVNode as _createVNode, mergeProps as _mergeProps } from "vue";
// Styles
import "./VPagination.css";
// Components
import { VBtn } from "../VBtn/index.mjs"; // Composables
import { useDisplay } from "../../composables/index.mjs";
import { makeBorderProps } from "../../composables/border.mjs";
import { makeComponentProps } from "../../composables/component.mjs";
import { provideDefaults } from "../../composables/defaults.mjs";
import { makeDensityProps } from "../../composables/density.mjs";
import { makeElevationProps } from "../../composables/elevation.mjs";
import { IconValue } from "../../composables/icons.mjs";
import { useLocale, useRtl } from "../../composables/locale.mjs";
import { useProxiedModel } from "../../composables/proxiedModel.mjs";
import { useRefs } from "../../composables/refs.mjs";
import { useResizeObserver } from "../../composables/resizeObserver.mjs";
import { makeRoundedProps } from "../../composables/rounded.mjs";
import { makeSizeProps } from "../../composables/size.mjs";
import { makeTagProps } from "../../composables/tag.mjs";
import { makeThemeProps, provideTheme } from "../../composables/theme.mjs";
import { makeVariantProps } from "../../composables/variant.mjs"; // Utilities
import { computed, nextTick, shallowRef, toRef } from 'vue';
import { createRange, genericComponent, keyValues, propsFactory, useRender } from "../../util/index.mjs"; // Types
export const makeVPaginationProps = propsFactory({
activeColor: String,
start: {
type: [Number, String],
default: 1
},
modelValue: {
type: Number,
default: props => props.start
},
disabled: Boolean,
length: {
type: [Number, String],
default: 1,
validator: val => val % 1 === 0
},
totalVisible: [Number, String],
firstIcon: {
type: IconValue,
default: '$first'
},
prevIcon: {
type: IconValue,
default: '$prev'
},
nextIcon: {
type: IconValue,
default: '$next'
},
lastIcon: {
type: IconValue,
default: '$last'
},
ariaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.root'
},
pageAriaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.page'
},
currentPageAriaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.currentPage'
},
firstAriaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.first'
},
previousAriaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.previous'
},
nextAriaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.next'
},
lastAriaLabel: {
type: String,
default: '$vuetify.pagination.ariaLabel.last'
},
ellipsis: {
type: String,
default: '...'
},
showFirstLastPage: Boolean,
...makeBorderProps(),
...makeComponentProps(),
...makeDensityProps(),
...makeElevationProps(),
...makeRoundedProps(),
...makeSizeProps(),
...makeTagProps({
tag: 'nav'
}),
...makeThemeProps(),
...makeVariantProps({
variant: 'text'
})
}, 'VPagination');
export const VPagination = genericComponent()({
name: 'VPagination',
props: makeVPaginationProps(),
emits: {
'update:modelValue': value => true,
first: value => true,
prev: value => true,
next: value => true,
last: value => true
},
setup(props, _ref) {
let {
slots,
emit
} = _ref;
const page = useProxiedModel(props, 'modelValue');
const {
t,
n
} = useLocale();
const {
isRtl
} = useRtl();
const {
themeClasses
} = provideTheme(props);
const {
width
} = useDisplay();
const maxButtons = shallowRef(-1);
provideDefaults(undefined, {
scoped: true
});
const {
resizeRef
} = useResizeObserver(entries => {
if (!entries.length) return;
const {
target,
contentRect
} = entries[0];
const firstItem = target.querySelector('.v-pagination__list > *');
if (!firstItem) return;
const totalWidth = contentRect.width;
const itemWidth = firstItem.offsetWidth + parseFloat(getComputedStyle(firstItem).marginRight) * 2;
maxButtons.value = getMax(totalWidth, itemWidth);
});
const length = computed(() => parseInt(props.length, 10));
const start = computed(() => parseInt(props.start, 10));
const totalVisible = computed(() => {
if (props.totalVisible != null) return parseInt(props.totalVisible, 10);else if (maxButtons.value >= 0) return maxButtons.value;
return getMax(width.value, 58);
});
function getMax(totalWidth, itemWidth) {
const minButtons = props.showFirstLastPage ? 5 : 3;
return Math.max(0, Math.floor(
// Round to two decimal places to avoid floating point errors
+((totalWidth - itemWidth * minButtons) / itemWidth).toFixed(2)));
}
const range = computed(() => {
if (length.value <= 0 || isNaN(length.value) || length.value > Number.MAX_SAFE_INTEGER) return [];
if (totalVisible.value <= 0) return [];else if (totalVisible.value === 1) return [page.value];
if (length.value <= totalVisible.value) {
return createRange(length.value, start.value);
}
const even = totalVisible.value % 2 === 0;
const middle = even ? totalVisible.value / 2 : Math.floor(totalVisible.value / 2);
const left = even ? middle : middle + 1;
const right = length.value - middle;
if (left - page.value >= 0) {
return [...createRange(Math.max(1, totalVisible.value - 1), start.value), props.ellipsis, length.value];
} else if (page.value - right >= (even ? 1 : 0)) {
const rangeLength = totalVisible.value - 1;
const rangeStart = length.value - rangeLength + start.value;
return [start.value, props.ellipsis, ...createRange(rangeLength, rangeStart)];
} else {
const rangeLength = Math.max(1, totalVisible.value - 3);
const rangeStart = rangeLength === 1 ? page.value : page.value - Math.ceil(rangeLength / 2) + start.value;
return [start.value, props.ellipsis, ...createRange(rangeLength, rangeStart), props.ellipsis, length.value];
}
});
// TODO: 'first' | 'prev' | 'next' | 'last' does not work here?
function setValue(e, value, event) {
e.preventDefault();
page.value = value;
event && emit(event, value);
}
const {
refs,
updateRef
} = useRefs();
provideDefaults({
VPaginationBtn: {
color: toRef(props, 'color'),
border: toRef(props, 'border'),
density: toRef(props, 'density'),
size: toRef(props, 'size'),
variant: toRef(props, 'variant'),
rounded: toRef(props, 'rounded'),
elevation: toRef(props, 'elevation')
}
});
const items = computed(() => {
return range.value.map((item, index) => {
const ref = e => updateRef(e, index);
if (typeof item === 'string') {
return {
isActive: false,
key: `ellipsis-${index}`,
page: item,
props: {
ref,
ellipsis: true,
icon: true,
disabled: true
}
};
} else {
const isActive = item === page.value;
return {
isActive,
key: item,
page: n(item),
props: {
ref,
ellipsis: false,
icon: true,
disabled: !!props.disabled || +props.length < 2,
color: isActive ? props.activeColor : props.color,
'aria-current': isActive,
'aria-label': t(isActive ? props.currentPageAriaLabel : props.pageAriaLabel, item),
onClick: e => setValue(e, item)
}
};
}
});
});
const controls = computed(() => {
const prevDisabled = !!props.disabled || page.value <= start.value;
const nextDisabled = !!props.disabled || page.value >= start.value + length.value - 1;
return {
first: props.showFirstLastPage ? {
icon: isRtl.value ? props.lastIcon : props.firstIcon,
onClick: e => setValue(e, start.value, 'first'),
disabled: prevDisabled,
'aria-label': t(props.firstAriaLabel),
'aria-disabled': prevDisabled
} : undefined,
prev: {
icon: isRtl.value ? props.nextIcon : props.prevIcon,
onClick: e => setValue(e, page.value - 1, 'prev'),
disabled: prevDisabled,
'aria-label': t(props.previousAriaLabel),
'aria-disabled': prevDisabled
},
next: {
icon: isRtl.value ? props.prevIcon : props.nextIcon,
onClick: e => setValue(e, page.value + 1, 'next'),
disabled: nextDisabled,
'aria-label': t(props.nextAriaLabel),
'aria-disabled': nextDisabled
},
last: props.showFirstLastPage ? {
icon: isRtl.value ? props.firstIcon : props.lastIcon,
onClick: e => setValue(e, start.value + length.value - 1, 'last'),
disabled: nextDisabled,
'aria-label': t(props.lastAriaLabel),
'aria-disabled': nextDisabled
} : undefined
};
});
function updateFocus() {
const currentIndex = page.value - start.value;
refs.value[currentIndex]?.$el.focus();
}
function onKeydown(e) {
if (e.key === keyValues.left && !props.disabled && page.value > +props.start) {
page.value = page.value - 1;
nextTick(updateFocus);
} else if (e.key === keyValues.right && !props.disabled && page.value < start.value + length.value - 1) {
page.value = page.value + 1;
nextTick(updateFocus);
}
}
useRender(() => _createVNode(props.tag, {
"ref": resizeRef,
"class": ['v-pagination', themeClasses.value, props.class],
"style": props.style,
"role": "navigation",
"aria-label": t(props.ariaLabel),
"onKeydown": onKeydown,
"data-test": "v-pagination-root"
}, {
default: () => [_createVNode("ul", {
"class": "v-pagination__list"
}, [props.showFirstLastPage && _createVNode("li", {
"key": "first",
"class": "v-pagination__first",
"data-test": "v-pagination-first"
}, [slots.first ? slots.first(controls.value.first) : _createVNode(VBtn, _mergeProps({
"_as": "VPaginationBtn"
}, controls.value.first), null)]), _createVNode("li", {
"key": "prev",
"class": "v-pagination__prev",
"data-test": "v-pagination-prev"
}, [slots.prev ? slots.prev(controls.value.prev) : _createVNode(VBtn, _mergeProps({
"_as": "VPaginationBtn"
}, controls.value.prev), null)]), items.value.map((item, index) => _createVNode("li", {
"key": item.key,
"class": ['v-pagination__item', {
'v-pagination__item--is-active': item.isActive
}],
"data-test": "v-pagination-item"
}, [slots.item ? slots.item(item) : _createVNode(VBtn, _mergeProps({
"_as": "VPaginationBtn"
}, item.props), {
default: () => [item.page]
})])), _createVNode("li", {
"key": "next",
"class": "v-pagination__next",
"data-test": "v-pagination-next"
}, [slots.next ? slots.next(controls.value.next) : _createVNode(VBtn, _mergeProps({
"_as": "VPaginationBtn"
}, controls.value.next), null)]), props.showFirstLastPage && _createVNode("li", {
"key": "last",
"class": "v-pagination__last",
"data-test": "v-pagination-last"
}, [slots.last ? slots.last(controls.value.last) : _createVNode(VBtn, _mergeProps({
"_as": "VPaginationBtn"
}, controls.value.last), null)])])]
}));
return {};
}
});
//# sourceMappingURL=VPagination.mjs.map