UNPKG

@kit-data-manager/pid-component

Version:

The PID-Component is a web component that can be used to evaluate and display FAIR Digital Objects, PIDs, ORCiDs, and possibly other identifiers in a user-friendly way. It is easily extensible to support other identifier types.

267 lines (266 loc) 14.6 kB
/*! * * Copyright 2024-2026 Karlsruhe Institute of Technology. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import { h } from "@stencil/core"; export class PidPagination { constructor() { this.currentPage = 0; this.totalItems = 0; this.itemsPerPage = 10; this.pageSizes = [5, 10, 25, 50, 100]; this.showItemsPerPageControl = true; this.darkMode = 'system'; this.handlePageChange = (page) => { if (page >= 0 && page <= this.totalPages - 1) { this.pageChange.emit(page); requestAnimationFrame(() => { const collapsible = this.el.closest('pid-collapsible'); if (collapsible && typeof collapsible.recalculateContentDimensions === 'function') { collapsible.recalculateContentDimensions(); } }); } }; this.handleItemsPerPageChange = (size) => { this.itemsPerPageChange.emit(size); requestAnimationFrame(() => { const collapsible = this.el.closest('pid-collapsible'); if (collapsible && typeof collapsible.recalculateContentDimensions === 'function') { collapsible.recalculateContentDimensions(); } }); }; } get totalPages() { return Math.max(1, Math.ceil(this.totalItems / this.itemsPerPage)); } get displayRange() { if (this.totalItems === 0) { return { start: 0, end: 0 }; } const start = this.currentPage * this.itemsPerPage + 1; const end = Math.min((this.currentPage + 1) * this.itemsPerPage, this.totalItems); return { start, end }; } render() { if (this.totalItems <= 0) { return null; } const visiblePages = this.getVisiblePageNumbers(); const needsPagination = this.totalItems > this.itemsPerPage; const isDarkMode = this.darkMode === 'dark' || (this.darkMode === 'system' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); const paginationId = `pagination-${Math.random().toString(36).substring(2, 11)}`; return (h("div", { class: `flex w-full resize-none flex-wrap items-center justify-between gap-2 ${isDarkMode ? 'bg-gray-800 text-gray-200' : 'bg-white text-gray-800'} px-3 text-sm`, role: "navigation", "aria-labelledby": `${paginationId}-label` }, h("span", { id: `${paginationId}-label`, class: "sr-only" }, "Pagination controls and display settings"), h("div", { class: `flex flex-wrap items-center gap-2 ${isDarkMode ? 'text-gray-300' : 'text-gray-600'}` }, this.showItemsPerPageControl && (h("div", { class: "flex items-center gap-1", role: "group", "aria-label": "Items per page options" }, h("span", { class: `text-xs whitespace-nowrap ${isDarkMode ? 'text-gray-300' : 'text-gray-600'}`, id: `${paginationId}-itemsperpage-label` }, "Items per page:"), h("div", { class: `flex items-center gap-0.5 rounded-sm border ${isDarkMode ? 'border-gray-600 bg-gray-700' : 'border-gray-200 bg-white'} p-0.5`, role: "toolbar", "aria-labelledby": `${paginationId}-itemsperpage-label` }, this.pageSizes.map(size => (h("button", { key: `size-${size}`, onClick: () => this.handleItemsPerPageChange(size), class: `resize-none rounded px-2 text-xs transition-colors ${this.itemsPerPage === size ? 'bg-blue-600 font-medium text-white py-0.5' : isDarkMode ? 'text-gray-200 hover:bg-gray-600 py-0' : 'text-gray-700 hover:bg-gray-100 py-0'}`, "aria-label": `Show ${size} items per page`, "aria-pressed": this.itemsPerPage === size ? 'true' : 'false', "aria-current": this.itemsPerPage === size ? 'true' : undefined, type: "button" }, size)))))), h("span", { class: `hidden text-xs whitespace-nowrap ${isDarkMode ? 'text-gray-300' : 'text-gray-600'} sm:block`, role: "status", "aria-live": "polite" }, "Showing ", this.displayRange.start, "-", this.displayRange.end, " of ", this.totalItems)), needsPagination && (h("div", { class: "flex items-center" }, h("nav", { class: "isolate inline-flex resize-none -space-x-px rounded-md shadow-xs", "aria-label": "Pagination", role: "navigation" }, h("button", { onClick: () => this.handlePageChange(this.currentPage - 1), disabled: this.currentPage === 0, class: `relative inline-flex resize-none items-center rounded-l-md px-2 py-0 ${isDarkMode ? 'text-gray-300 ring-1 ring-gray-600 ring-inset hover:bg-gray-700' : 'text-gray-500 ring-1 ring-gray-300 ring-inset hover:bg-gray-50'} focus:z-20 focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-500 disabled:cursor-not-allowed disabled:opacity-50`, "aria-label": "Previous page", title: "Go to previous page", type: "button" }, h("svg", { class: "h-4 w-4", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", role: "img" }, h("title", null, "Previous"), h("desc", null, "Arrow pointing to the left"), h("path", { "fill-rule": "evenodd", d: "M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06-.02z", "clip-rule": "evenodd" }))), visiblePages.map((page, i) => { if (page === '...') { return (h("span", { key: `ellipsis-${i}`, class: `relative inline-flex resize-none items-center px-2 py-0 text-sm rounded ${isDarkMode ? 'text-gray-300 ring-1 ring-gray-600 ring-inset' : 'text-gray-700 ring-1 ring-gray-300 ring-inset'}`, role: "separator", "aria-label": "More pages", "aria-hidden": "true" }, h("span", { "aria-hidden": "true" }, "..."), h("span", { class: "sr-only" }, "More pages"))); } const pageNum = page; const isCurrentPage = pageNum === this.currentPage; const humanPageNum = pageNum + 1; return (h("button", { key: `page-${pageNum}`, onClick: () => this.handlePageChange(pageNum), class: isCurrentPage ? 'relative z-10 inline-flex resize-none items-center rounded bg-blue-600 px-2 py-0.5 text-xs font-semibold text-white focus:z-20 focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600' : `relative inline-flex resize-none items-center rounded px-2 py-0 text-xs ${isDarkMode ? 'text-gray-200 ring-1 ring-gray-600 ring-inset hover:bg-gray-700' : 'text-gray-900 ring-1 ring-gray-300 ring-inset hover:bg-gray-50'} focus:z-20 focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-500`, "aria-label": `Page ${humanPageNum}`, "aria-current": isCurrentPage ? 'page' : undefined, type: "button", title: `Go to page ${humanPageNum}` }, humanPageNum)); }), h("button", { onClick: () => this.handlePageChange(this.currentPage + 1), disabled: this.currentPage >= this.totalPages - 1, class: `relative inline-flex resize-none items-center rounded-r-md px-2 py-0 rounded ${isDarkMode ? 'text-gray-300 ring-1 ring-gray-600 ring-inset hover:bg-gray-700' : 'text-gray-500 ring-1 ring-gray-300 ring-inset hover:bg-gray-50'} focus:z-20 focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-500 disabled:cursor-not-allowed disabled:opacity-50`, "aria-label": "Next page", title: "Go to next page", type: "button" }, h("svg", { class: "h-4 w-4", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", role: "img" }, h("title", null, "Next"), h("desc", null, "Arrow pointing to the right"), h("path", { "fill-rule": "evenodd", d: "M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z", "clip-rule": "evenodd" })))))))); } getVisiblePageNumbers() { const maxPages = 7; const pages = []; if (this.totalPages <= maxPages) { return Array.from({ length: this.totalPages }, (_, i) => i); } pages.push(0); let rangeStart = Math.max(1, this.currentPage - 1); let rangeEnd = Math.min(this.totalPages - 2, this.currentPage + 1); if (rangeEnd - rangeStart < 2) { if (this.currentPage < this.totalPages / 2) { rangeEnd = Math.min(this.totalPages - 2, rangeStart + 2); } else { rangeStart = Math.max(1, rangeEnd - 2); } } if (rangeStart > 1) { pages.push('...'); } for (let i = rangeStart; i <= rangeEnd; i++) { pages.push(i); } if (rangeEnd < this.totalPages - 2) { pages.push('...'); } pages.push(this.totalPages - 1); return pages; } static get is() { return "pid-pagination"; } static get properties() { return { "currentPage": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Current page (0-based index)" }, "getter": false, "setter": false, "reflect": false, "attribute": "current-page", "defaultValue": "0" }, "totalItems": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Total number of items" }, "getter": false, "setter": false, "reflect": false, "attribute": "total-items", "defaultValue": "0" }, "itemsPerPage": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Number of items per page" }, "getter": false, "setter": false, "reflect": false, "attribute": "items-per-page", "defaultValue": "10" }, "pageSizes": { "type": "unknown", "mutable": false, "complexType": { "original": "number[]", "resolved": "number[]", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Available page sizes" }, "getter": false, "setter": false, "defaultValue": "[5, 10, 25, 50, 100]" }, "showItemsPerPageControl": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Whether to show the items per page control" }, "getter": false, "setter": false, "reflect": false, "attribute": "show-items-per-page-control", "defaultValue": "true" }, "darkMode": { "type": "string", "mutable": false, "complexType": { "original": "'light' | 'dark' | 'system'", "resolved": "\"dark\" | \"light\" | \"system\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The dark mode setting for the component\nOptions: \"light\", \"dark\", \"system\"\nDefault: \"system\"" }, "getter": false, "setter": false, "reflect": false, "attribute": "dark-mode", "defaultValue": "'system'" } }; } static get events() { return [{ "method": "pageChange", "name": "pageChange", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event emitted when page changes" }, "complexType": { "original": "number", "resolved": "number", "references": {} } }, { "method": "itemsPerPageChange", "name": "itemsPerPageChange", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event emitted when items per page changes" }, "complexType": { "original": "number", "resolved": "number", "references": {} } }]; } static get elementRef() { return "el"; } } //# sourceMappingURL=pid-pagination.js.map