@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
454 lines (453 loc) • 14 kB
JavaScript
/*!
* All material copyright ESRI, All Rights Reserved, unless otherwise specified.
* See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
* v1.5.0-next.4
*/
import { Fragment, h } from "@stencil/core";
import { componentLoaded, setComponentLoaded, setUpLoadableComponent } from "../../utils/loadable";
import { connectLocalized, disconnectLocalized, numberStringFormatter } from "../../utils/locale";
import { connectMessages, disconnectMessages, setUpMessages, updateMessages } from "../../utils/t9n";
import { CSS } from "./resources";
const maxPagesDisplayed = 5;
export class Pagination {
constructor() {
this.previousClicked = () => {
this.previousPage().then();
this.emitUpdate();
};
this.nextClicked = () => {
this.nextPage();
this.emitUpdate();
};
this.groupSeparator = false;
this.messageOverrides = undefined;
this.pageSize = 20;
this.numberingSystem = undefined;
this.startItem = 1;
this.totalItems = 0;
this.scale = "m";
this.defaultMessages = undefined;
this.effectiveLocale = "";
this.messages = undefined;
}
onMessagesChange() {
/* wired up by t9n util */
}
effectiveLocaleChange() {
updateMessages(this, this.effectiveLocale);
}
effectiveLocaleWatcher() {
numberStringFormatter.numberFormatOptions = {
locale: this.effectiveLocale,
numberingSystem: this.numberingSystem,
useGrouping: this.groupSeparator
};
}
// --------------------------------------------------------------------------
//
// Lifecycle
//
// --------------------------------------------------------------------------
connectedCallback() {
connectLocalized(this);
connectMessages(this);
}
async componentWillLoad() {
await setUpMessages(this);
setUpLoadableComponent(this);
}
componentDidLoad() {
setComponentLoaded(this);
}
disconnectedCallback() {
disconnectLocalized(this);
disconnectMessages(this);
}
// --------------------------------------------------------------------------
//
// Public Methods
//
// --------------------------------------------------------------------------
/** Sets focus on the component's first focusable element. */
async setFocus() {
await componentLoaded(this);
this.el.focus();
}
/** Go to the next page of results. */
async nextPage() {
this.startItem = Math.min(this.getLastStart(), this.startItem + this.pageSize);
}
/** Go to the previous page of results. */
async previousPage() {
this.startItem = Math.max(1, this.startItem - this.pageSize);
}
// --------------------------------------------------------------------------
//
// Private Methods
//
// --------------------------------------------------------------------------
getLastStart() {
const { totalItems, pageSize } = this;
const lastStart = totalItems % pageSize === 0
? totalItems - pageSize
: Math.floor(totalItems / pageSize) * pageSize;
return lastStart + 1;
}
showLeftEllipsis() {
return Math.floor(this.startItem / this.pageSize) > 3;
}
showRightEllipsis() {
return (this.totalItems - this.startItem) / this.pageSize > 3;
}
emitUpdate() {
this.calcitePaginationChange.emit();
}
//--------------------------------------------------------------------------
//
// Render Methods
//
//--------------------------------------------------------------------------
renderPages() {
const lastStart = this.getLastStart();
let end;
let nextStart;
// if we don't need ellipses render the whole set
if (this.totalItems / this.pageSize <= maxPagesDisplayed) {
nextStart = 1 + this.pageSize;
end = lastStart - this.pageSize;
}
else {
// if we're within max pages of page 1
if (this.startItem / this.pageSize < maxPagesDisplayed - 1) {
nextStart = 1 + this.pageSize;
end = 1 + 4 * this.pageSize;
}
else {
// if we're within max pages of last page
if (this.startItem + 3 * this.pageSize >= this.totalItems) {
nextStart = lastStart - 4 * this.pageSize;
end = lastStart - this.pageSize;
}
else {
nextStart = this.startItem - this.pageSize;
end = this.startItem + this.pageSize;
}
}
}
const pages = [];
while (nextStart <= end) {
pages.push(nextStart);
nextStart = nextStart + this.pageSize;
}
return pages.map((page) => this.renderPage(page));
}
renderPage(start) {
const page = Math.floor(start / this.pageSize) + (this.pageSize === 1 ? 0 : 1);
numberStringFormatter.numberFormatOptions = {
locale: this.effectiveLocale,
numberingSystem: this.numberingSystem,
useGrouping: this.groupSeparator
};
const displayedPage = numberStringFormatter.localize(page.toString());
const selected = start === this.startItem;
return (h("button", { "aria-current": selected ? "page" : "false", class: {
[CSS.page]: true,
[CSS.selected]: selected
}, onClick: () => {
this.startItem = start;
this.emitUpdate();
} }, displayedPage));
}
renderLeftEllipsis() {
if (this.totalItems / this.pageSize > maxPagesDisplayed && this.showLeftEllipsis()) {
return h("span", { class: `${CSS.ellipsis} ${CSS.ellipsisStart}` }, "\u2026");
}
}
renderRightEllipsis() {
if (this.totalItems / this.pageSize > maxPagesDisplayed && this.showRightEllipsis()) {
return h("span", { class: `${CSS.ellipsis} ${CSS.ellipsisEnd}` }, "\u2026");
}
}
render() {
const { totalItems, pageSize, startItem } = this;
const prevDisabled = pageSize === 1 ? startItem <= pageSize : startItem < pageSize;
const nextDisabled = pageSize === 1 ? startItem + pageSize > totalItems : startItem + pageSize > totalItems;
return (h(Fragment, null, h("button", { "aria-label": this.messages.previous, class: {
[CSS.previous]: true,
[CSS.disabled]: prevDisabled
}, disabled: prevDisabled, onClick: this.previousClicked }, h("calcite-icon", { flipRtl: true, icon: "chevronLeft", scale: this.scale === "l" ? "m" : "s" })), totalItems > pageSize ? this.renderPage(1) : null, this.renderLeftEllipsis(), this.renderPages(), this.renderRightEllipsis(), this.renderPage(this.getLastStart()), h("button", { "aria-label": this.messages.next, class: {
[CSS.next]: true,
[CSS.disabled]: nextDisabled
}, disabled: nextDisabled, onClick: this.nextClicked }, h("calcite-icon", { flipRtl: true, icon: "chevronRight", scale: this.scale === "l" ? "m" : "s" }))));
}
static get is() { return "calcite-pagination"; }
static get encapsulation() { return "shadow"; }
static get delegatesFocus() { return true; }
static get originalStyleUrls() {
return {
"$": ["pagination.scss"]
};
}
static get styleUrls() {
return {
"$": ["pagination.css"]
};
}
static get assetsDirs() { return ["assets"]; }
static get properties() {
return {
"groupSeparator": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "When `true`, number values are displayed with a group separator corresponding to the language and country format."
},
"attribute": "group-separator",
"reflect": true,
"defaultValue": "false"
},
"messageOverrides": {
"type": "unknown",
"mutable": true,
"complexType": {
"original": "Partial<PaginationMessages>",
"resolved": "{ next?: string; previous?: string; }",
"references": {
"Partial": {
"location": "global"
},
"PaginationMessages": {
"location": "import",
"path": "./assets/pagination/t9n"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Use this property to override individual strings used by the component."
}
},
"pageSize": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Specifies the number of items per page."
},
"attribute": "page-size",
"reflect": true,
"defaultValue": "20"
},
"numberingSystem": {
"type": "string",
"mutable": false,
"complexType": {
"original": "NumberingSystem",
"resolved": "\"arab\" | \"arabext\" | \"bali\" | \"beng\" | \"deva\" | \"fullwide\" | \"gujr\" | \"guru\" | \"hanidec\" | \"khmr\" | \"knda\" | \"laoo\" | \"latn\" | \"limb\" | \"mlym\" | \"mong\" | \"mymr\" | \"orya\" | \"tamldec\" | \"telu\" | \"thai\" | \"tibt\"",
"references": {
"NumberingSystem": {
"location": "import",
"path": "../../utils/locale"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Specifies the Unicode numeral system used by the component for localization."
},
"attribute": "numbering-system",
"reflect": false
},
"startItem": {
"type": "number",
"mutable": true,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Specifies the starting item number."
},
"attribute": "start-item",
"reflect": true,
"defaultValue": "1"
},
"totalItems": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Specifies the total number of items."
},
"attribute": "total-items",
"reflect": true,
"defaultValue": "0"
},
"scale": {
"type": "string",
"mutable": false,
"complexType": {
"original": "Scale",
"resolved": "\"l\" | \"m\" | \"s\"",
"references": {
"Scale": {
"location": "import",
"path": "../interfaces"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Specifies the size of the component."
},
"attribute": "scale",
"reflect": true,
"defaultValue": "\"m\""
},
"messages": {
"type": "unknown",
"mutable": true,
"complexType": {
"original": "PaginationMessages",
"resolved": "{ next: string; previous: string; }",
"references": {
"PaginationMessages": {
"location": "import",
"path": "./assets/pagination/t9n"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [{
"name": "internal",
"text": undefined
}],
"text": "Made into a prop for testing purposes only"
}
}
};
}
static get states() {
return {
"defaultMessages": {},
"effectiveLocale": {}
};
}
static get events() {
return [{
"method": "calcitePaginationChange",
"name": "calcitePaginationChange",
"bubbles": true,
"cancelable": false,
"composed": true,
"docs": {
"tags": [],
"text": "Emits when the selected page changes."
},
"complexType": {
"original": "void",
"resolved": "void",
"references": {}
}
}];
}
static get methods() {
return {
"setFocus": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Sets focus on the component's first focusable element.",
"tags": []
}
},
"nextPage": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Go to the next page of results.",
"tags": []
}
},
"previousPage": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Go to the previous page of results.",
"tags": []
}
}
};
}
static get elementRef() { return "el"; }
static get watchers() {
return [{
"propName": "messageOverrides",
"methodName": "onMessagesChange"
}, {
"propName": "effectiveLocale",
"methodName": "effectiveLocaleChange"
}, {
"propName": "effectiveLocale",
"methodName": "effectiveLocaleWatcher"
}];
}
}