mn-angular-lib 1.0.112 → 1.0.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -5175,6 +5175,14 @@ class MnCollectionBase {
|
|
|
5175
5175
|
if (this.dataSource.labels.rowsPerPageKey) {
|
|
5176
5176
|
this.dataSource.labels.rowsPerPage = this.lang.t(this.dataSource.labels.rowsPerPageKey);
|
|
5177
5177
|
}
|
|
5178
|
+
// Resolved without params so the `{{current}}` / `{{start}}` placeholders
|
|
5179
|
+
// survive; MnCollectionPagination fills them in per render.
|
|
5180
|
+
if (this.dataSource.labels.pageIndicatorKey) {
|
|
5181
|
+
this.dataSource.labels.pageIndicator = this.lang.t(this.dataSource.labels.pageIndicatorKey);
|
|
5182
|
+
}
|
|
5183
|
+
if (this.dataSource.labels.itemRangeKey) {
|
|
5184
|
+
this.dataSource.labels.itemRange = this.lang.t(this.dataSource.labels.itemRangeKey);
|
|
5185
|
+
}
|
|
5178
5186
|
}
|
|
5179
5187
|
}
|
|
5180
5188
|
// ── Shared internals ──
|
|
@@ -5351,12 +5359,72 @@ class MnCollectionPagination {
|
|
|
5351
5359
|
get showPagination() {
|
|
5352
5360
|
return this.isPaginated && (this.totalPages > 1 || this.isServerPaginated);
|
|
5353
5361
|
}
|
|
5362
|
+
/** First item number on the current page, 1-based. Zero when there is no data. */
|
|
5363
|
+
get rangeStart() {
|
|
5364
|
+
return this.totalItemCount === 0 ? 0 : (this.currentPage - 1) * this.pageSize + 1;
|
|
5365
|
+
}
|
|
5366
|
+
/** Last item number on the current page, clamped to the total. */
|
|
5367
|
+
get rangeEnd() {
|
|
5368
|
+
return Math.min(this.currentPage * this.pageSize, this.totalItemCount);
|
|
5369
|
+
}
|
|
5370
|
+
/**
|
|
5371
|
+
* {@link visiblePages} anchored with the first and last page, so the total page
|
|
5372
|
+
* count is on screen at md+ without consulting the readout.
|
|
5373
|
+
*
|
|
5374
|
+
* e.g. page 5 of 50 → `1 … 4 5 6 … 50`
|
|
5375
|
+
*/
|
|
5376
|
+
get pageSlots() {
|
|
5377
|
+
const pages = this.visiblePages;
|
|
5378
|
+
if (pages.length === 0)
|
|
5379
|
+
return [];
|
|
5380
|
+
const first = pages[0];
|
|
5381
|
+
const last = pages[pages.length - 1];
|
|
5382
|
+
const slots = pages.map(page => ({ page, anchor: false }));
|
|
5383
|
+
if (first > 1) {
|
|
5384
|
+
// Only insert a gap when the anchor isn't already adjacent to the window.
|
|
5385
|
+
if (first > 2)
|
|
5386
|
+
slots.unshift({ page: null, anchor: true });
|
|
5387
|
+
slots.unshift({ page: 1, anchor: true });
|
|
5388
|
+
}
|
|
5389
|
+
if (last < this.totalPages) {
|
|
5390
|
+
if (last < this.totalPages - 1)
|
|
5391
|
+
slots.push({ page: null, anchor: true });
|
|
5392
|
+
slots.push({ page: this.totalPages, anchor: true });
|
|
5393
|
+
}
|
|
5394
|
+
return slots;
|
|
5395
|
+
}
|
|
5396
|
+
/** Wrapper classes for a slot: anchors and their gaps are md+ only. */
|
|
5397
|
+
slotVisibility(slot) {
|
|
5398
|
+
return slot.anchor ? 'hidden md:inline-flex' : 'inline-flex';
|
|
5399
|
+
}
|
|
5400
|
+
/** e.g. `Page 5 of 50`. */
|
|
5401
|
+
get pageIndicatorLabel() {
|
|
5402
|
+
return this.fill(this.labels?.pageIndicator || 'Page {{current}} of {{total}}', {
|
|
5403
|
+
current: this.currentPage,
|
|
5404
|
+
total: this.totalPages,
|
|
5405
|
+
});
|
|
5406
|
+
}
|
|
5407
|
+
/** e.g. `41–50 of 250`. */
|
|
5408
|
+
get itemRangeLabel() {
|
|
5409
|
+
return this.fill(this.labels?.itemRange || '{{start}}–{{end}} of {{total}}', {
|
|
5410
|
+
start: this.rangeStart,
|
|
5411
|
+
end: this.rangeEnd,
|
|
5412
|
+
total: this.totalItemCount,
|
|
5413
|
+
});
|
|
5414
|
+
}
|
|
5415
|
+
/**
|
|
5416
|
+
* Substitutes `{{name}}` placeholders, matching the interpolation syntax used
|
|
5417
|
+
* by MnLanguageService so the same translation strings work either way.
|
|
5418
|
+
*/
|
|
5419
|
+
fill(template, params) {
|
|
5420
|
+
return Object.entries(params).reduce((result, [key, value]) => result.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), String(value)), template);
|
|
5421
|
+
}
|
|
5354
5422
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnCollectionPagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5355
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnCollectionPagination, isStandalone: true, selector: "mn-collection-pagination", inputs: { idPrefix: "idPrefix", isPaginated: "isPaginated", isServerPaginated: "isServerPaginated", showLoadMore: "showLoadMore", loadingMoreRows: "loadingMoreRows", currentPage: "currentPage", pageSize: "pageSize", totalPages: "totalPages", totalItemCount: "totalItemCount", visiblePages: "visiblePages", pageSizeSelectOptions: "pageSizeSelectOptions", labels: "labels" }, outputs: { loadMore: "loadMore", pageChange: "pageChange", pageSizeChange: "pageSizeChange" }, ngImport: i0, template: "<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n (click)=\"loadMore.emit()\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'primary' }\"\n [disabled]=\"loadingMoreRows\"\n class=\"px-4 py-1.5 text-sm rounded border border-primary-500 text-primary-500 hover:bg-primary-100 transition-colors disabled:opacity-50\"\n mnButton\n >\n @if (loadingMoreRows) {\n <span\n class=\"inline-block w-3 h-3 border-2 border-primary-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n {{ labels?.loadMore || 'Load more' }}\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (showPagination) {\n <div class=\"flex items-center justify-
|
|
5423
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnCollectionPagination, isStandalone: true, selector: "mn-collection-pagination", inputs: { idPrefix: "idPrefix", isPaginated: "isPaginated", isServerPaginated: "isServerPaginated", showLoadMore: "showLoadMore", loadingMoreRows: "loadingMoreRows", currentPage: "currentPage", pageSize: "pageSize", totalPages: "totalPages", totalItemCount: "totalItemCount", visiblePages: "visiblePages", pageSizeSelectOptions: "pageSizeSelectOptions", labels: "labels" }, outputs: { loadMore: "loadMore", pageChange: "pageChange", pageSizeChange: "pageSizeChange" }, ngImport: i0, template: "<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n (click)=\"loadMore.emit()\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'primary' }\"\n [disabled]=\"loadingMoreRows\"\n class=\"px-4 py-1.5 text-sm rounded border border-primary-500 text-primary-500 hover:bg-primary-100 transition-colors disabled:opacity-50\"\n mnButton\n >\n @if (loadingMoreRows) {\n <span\n class=\"inline-block w-3 h-3 border-2 border-primary-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n {{ labels?.loadMore || 'Load more' }}\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (showPagination) {\n <div class=\"flex items-center justify-between gap-2 px-2 py-3 text-sm text-base-content\">\n @if (pageSizeSelectOptions.length > 1) {\n <div class=\"hidden md:flex items-center gap-2\">\n <span>{{ labels?.rowsPerPage || 'Items per page:' }}</span>\n <mn-lib-select\n (ngModelChange)=\"pageSizeChange.emit($event)\"\n [ngModel]=\"pageSize\"\n [props]=\"{\n id: idPrefix + '-page-size',\n options: pageSizeSelectOptions,\n size: 'sm'\n }\"\n ></mn-lib-select>\n </div>\n } @else {\n <div class=\"hidden md:block\"></div>\n }\n\n <!-- Narrow viewports state the page position outright: the strip's last-page\n anchor only appears once the window stops reaching the end, so it can't\n be relied on to carry the total. -->\n <span aria-live=\"polite\" class=\"md:hidden text-xs opacity-70 whitespace-nowrap\">{{ pageIndicatorLabel }}</span>\n\n <div class=\"flex flex-wrap items-center justify-center gap-0.5 md:gap-1\">\n <span class=\"text-xs mr-2 hidden md:inline\">{{ itemRangeLabel }}</span>\n\n <button\n (click)=\"pageChange.emit(1)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === 1 }\"\n [disabled]=\"currentPage === 1\"\n aria-label=\"First page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u00AB\n </button>\n\n <button\n (click)=\"pageChange.emit(currentPage - 1)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === 1 }\"\n [disabled]=\"currentPage === 1\"\n aria-label=\"Previous page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u2039\n </button>\n\n @for (slot of pageSlots; track $index) {\n <span [class]=\"slotVisibility(slot)\">\n @if (slot.page !== null) {\n <button\n (click)=\"pageChange.emit(slot.page)\"\n [attr.aria-current]=\"slot.page === currentPage ? 'page' : null\"\n [attr.aria-label]=\"'Page ' + slot.page\"\n [data]=\"{ size: 'sm', variant: 'text', color: slot.page === currentPage ? 'primary' : 'gray' }\"\n class=\"px-1.5 md:px-2.5 py-1 rounded underline underline-offset-2 transition-colors text-xs\"\n mnButton\n >{{ slot.page }}\n </button>\n } @else {\n <span aria-hidden=\"true\" class=\"px-0.5 text-xs opacity-50 select-none\">\u2026</span>\n }\n </span>\n }\n\n <button\n (click)=\"pageChange.emit(currentPage + 1)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === totalPages }\"\n [disabled]=\"currentPage === totalPages\"\n aria-label=\"Next page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u203A\n </button>\n\n <button\n (click)=\"pageChange.emit(totalPages)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === totalPages }\"\n [disabled]=\"currentPage === totalPages\"\n aria-label=\"Last page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u00BB\n </button>\n </div>\n </div>\n}\n", dependencies: [{ kind: "component", type: MnButton, selector: "button[mnButton], a[mnButton]", inputs: ["data"] }, { kind: "component", type: MnSelect, selector: "mn-lib-select", inputs: ["props"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5356
5424
|
}
|
|
5357
5425
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnCollectionPagination, decorators: [{
|
|
5358
5426
|
type: Component,
|
|
5359
|
-
args: [{ selector: 'mn-collection-pagination', standalone: true, imports: [MnButton, MnSelect, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n (click)=\"loadMore.emit()\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'primary' }\"\n [disabled]=\"loadingMoreRows\"\n class=\"px-4 py-1.5 text-sm rounded border border-primary-500 text-primary-500 hover:bg-primary-100 transition-colors disabled:opacity-50\"\n mnButton\n >\n @if (loadingMoreRows) {\n <span\n class=\"inline-block w-3 h-3 border-2 border-primary-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n {{ labels?.loadMore || 'Load more' }}\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (showPagination) {\n <div class=\"flex items-center justify-
|
|
5427
|
+
args: [{ selector: 'mn-collection-pagination', standalone: true, imports: [MnButton, MnSelect, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n (click)=\"loadMore.emit()\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'primary' }\"\n [disabled]=\"loadingMoreRows\"\n class=\"px-4 py-1.5 text-sm rounded border border-primary-500 text-primary-500 hover:bg-primary-100 transition-colors disabled:opacity-50\"\n mnButton\n >\n @if (loadingMoreRows) {\n <span\n class=\"inline-block w-3 h-3 border-2 border-primary-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n {{ labels?.loadMore || 'Load more' }}\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (showPagination) {\n <div class=\"flex items-center justify-between gap-2 px-2 py-3 text-sm text-base-content\">\n @if (pageSizeSelectOptions.length > 1) {\n <div class=\"hidden md:flex items-center gap-2\">\n <span>{{ labels?.rowsPerPage || 'Items per page:' }}</span>\n <mn-lib-select\n (ngModelChange)=\"pageSizeChange.emit($event)\"\n [ngModel]=\"pageSize\"\n [props]=\"{\n id: idPrefix + '-page-size',\n options: pageSizeSelectOptions,\n size: 'sm'\n }\"\n ></mn-lib-select>\n </div>\n } @else {\n <div class=\"hidden md:block\"></div>\n }\n\n <!-- Narrow viewports state the page position outright: the strip's last-page\n anchor only appears once the window stops reaching the end, so it can't\n be relied on to carry the total. -->\n <span aria-live=\"polite\" class=\"md:hidden text-xs opacity-70 whitespace-nowrap\">{{ pageIndicatorLabel }}</span>\n\n <div class=\"flex flex-wrap items-center justify-center gap-0.5 md:gap-1\">\n <span class=\"text-xs mr-2 hidden md:inline\">{{ itemRangeLabel }}</span>\n\n <button\n (click)=\"pageChange.emit(1)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === 1 }\"\n [disabled]=\"currentPage === 1\"\n aria-label=\"First page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u00AB\n </button>\n\n <button\n (click)=\"pageChange.emit(currentPage - 1)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === 1 }\"\n [disabled]=\"currentPage === 1\"\n aria-label=\"Previous page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u2039\n </button>\n\n @for (slot of pageSlots; track $index) {\n <span [class]=\"slotVisibility(slot)\">\n @if (slot.page !== null) {\n <button\n (click)=\"pageChange.emit(slot.page)\"\n [attr.aria-current]=\"slot.page === currentPage ? 'page' : null\"\n [attr.aria-label]=\"'Page ' + slot.page\"\n [data]=\"{ size: 'sm', variant: 'text', color: slot.page === currentPage ? 'primary' : 'gray' }\"\n class=\"px-1.5 md:px-2.5 py-1 rounded underline underline-offset-2 transition-colors text-xs\"\n mnButton\n >{{ slot.page }}\n </button>\n } @else {\n <span aria-hidden=\"true\" class=\"px-0.5 text-xs opacity-50 select-none\">\u2026</span>\n }\n </span>\n }\n\n <button\n (click)=\"pageChange.emit(currentPage + 1)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === totalPages }\"\n [disabled]=\"currentPage === totalPages\"\n aria-label=\"Next page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u203A\n </button>\n\n <button\n (click)=\"pageChange.emit(totalPages)\"\n [data]=\"{ size: 'sm', variant: 'outline', color: 'secondary', disabled: currentPage === totalPages }\"\n [disabled]=\"currentPage === totalPages\"\n aria-label=\"Last page\"\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed aspect-square leading-none\"\n mnButton\n >\u00BB\n </button>\n </div>\n </div>\n}\n" }]
|
|
5360
5428
|
}], propDecorators: { idPrefix: [{
|
|
5361
5429
|
type: Input
|
|
5362
5430
|
}], isPaginated: [{
|