UNPKG

bootstrap-vue-next

Version:

Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development

440 lines (439 loc) 16 kB
import { z as useToNumber } from "./dist-B10a-gZ8.mjs"; import { n as getActiveElement } from "./dom-AhkaSoh8.mjs"; import { t as useDefaults } from "./useDefaults-BKgBaqOV.mjs"; import { n as BvEvent } from "./classes-B0E5Y78Y.mjs"; import "./constants-BSIK14yA.mjs"; import "./src/types/index.mjs"; import { t as useAlignment } from "./useAlignment-BiCREohQ.mjs"; import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, defineComponent, mergeModels, mergeProps, nextTick, normalizeClass, openBlock, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useModel, useTemplateRef, watch, withCtx } from "vue"; //#region src/components/BPagination/BPagination.vue?vue&type=script&setup=true&lang.ts var _hoisted_1 = ["aria-disabled", "aria-label"]; var _hoisted_2 = ["displayIndex"]; var DEFAULT_PER_PAGE = 20; var DEFAULT_TOTAL_ROWS = 0; //#endregion //#region src/components/BPagination/BPagination.vue var BPagination_default = /* @__PURE__ */ defineComponent({ __name: "BPagination", props: /* @__PURE__ */ mergeModels({ align: { default: "start" }, ariaControls: { default: void 0 }, ariaLabel: { default: "Pagination" }, disabled: { type: Boolean, default: false }, ellipsisClass: { default: void 0 }, ellipsisText: { default: "…" }, firstClass: { default: void 0 }, firstNumber: { type: Boolean, default: false }, firstText: { default: "«" }, noEllipsis: { type: Boolean, default: false }, noGotoEndButtons: { type: Boolean, default: false }, labelFirstPage: { default: "Go to first page" }, labelLastPage: { default: "Go to last page" }, labelNextPage: { default: "Go to next page" }, labelPage: { default: "Go to page" }, labelPrevPage: { default: "Go to previous page" }, lastClass: { default: void 0 }, lastNumber: { type: Boolean, default: false }, lastText: { default: "»" }, limit: { default: 5 }, nextClass: { default: void 0 }, nextText: { default: "›" }, pageClass: { default: void 0 }, perPage: { default: DEFAULT_PER_PAGE }, pills: { type: Boolean, default: false }, prevClass: { default: void 0 }, prevText: { default: "‹" }, size: { default: void 0 }, totalRows: { default: DEFAULT_TOTAL_ROWS } }, { "modelValue": { default: 1 }, "modelModifiers": {} }), emits: /* @__PURE__ */ mergeModels(["page-click"], ["update:modelValue"]), setup(__props, { emit: __emit }) { const ELLIPSIS_THRESHOLD = 3; const FIRST_BUTTON = -1; const PREV_BUTTON = -2; const NEXT_BUTTON = -3; const LAST_BUTTON = -4; const FIRST_ELLIPSIS = -5; const LAST_ELLIPSIS = -6; const props = useDefaults(__props, "BPagination"); const emit = __emit; const modelValue = useModel(__props, "modelValue"); const pageElements = useTemplateRef("_pageElements"); const limitNumber = useToNumber(() => props.limit, { nanToZero: true, method: "parseInt" }); const perPageNumber = useToNumber(() => props.perPage, { nanToZero: true, method: "parseInt" }); const totalRowsNumber = useToNumber(() => props.totalRows, { nanToZero: true, method: "parseInt" }); const modelValueNumber = useToNumber(modelValue, { nanToZero: true, method: "parseInt" }); const perPageSanitized = computed(() => Math.max(perPageNumber.value || DEFAULT_PER_PAGE, 1)); const totalRowsSanitized = computed(() => Math.max(totalRowsNumber.value || DEFAULT_TOTAL_ROWS, 0)); const numberOfPages = computed(() => Math.ceil(totalRowsSanitized.value / perPageSanitized.value)); const computedFill = computed(() => props.align === "fill"); const alignment = useAlignment(computed(() => props.align === "fill" ? "start" : props.align)); const isActivePage = (pageNumber) => pageNumber === computedModelValue.value; const getTabIndex = (num) => props.disabled ? null : isActivePage(num) ? "0" : "-1"; const checkDisabled = (num) => props.disabled || isActivePage(num) || computedModelValue.value < 1 || num < 1 || num > numberOfPages.value; const firstDisabled = computed(() => checkDisabled(1)); const prevDisabled = computed(() => checkDisabled(computedModelValue.value - 1)); const lastDisabled = computed(() => checkDisabled(numberOfPages.value)); const nextDisabled = computed(() => checkDisabled(computedModelValue.value + 1)); const getBaseButtonProps = ({ page, classVal, disabled, slotName, textValue, tabIndex, label, position, isActive, hidden, isSmHidden }) => ({ li: { "class": [ "page-item", { "active": isActive, disabled, "bv-d-sm-down-none": isSmHidden, "flex-fill": computedFill.value, "d-flex": computedFill.value && !disabled }, classVal ], "role": "presentation", "aria-hidden": hidden }, button: { "is": disabled ? "span" : "button", "class": [ "page-link", "text-center", { "flex-grow-1": !disabled && computedFill.value } ], "aria-label": label, "aria-controls": props.ariaControls || void 0, "aria-disabled": disabled ? true : void 0, "aria-posinset": position, "aria-setsize": position ? numberOfPages.value : void 0, "role": "menuitem", "type": disabled ? void 0 : "button", "tabindex": disabled ? void 0 : tabIndex }, text: { name: slotName, active: isActive, value: textValue ?? page, page, disabled, index: page - 1, content: textValue ? void 0 : String(page) }, clickHandler: (e) => pageClick(e, page) }); const getButtonProps = ({ page, classVal, disabled, slotName, textValue, label }) => getBaseButtonProps({ page, classVal, disabled, slotName, textValue, label, tabIndex: "-1" }); const getPageButtonProps = (page, isSmHidden) => getBaseButtonProps({ page, disabled: props.disabled, classVal: props.pageClass, slotName: "page", label: props.labelPage ? `${props.labelPage} ${page}` : void 0, tabIndex: getTabIndex(page) ?? void 0, position: page, isActive: isActivePage(page), isSmHidden }); const firstButtonProps = computed(() => getButtonProps({ page: 1, disabled: firstDisabled.value, classVal: props.firstClass, slotName: "first-text", textValue: props.firstText, label: props.labelFirstPage })); const prevButtonProps = computed(() => getButtonProps({ page: Math.max(computedModelValue.value - 1, 1), disabled: prevDisabled.value, classVal: props.prevClass, slotName: "prev-text", textValue: props.prevText, label: props.labelPrevPage })); const nextButtonProps = computed(() => getButtonProps({ page: Math.min(computedModelValue.value + 1, numberOfPages.value), disabled: nextDisabled.value, classVal: props.nextClass, slotName: "next-text", textValue: props.nextText, label: props.labelNextPage })); const lastButtonProps = computed(() => getButtonProps({ page: numberOfPages.value, disabled: lastDisabled.value, classVal: props.lastClass, slotName: "last-text", textValue: props.lastText, label: props.labelLastPage })); const ellipsisProps = computed(() => ({ li: { class: [ "page-item", "disabled", "text-center", "bv-d-sm-down-none", computedFill.value ? "flex-fill" : "", props.ellipsisClass ], role: "separator" }, span: { class: ["page-link"] } })); const computedWrapperClasses = computed(() => [alignment.value, { [`pagination-${props.size}`]: props.size !== void 0, "b-pagination-pills": props.pills }]); const pagination = computed(() => ({ pageSize: perPageSanitized.value, totalRows: totalRowsNumber.value, numberOfPages: numberOfPages.value })); const pageClick = (event, pageNumber) => { if (pageNumber === computedModelValue.value) return; const clickEvent = new BvEvent("page-click", { cancelable: true, target: event.target }); emit("page-click", clickEvent, pageNumber); if (clickEvent.defaultPrevented) return; modelValue.value = pageNumber; nextTick(() => { if (pageNumber === 1) focusFirst(); else if (pageNumber === pagination.value.numberOfPages) focusLast(); }); }; const isDisabled = (el) => { const isElement = el && el.nodeType === Node.ELEMENT_NODE; const hasAttr = isElement ? el.hasAttribute("disabled") : null; const hasClass = isElement && el.classList ? el.classList.contains("disabled") : false; return !isElement || el.disabled || hasAttr || hasClass; }; const getButtons = () => [...pageElements.value ?? []].sort((a, b) => Number.parseInt(a.getAttribute("displayIndex") || "0") - Number.parseInt(b.getAttribute("displayIndex") || "0")).map((page) => page.children[0]).filter((el) => { if (el?.getAttribute("display") === "none" || el?.tagName.toUpperCase() !== "BUTTON") return false; const bcr = el?.getBoundingClientRect(); return !!(bcr && bcr.height > 0 && bcr.width > 0); }).map((el) => el); const focusFirst = () => { nextTick(() => { getButtons().find((el) => !isDisabled(el))?.focus(); }); }; const focusPrev = () => { nextTick(() => { const buttons = getButtons(); const index = buttons.indexOf(getActiveElement()); const button = buttons[index - 1]; if (index > 0 && button !== void 0 && !isDisabled(button)) buttons[index - 1]?.focus(); }); }; const focusLast = () => { nextTick(() => { getButtons().reverse().find((el) => !isDisabled(el))?.focus(); }); }; const focusNext = () => { nextTick(() => { const buttons = getButtons(); const index = buttons.indexOf(getActiveElement()); const button = buttons[index + 1]; if (index < buttons.length - 1 && button !== void 0 && !isDisabled(button)) buttons[index + 1]?.focus(); }); }; const handleKeyNav = (event) => { const { code, shiftKey } = event; if (code === "ArrowLeft" || code === "ArrowUp") { event.preventDefault(); if (shiftKey) focusFirst(); else focusPrev(); } else if (code === "ArrowRight" || code === "ArrowDown") { event.preventDefault(); if (shiftKey) focusLast(); else focusNext(); } }; const computedModelValue = computed(() => { const page = modelValueNumber.value || 1; return page > numberOfPages.value ? numberOfPages.value : page < 1 ? 1 : page; }); watch(pagination, (oldValue, newValue) => { if (newValue.pageSize !== oldValue.pageSize && newValue.totalRows === oldValue.totalRows) modelValue.value = 1; }); const noFirstButton = computed(() => props.noGotoEndButtons && !props.firstNumber ? 1 : 0); const noLastButton = computed(() => props.noGotoEndButtons && !props.lastNumber ? 1 : 0); const showFirstButton = computed(() => noFirstButton.value ? 0 : 1); const showLastButton = computed(() => noLastButton.value ? 0 : 1); const firstPage = computed(() => props.firstNumber ? 1 : 0); const lastPage = computed(() => props.lastNumber ? 1 : 0); const halfLimit = computed(() => Math.floor(limitNumber.value / 2)); const pages = computed(() => { const { value } = computedModelValue; const els = elements.value.map((p) => { switch (p) { case FIRST_BUTTON: return { id: p, ...firstButtonProps.value }; case PREV_BUTTON: return { id: p, ...prevButtonProps.value }; case NEXT_BUTTON: return { id: p, ...nextButtonProps.value }; case LAST_BUTTON: return { id: p, ...lastButtonProps.value }; case FIRST_ELLIPSIS: case LAST_ELLIPSIS: return { id: p, ...ellipsisProps.value }; default: return { id: p, ...getPageButtonProps(p) }; } }); if (numberOfPages.value > 3) { if (value > numberOfPages.value - halfLimit.value - lastPage.value) { const idx = 2 + showFirstButton.value; const el = els[idx]; if (el !== void 0) els[idx] = { id: el.id, ...getPageButtonProps(el.id, true) }; } if (value <= halfLimit.value + firstPage.value) { const idx = els.length - (3 + showLastButton.value); const el = els[idx]; if (el !== void 0) els[idx] = { id: el.id, ...getPageButtonProps(el.id, true) }; } } return els; }); const elements = computed(() => { const pages = numberOfPages.value; const { value } = computedModelValue; const limit = limitNumber.value; const noEllipsis = props.noEllipsis || limit <= ELLIPSIS_THRESHOLD; if (pages < limit + firstPage.value + lastPage.value) return [ !firstPage.value && !noFirstButton.value ? FIRST_BUTTON : null, PREV_BUTTON, ...Array.from({ length: pages }, (_, index) => index + 1), NEXT_BUTTON, !lastPage.value && !noLastButton.value ? LAST_BUTTON : null ].filter((x) => x !== null); const buttons = Array.from({ length: limit + 4 - (noFirstButton.value + noLastButton.value) }); if (!noFirstButton.value) if (!firstPage.value) { buttons[0] = FIRST_BUTTON; buttons[1] = PREV_BUTTON; } else { buttons[0] = PREV_BUTTON; buttons[1] = 1; } else buttons[0] = PREV_BUTTON; if (!noLastButton.value) if (!lastPage.value) { buttons[buttons.length - 1] = LAST_BUTTON; buttons[buttons.length - 2] = NEXT_BUTTON; } else { buttons[buttons.length - 1] = NEXT_BUTTON; buttons[buttons.length - 2] = pages; } else buttons[buttons.length - 1] = NEXT_BUTTON; if (value <= halfLimit.value + firstPage.value) { for (let index = 1; index <= limit; index++) buttons[index + 1 - noFirstButton.value] = index + firstPage.value; if (!noEllipsis) buttons[buttons.length - (2 + showLastButton.value)] = LAST_ELLIPSIS; } if (value > pages - halfLimit.value - lastPage.value) { const start = pages - (limit - 1) - lastPage.value; for (let index = 0; index < limit; index++) buttons[index + 2 - noFirstButton.value] = start + index; if (!noEllipsis) buttons[1 + showFirstButton.value] = FIRST_ELLIPSIS; } if (!buttons[2]) { const start = value - Math.floor(limit / 2); for (let index = 0; index < limit; index++) buttons[index + 2 - noFirstButton.value] = start + index; if (!noEllipsis) { buttons[1 + showFirstButton.value] = FIRST_ELLIPSIS; buttons[buttons.length - (2 + showLastButton.value)] = LAST_ELLIPSIS; } } return buttons.filter((x) => x !== null); }); return (_ctx, _cache) => { return openBlock(), createElementBlock("ul", { class: normalizeClass(["pagination", computedWrapperClasses.value]), role: "menubar", "aria-disabled": unref(props).disabled, "aria-label": unref(props).ariaLabel || void 0, onKeydown: handleKeyNav }, [(openBlock(true), createElementBlock(Fragment, null, renderList(pages.value, (page, index) => { return openBlock(), createElementBlock("li", mergeProps({ key: `page-${page.id}` }, { ref_for: true }, page.li, { ref_for: true, ref: "_pageElements", displayIndex: index }), [page.id === FIRST_ELLIPSIS || page.id === LAST_ELLIPSIS ? (openBlock(), createElementBlock("span", mergeProps({ key: 0, ref_for: true }, ellipsisProps.value.span), [renderSlot(_ctx.$slots, "ellipsis-text", {}, () => [createTextVNode(toDisplayString(unref(props).ellipsisText || "..."), 1)])], 16)) : "button" in page ? (openBlock(), createBlock(resolveDynamicComponent(page.button.is), mergeProps({ key: 1, ref_for: true }, page.button, { onClick: page.clickHandler }), { default: withCtx(() => [renderSlot(_ctx.$slots, page.text.name, { disabled: page.text.disabled, page: page.text.page, index: page.text.index, active: page.text.active ?? false, content: page.text.value }, () => [createTextVNode(toDisplayString(page.text.value), 1)])]), _: 2 }, 1040, ["onClick"])) : createCommentVNode("", true)], 16, _hoisted_2); }), 128))], 42, _hoisted_1); }; } }); //#endregion export { BPagination_default as t }; //# sourceMappingURL=BPagination-CvoSN1He.mjs.map