import { Component, input, output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatSelectModule } from '@angular/material/select';
import { MatFormFieldModule } from '@angular/material/form-field';
import { PaginationState } from '../../../core/services/pagination.service';
/**
* Pagination Component
* Reusable pagination controls with customizable options
*
* Features:
* - Previous/Next buttons
* - First/Last page buttons
* - Page number buttons with active state
* - "Showing X-Y of Z results" display
* - Page size selector
* - Responsive design (fewer buttons on mobile)
* - Accessible with keyboard navigation and ARIA labels
*
* @example
*
*
*/
@Component({
selector: 'app-pagination',
imports: [
CommonModule,
MatButtonModule,
MatIconModule,
MatTooltipModule,
MatSelectModule,
MatFormFieldModule
],
template: `
`,
styles: [`
.pagination-container {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
background: var(--surface-color, #fff);
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.pagination-info {
display: flex;
align-items: center;
justify-content: center;
}
.info-text {
font-size: 0.875rem;
color: var(--text-secondary, #666);
}
.info-text strong {
color: var(--text-primary, #333);
font-weight: 600;
}
.pagination-actions {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
}
.page-size-selector {
min-width: 140px;
}
.page-size-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper {
display: none;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 0.5rem;
}
.page-numbers {
display: flex;
align-items: center;
gap: 0.25rem;
}
.page-button {
min-width: 40px;
height: 40px;
padding: 0 8px;
border-radius: 4px;
transition: all 0.2s ease;
}
.page-button:hover {
background-color: var(--hover-color, rgba(0, 0, 0, 0.04));
}
.page-button.active {
background-color: var(--primary-color, #1976d2);
color: white;
font-weight: 600;
}
.page-button.active:hover {
background-color: var(--primary-dark, #1565c0);
}
.ellipsis {
padding: 0 8px;
color: var(--text-secondary, #666);
user-select: none;
}
/* Responsive design */
@media (max-width: 768px) {
.pagination-container {
padding: 0.75rem;
}
.pagination-actions {
flex-direction: column;
align-items: stretch;
}
.page-size-selector {
width: 100%;
}
.pagination-controls {
justify-content: center;
}
.page-numbers {
gap: 0.125rem;
}
.page-button {
min-width: 36px;
height: 36px;
font-size: 0.875rem;
}
/* Hide ellipsis on very small screens */
@media (max-width: 480px) {
.ellipsis {
display: none;
}
}
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.pagination-container {
background: var(--surface-dark, #1e1e1e);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.info-text {
color: var(--text-secondary-dark, #b0b0b0);
}
.info-text strong {
color: var(--text-primary-dark, #e0e0e0);
}
.page-button:hover {
background-color: rgba(255, 255, 255, 0.08);
}
.ellipsis {
color: var(--text-secondary-dark, #b0b0b0);
}
}
/* Focus styles for accessibility */
.page-button:focus-visible,
button:focus-visible {
outline: 2px solid var(--primary-color, #1976d2);
outline-offset: 2px;
}
/* Disabled state */
button:disabled {
opacity: 0.4;
cursor: not-allowed;
}
`]
})
export class PaginationComponent {
// Input signals
state = input.required();
pageNumbers = input<(number | string)[]>([]);
pageSizeOptions = input([10, 25, 50, 100]);
showPageSizeSelector = input(true);
showFirstLast = input(true);
maxVisiblePages = input(5);
itemLabel = input('results');
// Output events
pageChange = output();
pageSizeChange = output();
/**
* Handle page change
*/
onPageChange(page: number): void {
if (page >= 1 && page <= (this.state()?.totalPages ?? 1)) {
this.pageChange.emit(page);
}
}
/**
* Handle page button click (for page numbers)
*/
handlePageClick(page: number | string): void {
if (typeof page === 'number') {
this.onPageChange(page);
}
}
/**
* Handle page size change
*/
onPageSizeChange(pageSize: number): void {
this.pageSizeChange.emit(pageSize);
}
}