UNPKG

@trimble-oss/moduswebcomponents

Version:

Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust

291 lines (290 loc) 13.2 kB
import { h, } from "@stencil/core"; import { inheritAriaAttributes } from "../utils"; import { convertPropsToClasses } from "./modus-wc-pagination.tailwind"; import { ChevronDoubleLeftSolidIcon } from "../../icons/chevron-double-left-solid.icon"; import { ChevronDoubleRightSolidIcon } from "../../icons/chevron-double-right-solid.icon"; import { ChevronLeftSolidIcon } from "../../icons/chevron-left-solid.icon"; import { ChevronRightSolidIcon } from "../../icons/chevron-right-solid.icon"; /** * Pagination component to navigate through pages of content */ export class ModusWcPagination { constructor() { this.inheritedAttributes = {}; this.maxVisibleButtons = 5; /** Total number of pages */ this.count = 1; /** Custom CSS class to apply */ this.customClass = ''; /** The current page number */ this.page = 1; /** Size of the pagination buttons */ this.size = 'md'; /** Internal state to track visible page numbers */ this.visiblePages = []; this.handlePageClick = (newPage) => { if (newPage === this.page || newPage < 1 || newPage > this.count) { return; } this.pageChange.emit({ newPage, prevPage: this.page }); this.page = newPage; }; } // Creates a sliding "window" of page buttons that tries to keep the current page centered when possible. calculateVisiblePages() { const pages = []; // Calculates how many page buttons should ideally appear on each side of current page. const halfVisible = Math.floor(this.maxVisibleButtons / 2); let startPage = Math.max(1, this.page - halfVisible); let endPage = Math.min(this.count, startPage + this.maxVisibleButtons - 1); // Handles edge case when near end of the page count. // If we can't fit enough buttons after current page, then shift window left. if (endPage - startPage + 1 < this.maxVisibleButtons) { startPage = Math.max(1, endPage - this.maxVisibleButtons + 1); } for (let i = startPage; i <= endPage; i++) { pages.push(i); } this.visiblePages = pages; } componentWillLoad() { this.calculateVisiblePages(); this.inheritedAttributes = inheritAriaAttributes(this.el); } getClasses() { const buttonClassList = [ 'modus-wc-pagination-btn', 'modus-wc-join-item', 'modus-wc-btn', 'modus-wc-btn-square', ]; const paginationClassList = ['modus-wc-pagination', 'modus-wc-join']; // The order CSS classes are added matters to CSS specificity if (this.customClass) paginationClassList.push(this.customClass); const paginationClasses = paginationClassList.join(' '); const propClasses = convertPropsToClasses({ size: this.size }); if (propClasses) buttonClassList.push(propClasses); const buttonClasses = buttonClassList.join(' '); return { paginationClasses, buttonClasses }; } render() { var _a, _b, _c, _d, _e; const { paginationClasses, buttonClasses } = this.getClasses(); const isFirstPage = this.page === 1; const isLastPage = this.page === this.count; const shouldShowFirstLastButtons = this.count > this.maxVisibleButtons; // Default aria values if not provided const ariaLabels = { firstPage: ((_a = this.ariaLabelValues) === null || _a === void 0 ? void 0 : _a.firstPage) || 'First page', lastPage: ((_b = this.ariaLabelValues) === null || _b === void 0 ? void 0 : _b.lastPage) || 'Last page', nextPage: ((_c = this.ariaLabelValues) === null || _c === void 0 ? void 0 : _c.nextPage) || 'Next page', page: ((_d = this.ariaLabelValues) === null || _d === void 0 ? void 0 : _d.page) || 'Page {0}', previousPage: ((_e = this.ariaLabelValues) === null || _e === void 0 ? void 0 : _e.previousPage) || 'Previous page', }; return (h("div", Object.assign({ key: 'a98ee63c53970988224d69574f8caef0a18e83c8', class: paginationClasses }, this.inheritedAttributes), shouldShowFirstLastButtons && (h("button", { key: '60f632a86371057be72603418ff9484579002849', "aria-label": ariaLabels.firstPage, class: buttonClasses, disabled: isFirstPage, onClick: () => this.handlePageClick(1) }, h(ChevronDoubleLeftSolidIcon, { key: '28d4d49215b91ce731bc5995a63fdacc64508b85', className: "modus-wc-pagination-icon" }))), h("button", { key: '964764254784345bd0631658c2d9a1b76714c93d', "aria-label": this.prevButtonText ? undefined : ariaLabels.previousPage, class: `${buttonClasses} ${this.prevButtonText ? 'modus-wc-pagination-button-text' : ''}`, disabled: isFirstPage, onClick: () => this.handlePageClick(this.page - 1) }, this.prevButtonText ? (h("span", null, this.prevButtonText)) : (h(ChevronLeftSolidIcon, { className: "modus-wc-pagination-icon" }))), this.visiblePages.map((page) => (h("button", { "aria-current": this.page === page ? 'page' : undefined, "aria-label": ariaLabels.page.replace('{0}', page.toString()), class: `${buttonClasses} ${this.page === page ? 'modus-wc-btn-active' : ''}`, onClick: () => this.handlePageClick(page) }, page))), h("button", { key: 'f4554c62d1e20b95e324b73b223a1a6b2ad1eaf2', "aria-label": this.nextButtonText ? undefined : ariaLabels.nextPage, class: `${buttonClasses} ${this.nextButtonText ? 'modus-wc-pagination-button-text' : ''}`, disabled: isLastPage, onClick: () => this.handlePageClick(this.page + 1) }, this.nextButtonText ? (h("span", null, this.nextButtonText)) : (h(ChevronRightSolidIcon, { className: "modus-wc-pagination-icon" }))), shouldShowFirstLastButtons && (h("button", { key: 'f725c5b939a5340637304c34ff260c51a6cbd5cd', "aria-label": ariaLabels.lastPage, class: buttonClasses, disabled: isLastPage, onClick: () => this.handlePageClick(this.count) }, h(ChevronDoubleRightSolidIcon, { key: 'b133e57a7633ed14304db9bd3c89c50f98cb33d2', className: "modus-wc-pagination-icon" }))))); } static get is() { return "modus-wc-pagination"; } static get originalStyleUrls() { return { "$": ["modus-wc-pagination.scss"] }; } static get styleUrls() { return { "$": ["modus-wc-pagination.css"] }; } static get properties() { return { "ariaLabelValues": { "type": "unknown", "attribute": "aria-label-values", "mutable": false, "complexType": { "original": "IAriaLabelValues", "resolved": "IAriaLabelValues | undefined", "references": { "IAriaLabelValues": { "location": "local", "path": "/home/runner/work/modus-wc-2.0/modus-wc-2.0/src/components/modus-wc-pagination/modus-wc-pagination.tsx", "id": "src/components/modus-wc-pagination/modus-wc-pagination.tsx::IAriaLabelValues" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Aria label values for pagination buttons" }, "getter": false, "setter": false }, "count": { "type": "number", "attribute": "count", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Total number of pages" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "1" }, "customClass": { "type": "string", "attribute": "custom-class", "mutable": false, "complexType": { "original": "string", "resolved": "string | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Custom CSS class to apply" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "''" }, "nextButtonText": { "type": "string", "attribute": "next-button-text", "mutable": false, "complexType": { "original": "string", "resolved": "string | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The next page button text. If not set, an icon control will be used." }, "getter": false, "setter": false, "reflect": false }, "page": { "type": "number", "attribute": "page", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The current page number" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "1" }, "prevButtonText": { "type": "string", "attribute": "prev-button-text", "mutable": false, "complexType": { "original": "string", "resolved": "string | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The previous page button text. If not set, an icon control will be used." }, "getter": false, "setter": false, "reflect": false }, "size": { "type": "string", "attribute": "size", "mutable": false, "complexType": { "original": "ModusSize", "resolved": "\"lg\" | \"md\" | \"sm\"", "references": { "ModusSize": { "location": "import", "path": "../types", "id": "src/components/types.ts::ModusSize" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Size of the pagination buttons" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "'md'" } }; } static get states() { return { "visiblePages": {} }; } static get events() { return [{ "method": "pageChange", "name": "pageChange", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event emitted when page changes" }, "complexType": { "original": "IPageChange", "resolved": "IPageChange", "references": { "IPageChange": { "location": "local", "path": "/home/runner/work/modus-wc-2.0/modus-wc-2.0/src/components/modus-wc-pagination/modus-wc-pagination.tsx", "id": "src/components/modus-wc-pagination/modus-wc-pagination.tsx::IPageChange" } } } }]; } static get elementRef() { return "el"; } static get watchers() { return [{ "propName": "page", "methodName": "calculateVisiblePages" }, { "propName": "count", "methodName": "calculateVisiblePages" }]; } }