@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
JavaScript
/*!
*
* 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