{"version":3,"file":"mn-angular-lib-collection.mjs","sources":["../../../projects/mn-angular-lib/collection/src/mn-collection/mn-collection.types.ts","../../../projects/mn-angular-lib/collection/src/mn-collection/mn-collection-base.directive.ts","../../../projects/mn-angular-lib/collection/src/mn-collection/mn-selectable-collection-base.directive.ts","../../../projects/mn-angular-lib/collection/src/mn-collection/mn-collection-pagination.component.ts","../../../projects/mn-angular-lib/collection/src/mn-collection/mn-collection-pagination.component.html","../../../projects/mn-angular-lib/collection/src/mn-table/mn-table.types.ts","../../../projects/mn-angular-lib/collection/src/mn-table/mn-table-filter.util.ts","../../../projects/mn-angular-lib/collection/src/mn-table/mn-hidden-below.directive.ts","../../../projects/mn-angular-lib/collection/src/mn-table/mn-show-above.directive.ts","../../../projects/mn-angular-lib/collection/src/mn-table/mn-show-below.directive.ts","../../../projects/mn-angular-lib/collection/src/mn-table/mn-table.component.ts","../../../projects/mn-angular-lib/collection/src/mn-table/mn-table.component.html","../../../projects/mn-angular-lib/collection/src/mn-list/mn-list.component.ts","../../../projects/mn-angular-lib/collection/src/mn-list/mn-list.component.html","../../../projects/mn-angular-lib/collection/src/mn-grid/mn-grid.component.ts","../../../projects/mn-angular-lib/collection/src/mn-grid/mn-grid.component.html","../../../projects/mn-angular-lib/collection/public-api.ts","../../../projects/mn-angular-lib/collection/mn-angular-lib-collection.ts"],"sourcesContent":["import {TemplateRef} from '@angular/core';\nimport {LucideIconData} from '@lucide/angular';\nimport {BehaviorSubject} from 'rxjs';\n\n// ── Pagination Strategy ──\nexport type PaginationStrategy = {\n  hasMoreRows: boolean;\n  loadMore: () => Promise<void>;\n  reset?: () => void;\n}\n\nexport type CursorPaginationStrategy = {\n  endCursor?: string;\n} & PaginationStrategy\n\nexport type OffsetPaginationStrategy = {\n  currentPage: number;\n  pageSize: number;\n  totalItems?: number;\n} & PaginationStrategy\n\n// ── Data lifecycle state ──\n/**\n * Lifecycle state of a collection's data, driving which chrome the component\n * renders: skeleton placeholders ({@link LOADING}), the rows or empty state\n * ({@link RETRIEVED}), or an error placeholder ({@link ERROR}).\n *\n * Because the components are zoneless and OnPush, a consumer that flips `state`\n * to `ERROR` (or `RETRIEVED`) must also emit on `dataRows` (e.g. `dataRows.next([])`)\n * so the component runs change detection and re-reads the new state.\n */\nexport enum MnCollectionState {\n  /** Data is being (re)loaded; skeleton placeholders are shown. */\n  LOADING = 'LOADING',\n  /** Data has loaded (possibly empty); rows or the empty state are shown. */\n  RETRIEVED = 'RETRIEVED',\n  /** Loading failed; the error placeholder is shown. */\n  ERROR = 'ERROR',\n}\n\n// ── Pagination Mode ──\nexport type PaginationMode =\n  | 'none'\n  | 'load-more'\n  | 'paginated'\n  | 'client-side-pagination'\n  | 'infinite-scroll';\n\n// ── Shared Labels / i18n ──\nexport type MnCollectionLabels = {\n  loadMore?: string;\n  /** Translation key for the \"Load more\" button label. */\n  loadMoreKey?: string;\n  rowsPerPage?: string;\n  /** Translation key for the \"Rows per page\" label. */\n  rowsPerPageKey?: string;\n  /**\n   * Page position readout, shown on narrow viewports where the item range does\n   * not fit. Supports the `{{current}}` and `{{total}}` placeholders.\n   * Defaults to `Page {{current}} of {{total}}`.\n   */\n  pageIndicator?: string;\n  /** Translation key for the page position readout. */\n  pageIndicatorKey?: string;\n  /**\n   * Item range readout. Supports the `{{start}}`, `{{end}}` and `{{total}}`\n   * placeholders. Defaults to `{{start}}–{{end}} of {{total}}`.\n   */\n  itemRange?: string;\n  /** Translation key for the item range readout. */\n  itemRangeKey?: string;\n}\n\n/**\n * Chrome shared by every MnLib collection component (table, list, grid):\n * data, search, pagination, loading/skeleton, empty state and i18n. Component\n * data sources ({@link import('../mn-table').TableDataSource},\n * {@link import('../mn-list').ListDataSource},\n * {@link import('../mn-grid').GridDataSource}) extend this with their own\n * rendering contract (columns / item template / card template).\n */\nexport type MnCollectionDataSource<T> = {\n  dataRows: BehaviorSubject<T[]>;\n  getID: (row: T) => string;\n\n  emptyMessage: string;\n  /** Translation key for the empty message. When set, the component resolves it via MnLanguageService. */\n  emptyMessageKey?: string;\n  emptyTemplate?: TemplateRef<unknown>;\n  /**\n   * Icon rendered above {@link emptyMessage} in the default empty state. Pass any\n   * lucide icon's static `.icon` data (e.g. `LucideSearchX.icon`). Defaults to an\n   * inbox icon when omitted; set to `null` to render the message with no icon.\n   * Ignored when {@link emptyTemplate} is provided.\n   */\n  emptyIcon?: LucideIconData | null;\n\n  /**\n   * Lifecycle state of the data, controlling loading / error / empty rendering.\n   * Defaults to {@link MnCollectionState.RETRIEVED} when not set.\n   */\n  state?: MnCollectionState;\n  /** Number of placeholder rows rendered while data is loading. Defaults to 5. */\n  skeletonRowCount?: number;\n\n  /** Message shown in the error placeholder when {@link state} is ERROR. */\n  errorMessage?: string;\n  /** Translation key for {@link errorMessage}; resolved via MnLanguageService. */\n  errorMessageKey?: string;\n  /** Custom template rendered in place of the default error placeholder. */\n  errorTemplate?: TemplateRef<unknown>;\n\n  // Search\n  /**\n   * Whether to show the search box in the toolbar. When omitted, search auto-enables once\n   * the collection holds at least {@link searchThreshold} rows *and* a way to search exists\n   * ({@link isInSearch} or {@link onServerSearch}) — the same rule mn-select and\n   * mn-multi-select apply to their option lists, so long collections stay filterable\n   * without every call site opting in. Set explicitly to force it on or off.\n   */\n  canSearch?: boolean;\n  /**\n   * Number of rows at which the search box auto-enables (default: 8). Ignored when\n   * {@link canSearch} is set explicitly. Server-paginated sources count {@link totalItems}.\n   */\n  searchThreshold?: number;\n  searchPlaceholder?: string;\n  /** Translation key for the search placeholder. When set, the component resolves it via MnLanguageService. */\n  searchPlaceholderKey?: string;\n  isInSearch?: (row: T, searchValue: string) => boolean;\n  searchForAdditionalItems?: (searchValue: string) => Promise<T[]>;\n\n  /**\n   * Callback invoked when the user types in the search box (server-side search).\n   * When provided, the component skips client-side filtering and delegates to the consumer.\n   */\n  onServerSearch?: (searchValue: string) => void;\n\n  // Pagination\n  paginationMode?: PaginationMode;\n  paginationStrategy?: PaginationStrategy;\n  loadAdditionalRows?: () => Promise<T[]>;\n\n  /** Number of items per page when paginationMode is 'paginated'. Defaults to 10. */\n  pageSize?: number;\n\n  /** Options for the page-size selector dropdown. Defaults to [5, 10, 25, 50]. */\n  pageSizeOptions?: number[];\n\n  /** Callback invoked when the user changes the page size via the dropdown. */\n  onPageSizeChange?: (newSize: number) => void;\n\n  /**\n   * Total number of items on the server.\n   * When set, pagination and infinite-scroll use this instead of filteredItems.length.\n   */\n  totalItems?: number;\n\n  /**\n   * Callback invoked when the user navigates to a different page.\n   * When provided, the component delegates pagination to the consumer (server-side).\n   */\n  onPageChange?: (page: number) => void;\n\n  /**\n   * Callback invoked when the user scrolls to the bottom in infinite-scroll mode.\n   * When provided, the component delegates loading more rows to the consumer (server-side).\n   */\n  onLoadMore?: () => void;\n\n  // Labels / i18n\n  labels?: MnCollectionLabels;\n}\n\n/**\n * Adds row/item selection to {@link MnCollectionDataSource}. Used by components\n * that support selection (table, list); grid intentionally omits it.\n */\nexport type MnSelectableCollectionDataSource<T> = MnCollectionDataSource<T> & {\n  selectionMode?: 'none' | 'single' | 'multi';\n  selectedRows?: BehaviorSubject<T[]>;\n  /** IDs to pre-select when the component initializes. */\n  initialSelectedIds?: string[];\n\n  /**\n   * Rows behind {@link initialSelectedIds}, for collections whose rows are paged in\n   * from a server. The component can only recognise a selected row once it has been\n   * loaded, so on page 1 of a server-paginated table it knows the *ids* that are\n   * selected but not what they are called — which is exactly what\n   * {@link selectionSummary} needs to render. Supplying the rows here fills that\n   * gap. Unnecessary when every row is client-side: the ids resolve against\n   * `dataRows` on their own.\n   */\n  initialSelectedRows?: T[];\n\n  /**\n   * Renders an always-visible summary of the current selection above the\n   * collection: a count and one removable tag per selected row.\n   *\n   * It exists because a selection and a paginated list answer different questions.\n   * The list is for *finding* rows and is therefore filtered, searched and paged;\n   * the selection is the answer the user is assembling, and hiding it on page 40\n   * makes people re-pick rows they already had. The summary never pages, filters or\n   * sorts — it always shows the whole selection.\n   */\n  selectionSummary?: boolean;\n\n  /**\n   * Label for a row inside {@link selectionSummary}. Defaults to the first column\n   * that renders a plain string, falling back to the row's id.\n   */\n  selectionLabel?: (row: T) => string;\n\n  /**\n   * How many tags {@link selectionSummary} shows before collapsing the rest behind\n   * a \"+N more\" control. Defaults to 8.\n   *\n   * A summary exists to be taken in at a glance, so it must not grow without bound:\n   * left uncapped, selecting a few hundred rows turns the header into the page and\n   * pushes the table — the thing being worked in — off screen entirely. The count in\n   * the heading always states the true total, so collapsing hides tags, never\n   * information.\n   */\n  selectionSummaryLimit?: number;\n\n  /** Labels for the {@link selectionSummary} chrome. */\n  selectionSummaryLabels?: {\n    /** Heading, supporting a `{{count}}` placeholder. Defaults to `Selected ({{count}})`. */\n    title?: string;\n    /** Translation key for {@link title}. */\n    titleKey?: string;\n    /** Label for the clear-everything action. Defaults to `Clear all`. */\n    clearAll?: string;\n    /** Translation key for {@link clearAll}. */\n    clearAllKey?: string;\n    /** Accessible label for a tag's remove button, supporting `{{label}}`. */\n    remove?: string;\n    /** Translation key for {@link remove}. */\n    removeKey?: string;\n    /** Expand action, supporting a `{{count}}` placeholder. Defaults to `+{{count}} more`. */\n    showMore?: string;\n    /** Translation key for {@link showMore}. */\n    showMoreKey?: string;\n    /** Collapse action. Defaults to `Show less`. */\n    showLess?: string;\n    /** Translation key for {@link showLess}. */\n    showLessKey?: string;\n  };\n}\n","import {\n  afterEveryRender,\n  ChangeDetectorRef,\n  Directive,\n  DoCheck,\n  ElementRef,\n  inject,\n  Input,\n  OnDestroy,\n  OnInit,\n  TemplateRef,\n} from '@angular/core';\n\nimport {debounceTime, skip, Subject, Subscription} from 'rxjs';\nimport {MnLanguageService} from 'mn-angular-lib/core';\nimport {MnSelectOption} from 'mn-angular-lib/forms';\nimport {MnCollectionDataSource, MnCollectionState} from './mn-collection.types';\nimport * as lucide from 'lucide';\nimport { lucideIcons } from 'mn-angular-lib/core';\n\n/** Lucide icons this file renders. */\nconst ICONS = lucideIcons({ Inbox: lucide.Inbox });\n\n/**\n * Shared chrome for MnLib collection components (table, list, grid):\n * data subscription, client/server search, every pagination mode, load-more,\n * skeleton-row count, empty-state plumbing, common i18n key resolution and\n * toolbar change-detection.\n *\n * Concrete components extend this (or {@link MnSelectableCollectionBase}) and\n * implement only their rendering. The class is decorated `@Directive()` so it can\n * declare `@Input`s and use `inject()` while remaining abstract.\n *\n * Init runs in a fixed order (see {@link ngOnInit}); subclasses hook in via the\n * `protected` template methods rather than overriding `ngOnInit`.\n */\n@Directive()\nexport abstract class MnCollectionBase<T, DS extends MnCollectionDataSource<T>>\n  implements OnInit, OnDestroy, DoCheck {\n  @Input() dataSource!: DS;\n\n  /** Row count at which the search box auto-enables when `canSearch` is unset. */\n  private static readonly DEFAULT_SEARCH_THRESHOLD = 8;\n\n  filteredItems: T[] = [];\n  paginatedItems: T[] = [];\n  searchValue = '';\n  loadingMoreRows = false;\n\n  /** Fallback empty-state icon used when a data source doesn't set `emptyIcon`. */\n  protected readonly defaultEmptyIcon = ICONS.Inbox;\n\n  currentPage = 1;\n  pageSize = 10;\n\n  /**\n   * Measured pixel height of the body container, applied as a `min-height` floor\n   * while a server reload is in flight so the container can't collapse when the\n   * data rows are swapped for skeletons. Released in {@link ngDoCheck} the moment\n   * the loading state clears. `0` means no lock.\n   */\n  lockedMinHeight = 0;\n\n  /**\n   * Measured pixel height of one full page, applied as a persistent `min-height` floor\n   * while paginated so a short page (the last page, or after a row is removed/filtered)\n   * can't collapse the body and jump the layout below it. Blank space fills the remaindernpm\n   * at the bottom. Captured once a full page is actually on screen; `0` means unmeasured.\n   * Distinct from the transient {@link lockedMinHeight} reload lock — both combine in\n   * {@link bodyMinHeight} via `Math.max`.\n   */\n  fullPageHeight = 0;\n\n  /** Write-once guard so {@link fullPageHeight} is measured once per pageSize. */\n  private pageHeightMeasured = false;\n\n  protected readonly cdr = inject(ChangeDetectorRef);\n  protected readonly lang = inject(MnLanguageService);\n  /** Prefix used in validation error messages, e.g. `MnList`. Overridden by subclasses. */\n  protected readonly componentName: string = 'MnCollection';\n  private dataSubscription?: Subscription;\n  private searchSubject = new Subject<string>();\n  private searchSubscription?: Subscription;\n  private langSubscription?: Subscription;\n  /** Tracks the previous toolbar template reference for change detection. */\n  private previousToolbarTemplate?: TemplateRef<unknown>;\n\n  constructor() {\n    // Measure the body's height once a full page is on screen and cache it as the persistent\n    // {@link fullPageHeight} floor. Runs after every render (outside change detection, so\n    // writing the bound field can't trigger `ExpressionChangedAfterItHasBeenChecked`); the\n    // {@link pageHeightMeasured} guard limits the actual measurement to once per pageSize.\n    afterEveryRender(() => {\n      if (this.pageHeightMeasured || !this.isPaginated || this.isLoadingState) return;\n      if (this.paginatedItems.length !== this.pageSize) return;\n      const el = this.collectionBody?.nativeElement;\n      if (!el) return;\n      this.fullPageHeight = el.offsetHeight;\n      this.pageHeightMeasured = true;\n      this.cdr.markForCheck();\n    });\n  }\n\n  // ── Data lifecycle state ──\n\n  /**\n   * Single source of truth for the data lifecycle: the explicit\n   * {@link MnCollectionDataSource.state}, defaulting to RETRIEVED when unset.\n   * Every internal loading check routes through this.\n   */\n  get collectionState(): MnCollectionState {\n    return this.dataSource.state ?? MnCollectionState.RETRIEVED;\n  }\n\n  /** Whether the collection is currently loading (skeleton placeholders shown). */\n  get isLoadingState(): boolean {\n    return this.collectionState === MnCollectionState.LOADING;\n  }\n\n  /** Accessible name for the loading placeholder, and the text the status region announces. */\n  get loadingLabel(): string {\n    return this.resolveLabel(undefined, 'mnCollection.loading', 'Loading');\n  }\n\n  /** Whether loading failed (the error placeholder is shown instead of rows/empty). */\n  get isErrorState(): boolean {\n    return this.collectionState === MnCollectionState.ERROR;\n  }\n\n  // ── Template-method hooks ──\n\n  /** Whether the component delegates search to the consumer (server-side). */\n  get isServerSearched(): boolean {\n    return !!this.dataSource.onServerSearch;\n  }\n\n  /**\n   * Whether the search box is shown: the explicit `canSearch` when set, otherwise\n   * auto-enabled once the row count reaches `searchThreshold` and the source can actually\n   * search (a client predicate or a server callback — a box that filters nothing is noise).\n   * A non-empty term keeps the box even when the (server-)filtered result drops below the\n   * threshold, so the user can always clear what they typed.\n   */\n  get isSearchable(): boolean {\n    if (this.dataSource.canSearch !== undefined) return this.dataSource.canSearch;\n    if (!this.dataSource.isInSearch && !this.isServerSearched) return false;\n    if (this.searchValue.length > 0) return true;\n    const threshold = this.dataSource.searchThreshold ?? MnCollectionBase.DEFAULT_SEARCH_THRESHOLD;\n    const rowCount = this.isServerPaginated && this.dataSource.totalItems != null\n      ? this.dataSource.totalItems\n      : (this.dataSource.dataRows.value ?? []).length;\n    return rowCount >= threshold;\n  }\n\n  get isPaginated(): boolean {\n    const mode = this.dataSource.paginationMode;\n    return mode === 'paginated' || mode === 'client-side-pagination';\n  }\n\n  /** Whether the component delegates pagination to the consumer (server-side). */\n  get isServerPaginated(): boolean {\n    const mode = this.dataSource.paginationMode ?? 'load-more';\n    return mode === 'paginated' || mode === 'load-more';\n  }\n\n  get showLoadMore(): boolean {\n    const mode = this.dataSource.paginationMode ?? 'load-more';\n    // Server-side load-more: check if there are more items to load.\n    if (this.dataSource.onLoadMore) {\n      const totalItems = this.dataSource.totalItems ?? 0;\n      return mode === 'load-more' && this.filteredItems.length < totalItems;\n    }\n    const strategy = this.dataSource.paginationStrategy;\n    const hasMore = strategy ? strategy.hasMoreRows : !!this.dataSource.loadAdditionalRows;\n    return mode === 'load-more' && hasMore;\n  }\n\n  // ── Height stabilization ──\n\n  /**\n   * The measured full-page {@link fullPageHeight} floor, but only while it should apply:\n   * paginated, not loading, with rows present. Keeps a short page from collapsing the body.\n   */\n  get reservedPageHeight(): number {\n    if (this.isPaginated && !this.isLoadingState && this.filteredItems.length > 0) {\n      return this.fullPageHeight;\n    }\n    return 0;\n  }\n\n  /**\n   * `min-height` (px) applied to the body: the larger of the transient reload lock and the\n   * persistent full-page floor, so neither can shrink the body below the other. `null` clears it.\n   */\n  get bodyMinHeight(): number | null {\n    return Math.max(this.lockedMinHeight, this.reservedPageHeight) || null;\n  }\n\n  // ── Lifecycle ──\n\n  /** Total number of items, accounting for server-side pagination. */\n  get totalItemCount(): number {\n    if (this.isServerPaginated && this.dataSource.totalItems != null) {\n      return this.dataSource.totalItems;\n    }\n    return this.filteredItems.length;\n  }\n\n  get totalPages(): number {\n    return Math.max(1, Math.ceil(this.totalItemCount / this.pageSize));\n  }\n\n  get resolvedPageSizeOptions(): number[] {\n    return this.dataSource.pageSizeOptions ?? [5, 10, 25, 50];\n  }\n\n  // ── Search ──\n\n  /** Page-size options formatted for mn-select. */\n  get pageSizeSelectOptions(): MnSelectOption<number>[] {\n    return this.resolvedPageSizeOptions.map(opt => ({label: String(opt), value: opt}));\n  }\n\n  get visiblePages(): number[] {\n    const total = this.totalPages;\n    const current = this.currentPage;\n    const maxVisible = 3;\n    let start = Math.max(1, current - Math.floor(maxVisible / 2));\n    let end = start + maxVisible - 1;\n    if (end > total) {\n      end = total;\n      start = Math.max(1, end - maxVisible + 1);\n    }\n    const pages: number[] = [];\n    for (let i = start; i <= end; i++) {\n      pages.push(i);\n    }\n    return pages;\n  }\n\n  // ── Pagination ──\n  /**\n   * Body container wrapping the skeleton/data swap region, used to measure its\n   * height for {@link lockBodyHeight}. Implemented by each component with a\n   * `@ViewChild('collectionBody')` so the template reference resolves there.\n   */\n  protected abstract collectionBody?: ElementRef<HTMLElement>;\n\n  /** The toolbar template whose identity is watched in change detection. */\n  protected abstract get trackedToolbarTemplate(): TemplateRef<unknown> | undefined;\n\n  get skeletonRows(): number[] {\n    // Explicit override wins; otherwise match the rows currently on screen so the\n    // skeleton fills the same space on a reload; fall back to 5 on the first load.\n    const count = this.dataSource.skeletonRowCount ?? (this.paginatedItems.length || 5);\n    return Array.from({length: count});\n  }\n\n  ngOnInit(): void {\n    this.normalizeDataSource();\n    this.resolveTranslationKeys();\n    this.pageSize = this.dataSource.pageSize ?? 10;\n    this.beforeInitialFilter();\n\n    this.applyFilter(false);\n\n    // Skip the initial BehaviorSubject emission (already handled above).\n    this.dataSubscription = this.dataSource.dataRows.pipe(skip(1)).subscribe(() => {\n      this.applyFilter(false);\n      this.onRowsChanged();\n      this.cdr.markForCheck();\n    });\n\n    this.searchSubscription = this.searchSubject\n      .pipe(debounceTime(300))\n      .subscribe(value => {\n        this.searchValue = value;\n        this.applyFilter(true);\n        this.cdr.markForCheck();\n      });\n\n    // Re-resolve translation keys whenever the locale changes.\n    this.langSubscription = this.lang.locale$.pipe(skip(1)).subscribe(() => {\n      this.resolveTranslationKeys();\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngDoCheck(): void {\n    // Release the height lock as soon as loading ends — same CD cycle that clears\n    // the skeleton, so the lock can never outlive the skeleton it protects.\n    if (this.lockedMinHeight && !this.isLoadingState) {\n      this.lockedMinHeight = 0;\n    }\n    const currentTemplate = this.trackedToolbarTemplate;\n    if (currentTemplate !== this.previousToolbarTemplate) {\n      this.previousToolbarTemplate = currentTemplate;\n      this.cdr.markForCheck();\n    }\n  }\n\n  ngOnDestroy(): void {\n    this.dataSubscription?.unsubscribe();\n    this.searchSubscription?.unsubscribe();\n    this.langSubscription?.unsubscribe();\n  }\n\n  onSearch(searchString: string): void {\n    this.currentPage = 1;\n    if (this.isServerSearched) {\n      this.lockBodyHeight();\n      this.searchValue = searchString;\n      this.dataSource.onServerSearch?.(searchString);\n      this.cdr.markForCheck();\n    } else {\n      this.searchSubject.next(searchString);\n    }\n  }\n\n  goToPage(page: number): void {\n    if (page < 1 || page > this.totalPages) return;\n    this.currentPage = page;\n    if (this.dataSource.paginationMode === 'client-side-pagination') {\n      this.applyPagination();\n    } else {\n      this.lockBodyHeight();\n      this.dataSource.onPageChange?.(page);\n    }\n    this.cdr.markForCheck();\n  }\n\n  onPageSizeChange(newSize: number): void {\n    this.invalidatePageHeight();\n    this.pageSize = newSize;\n    this.currentPage = 1;\n    if (this.dataSource.paginationMode === 'client-side-pagination') {\n      this.applyPagination();\n    } else {\n      this.lockBodyHeight();\n      this.dataSource.onPageSizeChange?.(newSize);\n    }\n    this.cdr.markForCheck();\n  }\n\n  loadMoreRows(): void {\n    // Server-side infinite scroll: delegate to consumer callback.\n    if (this.dataSource.onLoadMore) {\n      this.dataSource.onLoadMore();\n      return;\n    }\n\n    if (!this.dataSource.loadAdditionalRows || this.loadingMoreRows) return;\n\n    this.loadingMoreRows = true;\n    const promise = (this.searchValue && this.searchValue.length > 0 && this.dataSource.searchForAdditionalItems)\n      ? this.dataSource.searchForAdditionalItems(this.searchValue)\n      : this.dataSource.loadAdditionalRows();\n\n    promise\n      .then(rows => this.processLoadedRows(rows))\n      .catch(() => {\n        // The resolved path is repainted by the `dataRows` subscription; a rejection reaches\n        // nothing, which would leave the load-more button spinning with no way to retry.\n        this.loadingMoreRows = false;\n        this.cdr.markForCheck();\n      });\n  }\n\n  isTemplateRef(value: unknown): value is TemplateRef<unknown> {\n    return value instanceof TemplateRef;\n  }\n\n  trackByID = (_index: number, item: T): string => {\n    return this.dataSource.getID(item);\n  };\n\n  // ── Skeleton ──\n\n  /** Applies search/sort/filtering and pagination to the current rows. */\n  protected abstract applyFilter(searchForItems: boolean): void;\n\n  // ── Template helpers ──\n\n  /** Runs after pageSize is set but before the first {@link applyFilter}. */\n  protected beforeInitialFilter(): void {\n    // no-op by default\n  }\n\n  /**\n   * Runs after a fresh batch of rows has been filtered in, for work that needs the\n   * rows to exist. Subclasses override to react to data arriving late; call `super`\n   * to keep the default (currently nothing).\n   */\n  protected onRowsChanged(): void {\n    // no-op by default\n  }\n\n  /**\n   * Resolves a label three ways, in order: the consumer's explicit key, a\n   * conventional `mnCollection.*` key when the app defines one, and finally a\n   * readable English default.\n   *\n   * The middle step is what makes the components translatable out of the box: an\n   * app that adds the `mnCollection` namespace to its locale files gets every\n   * table, list and grid translated at once, with no per-call-site wiring across\n   * dozens of data sources. An app that does not keeps today's English text rather\n   * than leaking raw keys into the UI.\n   *\n   * @param consumerKey The data source's own translation key, if it set one.\n   * @param defaultKey The conventional key this label falls back to.\n   * @param fallback The English text used when neither key resolves.\n   * @param params Optional interpolation values.\n   * @returns The resolved label.\n   */\n  protected resolveLabel(\n    consumerKey: string | undefined,\n    defaultKey: string,\n    fallback: string,\n    params?: Record<string, string | number>,\n  ): string {\n    if (consumerKey) return this.lang.t(consumerKey, params);\n    return this.lang.translateIfPresent(defaultKey, params) ?? fallback;\n  }\n\n  /**\n   * Resolves translation keys to display strings via {@link MnLanguageService}.\n   * Subclasses override to resolve their own keys; call `super` to keep these.\n   */\n  protected resolveTranslationKeys(): void {\n    if (this.dataSource.emptyMessageKey) {\n      this.dataSource.emptyMessage = this.lang.t(this.dataSource.emptyMessageKey);\n    }\n    if (this.dataSource.errorMessageKey) {\n      this.dataSource.errorMessage = this.lang.t(this.dataSource.errorMessageKey);\n    }\n    if (this.dataSource.searchPlaceholderKey) {\n      this.dataSource.searchPlaceholder = this.lang.t(this.dataSource.searchPlaceholderKey);\n    }\n    if (this.dataSource.labels) {\n      if (this.dataSource.labels.loadMoreKey) {\n        this.dataSource.labels.loadMore = this.lang.t(this.dataSource.labels.loadMoreKey);\n      }\n      if (this.dataSource.labels.rowsPerPageKey) {\n        this.dataSource.labels.rowsPerPage = this.lang.t(this.dataSource.labels.rowsPerPageKey);\n      }\n      // Resolved without params so the `{{current}}` / `{{start}}` placeholders\n      // survive; MnCollectionPagination fills them in per render.\n      if (this.dataSource.labels.pageIndicatorKey) {\n        this.dataSource.labels.pageIndicator = this.lang.t(this.dataSource.labels.pageIndicatorKey);\n      }\n      if (this.dataSource.labels.itemRangeKey) {\n        this.dataSource.labels.itemRange = this.lang.t(this.dataSource.labels.itemRangeKey);\n      }\n    }\n  }\n\n  // ── Shared internals ──\n\n  /**\n   * Captures the body container's current height into {@link lockedMinHeight} so it\n   * holds while a server reload swaps the data rows for skeletons. Must be called\n   * while the old rows are still rendered (before delegating to the consumer), and\n   * only locks when rows are present — the first load has nothing to preserve.\n   */\n  protected lockBodyHeight(): void {\n    const el = this.collectionBody?.nativeElement;\n    if (el && this.paginatedItems.length > 0) {\n      this.lockedMinHeight = el.offsetHeight;\n    }\n  }\n\n  /**\n   * Drops the cached {@link fullPageHeight} floor so it is re-measured on the next full page.\n   * Must run whenever the page size changes (the old floor is for a different row count).\n   */\n  protected invalidatePageHeight(): void {\n    this.fullPageHeight = 0;\n    this.pageHeightMeasured = false;\n  }\n\n  protected applyPagination(): void {\n    if (this.dataSource.paginationMode === 'client-side-pagination') {\n      const start = (this.currentPage - 1) * this.pageSize;\n      this.paginatedItems = this.filteredItems.slice(start, start + this.pageSize);\n    } else {\n      // Server always provides the correct page/slice — no client-side slicing.\n      this.paginatedItems = this.filteredItems;\n    }\n  }\n\n  /** Client-side search filtering shared by list and grid. */\n  protected applySearchFilter(items: T[]): T[] {\n    if (!this.isServerSearched && this.dataSource.isInSearch && this.isSearchable && this.searchValue && this.searchValue.length > 0) {\n      const term = this.searchValue.toLowerCase();\n      return items.filter(row => this.dataSource.isInSearch!(row, term));\n    }\n    return items;\n  }\n\n  protected processLoadedRows(rows: T[]): void {\n    const merged = [...new Map(\n      [...this.dataSource.dataRows.value, ...rows].map(item => [this.dataSource.getID(item), item])\n    ).values()];\n    this.dataSource.dataRows.next(merged);\n    this.loadingMoreRows = false;\n    this.applyFilter(false);\n  }\n\n  /**\n   * Reports every misconfigured pagination setting and repairs it in place.\n   *\n   * This deliberately does **not** throw. It runs first in {@link ngOnInit}, and a\n   * throw there aborts the rest of init — the data subscription is never made and\n   * {@link applyFilter} never runs, so the component renders a permanently empty\n   * body that only \"heals\" once some later interaction happens to call\n   * {@link applyFilter}. That failure mode reads as \"the table is broken\" rather\n   * than \"the data source is misconfigured\", and inside a modal the thrown error\n   * is easy to miss entirely. Logging loudly and degrading to the nearest working\n   * mode keeps the misconfiguration visible while still rendering the rows.\n   */\n  protected normalizeDataSource(): void {\n    const mode = this.dataSource.paginationMode;\n\n    // Server-side pagination without the server half of the contract: there is no\n    // way to fetch another page, so paginate the rows we were handed instead.\n    if (mode === 'paginated') {\n      const missing: string[] = [];\n      if (!this.dataSource.onPageChange) missing.push('onPageChange');\n      if (this.dataSource.totalItems == null) missing.push('totalItems');\n      if (missing.length > 0) {\n        this.reportConfigError(\n          `paginationMode is 'paginated' but ${missing.join(' and ')} ${missing.length === 1 ? 'is' : 'are'} missing. ` +\n          `Server-side pagination requires both; falling back to 'client-side-pagination'.`,\n        );\n        this.dataSource.paginationMode = 'client-side-pagination';\n      }\n    }\n\n    if (mode === 'load-more' || mode === 'infinite-scroll') {\n      if (!this.dataSource.onLoadMore && !this.dataSource.loadAdditionalRows && !this.dataSource.paginationStrategy) {\n        this.reportConfigError(\n          `paginationMode is '${mode}' but no load-more mechanism is provided. ` +\n          `Provide 'onLoadMore', 'loadAdditionalRows', or 'paginationStrategy'; falling back to 'none'.`,\n        );\n        this.dataSource.paginationMode = 'none';\n      }\n    }\n\n    // A pageSize outside the selector's options would leave the dropdown with no\n    // matching entry; widen the options rather than override the consumer's size.\n    if (this.dataSource.paginationMode && this.dataSource.paginationMode !== 'none') {\n      const options = this.resolvedPageSizeOptions;\n      const size = this.dataSource.pageSize ?? 10;\n      if (!options.includes(size)) {\n        this.reportConfigError(\n          `pageSize '${size}' is not one of pageSizeOptions [${options.join(', ')}]. ` +\n          `Adding it so the rows-per-page selector can show it.`,\n        );\n        this.dataSource.pageSizeOptions = [...options, size].sort((a, b) => a - b);\n      }\n    }\n  }\n\n  /**\n   * Logs a data-source configuration problem, prefixed with the component name.\n   * @param message What is wrong and how it was compensated for.\n   */\n  private reportConfigError(message: string): void {\n    console.error(`[${this.componentName}] ${message}`);\n  }\n}\n","import {Directive, EventEmitter, Output} from '@angular/core';\nimport {MnCollectionBase} from './mn-collection-base.directive';\nimport {MnSelectableCollectionDataSource} from './mn-collection.types';\n\n/**\n * Extends {@link MnCollectionBase} with single/multi row selection, shared by\n * components that support it (table, list). Grid extends the plain base instead.\n */\n@Directive()\nexport abstract class MnSelectableCollectionBase<\n  T,\n  DS extends MnSelectableCollectionDataSource<T>,\n> extends MnCollectionBase<T, DS> {\n  @Output() selectionChange = new EventEmitter<T[]>();\n\n  selectedIds = new Set<string>();\n\n  /** Whether the summary is currently showing every tag rather than the first few. */\n  selectionSummaryExpanded = false;\n\n  get allSelected(): boolean {\n    return this.filteredItems.length > 0 && this.selectedIds.size === this.filteredItems.length;\n  }\n\n  /**\n   * The row behind every selected id, kept so the selection survives the rows\n   * themselves going away.\n   *\n   * {@link selectedIds} alone is enough to tick a checkbox, because that only ever\n   * asks about a row already on screen. The summary asks the opposite question —\n   * \"what is selected, including what isn't on this page?\" — and a server-paginated\n   * collection has long since discarded those rows. Rows are captured as they are\n   * selected and backfilled from {@link MnSelectableCollectionDataSource.initialSelectedRows}\n   * and from each batch that loads.\n   */\n  protected selectedRowsById = new Map<string, T>();\n  /**\n   * Whether a seeded initial selection still has to be announced, because none of\n   * its ids matched a loaded row yet. See {@link beforeInitialFilter}.\n   */\n  private pendingInitialEmit = false;\n\n  /**\n   * Every selected row, in selection order, for the summary. Ids whose row was\n   * never seen are skipped rather than rendered as a bare id.\n   */\n  get selectedSummaryRows(): T[] {\n    const rows: T[] = [];\n    for (const id of this.selectedIds) {\n      const row = this.selectedRowsById.get(id);\n      if (row !== undefined) rows.push(row);\n    }\n    return rows;\n  }\n\n  /** Whether the selection summary should render. */\n  get showSelectionSummary(): boolean {\n    return !!this.dataSource.selectionSummary && this.hasSelection && this.selectedIds.size > 0;\n  }\n\n  /** How many tags to show before collapsing the remainder. */\n  get selectionSummaryLimit(): number {\n    return this.dataSource.selectionSummaryLimit ?? this.defaultSelectionSummaryLimit;\n  }\n\n  /**\n   * Tag count the summary collapses at when the data source names no limit.\n   *\n   * Subclasses that know their own width narrow this: the same eight tags that\n   * read as a compact header on a wide table become seven stacked lines in a phone\n   * sheet, pushing the rows they describe off screen. Overridden by\n   * {@link MnCollectionDataSource.selectionSummaryLimit}.\n   */\n  // Deliberately an accessor, not a readonly field: MnTable overrides it with a\n  // width-dependent getter, and TypeScript cannot override a property with one.\n  // eslint-disable-next-line @typescript-eslint/class-literal-property-style\n  protected get defaultSelectionSummaryLimit(): number {\n    return 8;\n  }\n\n  /**\n   * The tags to render: the first {@link selectionSummaryLimit} rows, or all of them\n   * once expanded. Keeps a large selection from turning the header into the page.\n   */\n  get visibleSelectionRows(): T[] {\n    const rows = this.selectedSummaryRows;\n    return this.selectionSummaryExpanded ? rows : rows.slice(0, this.selectionSummaryLimit);\n  }\n\n  /** How many selected rows are collapsed out of view; 0 when all are shown. */\n  get hiddenSelectionCount(): number {\n    if (this.selectionSummaryExpanded) return 0;\n    return Math.max(0, this.selectedSummaryRows.length - this.selectionSummaryLimit);\n  }\n\n  /** Expands or re-collapses the summary's tag list. */\n  toggleSelectionSummary(): void {\n    this.selectionSummaryExpanded = !this.selectionSummaryExpanded;\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * The label for a row in the summary: the consumer's {@link\n   * MnSelectableCollectionDataSource.selectionLabel}, else the first column that\n   * renders a plain string, else the row's id.\n   * @param row The selected row.\n   * @returns The text to show on the row's tag.\n   */\n  selectionLabelFor(row: T): string {\n    const custom = this.dataSource.selectionLabel;\n    if (custom) return custom(row);\n    return this.defaultSelectionLabel(row) ?? this.dataSource.getID(row);\n  }\n\n  /** Removes one row from the selection, from its tag in the summary. */\n  removeSelection(row: T): void {\n    const id = this.dataSource.getID(row);\n    if (!this.selectedIds.delete(id)) return;\n    this.selectedRowsById.delete(id);\n    this.emitSelection();\n    this.cdr.markForCheck();\n  }\n\n  get hasSelection(): boolean {\n    return (this.dataSource.selectionMode ?? 'none') !== 'none';\n  }\n\n  get isMultiSelect(): boolean {\n    return this.dataSource.selectionMode === 'multi';\n  }\n\n  isSelected(item: T): boolean {\n    return this.selectedIds.has(this.dataSource.getID(item));\n  }\n\n  /** Clears the whole selection, from the summary's clear-all action. */\n  clearSelection(): void {\n    if (this.selectedIds.size === 0) return;\n    this.selectedIds.clear();\n    this.selectedRowsById.clear();\n    this.emitSelection();\n    this.cdr.markForCheck();\n  }\n\n  toggle(item: T): void {\n    const id = this.dataSource.getID(item);\n    const mode = this.dataSource.selectionMode ?? 'none';\n\n    if (mode === 'single') {\n      this.selectedIds.clear();\n      this.selectedRowsById.clear();\n      this.selectedIds.add(id);\n      this.selectedRowsById.set(id, item);\n    } else if (mode === 'multi') {\n      if (this.selectedIds.has(id)) {\n        this.selectedIds.delete(id);\n        this.selectedRowsById.delete(id);\n      } else {\n        this.selectedIds.add(id);\n        this.selectedRowsById.set(id, item);\n      }\n    }\n\n    this.emitSelection();\n  }\n\n  toggleAll(): void {\n    if (this.selectedIds.size === this.filteredItems.length) {\n      this.selectedIds.clear();\n      this.selectedRowsById.clear();\n    } else {\n      this.filteredItems.forEach(item => {\n        const id = this.dataSource.getID(item);\n        this.selectedIds.add(id);\n        this.selectedRowsById.set(id, item);\n      });\n    }\n    this.emitSelection();\n  }\n\n  /**\n   * Fallback label used when the data source declares no `selectionLabel`.\n   * Subclasses that know how to render a row as text (a table knows its columns)\n   * override this; the base has nothing to go on.\n   * @returns The label, or null when none can be derived.\n   */\n  protected defaultSelectionLabel(_row: T): string | null {\n    return null;\n  }\n\n  /** Seeds selection from `initialSelectedIds` before the first filter pass. */\n  protected override beforeInitialFilter(): void {\n    super.beforeInitialFilter();\n    if (!this.dataSource.initialSelectedIds?.length) return;\n\n    for (const id of this.dataSource.initialSelectedIds) {\n      this.selectedIds.add(id);\n    }\n    for (const row of this.dataSource.initialSelectedRows ?? []) {\n      this.selectedRowsById.set(this.dataSource.getID(row), row);\n    }\n    this.captureSelectedRows();\n\n    // The rows are commonly still in flight at this point (any server fetch), and\n    // then no id resolves to a row yet. Emitting that would announce \"nothing is\n    // selected\" and let the consumer — a form control bound to this table, say —\n    // overwrite the very value it just seeded us with. Defer instead, and announce\n    // it from {@link onRowsChanged} once the rows actually arrive.\n    if (this.resolveSelectedRows().length === 0) {\n      this.pendingInitialEmit = true;\n      return;\n    }\n    this.emitSelection();\n  }\n\n  /** Announces a deferred initial selection as soon as its rows are loaded. */\n  protected override onRowsChanged(): void {\n    super.onRowsChanged();\n    // A newly loaded page may hold rows for ids selected before it arrived.\n    this.captureSelectedRows();\n    if (!this.pendingInitialEmit || this.resolveSelectedRows().length === 0) return;\n    this.pendingInitialEmit = false;\n    this.emitSelection();\n  }\n\n  protected emitSelection(): void {\n    // A real user interaction supersedes any deferred initial announcement.\n    this.pendingInitialEmit = false;\n    const rows = this.resolveSelectedRows();\n    this.dataSource.selectedRows?.next(rows);\n    this.selectionChange.emit(rows);\n  }\n\n  /** Records the row object for every loaded row that is currently selected. */\n  private captureSelectedRows(): void {\n    for (const row of this.dataSource.dataRows.value ?? []) {\n      const id = this.dataSource.getID(row);\n      if (this.selectedIds.has(id)) this.selectedRowsById.set(id, row);\n    }\n  }\n\n  /** The currently loaded rows whose id is selected. */\n  private resolveSelectedRows(): T[] {\n    return (this.dataSource.dataRows.value ?? [])\n      .filter(r => this.selectedIds.has(this.dataSource.getID(r)));\n  }\n}\n","import {ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {MnButton} from 'mn-angular-lib/button';\nimport {MnSelect, MnSelectOption} from 'mn-angular-lib/forms';\nimport {MnLanguageService} from 'mn-angular-lib/core';\nimport {MnCollectionLabels} from './mn-collection.types';\n\n/** One position in the page-number strip. */\nexport type MnPageSlot = {\n  /** Page to jump to, or `null` for an ellipsis gap. */\n  page: number | null;\n  /**\n   * True for the first/last page anchors and the gaps beside them. These are\n   * hidden below `md`, where the readout states the total and « » already jump\n   * to either end — the strip would otherwise wrap.\n   */\n  anchor: boolean;\n}\n\n/**\n * Presentational pagination footer shared by every MnLib collection component\n * (table, list, grid): the load-more button, the page-size selector and the\n * page navigator. It holds no state — the host component owns pagination state\n * (via {@link import('./mn-collection-base.directive').MnCollectionBase}) and\n * reacts to the outputs.\n */\n@Component({\n  selector: 'mn-collection-pagination',\n  standalone: true,\n  imports: [MnButton, MnSelect, FormsModule],\n  templateUrl: './mn-collection-pagination.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MnCollectionPagination {\n  private readonly lang = inject(MnLanguageService);\n\n  /** Prefix for the page-size select's id, keeping it unique per host. */\n  @Input() idPrefix = 'mn-collection';\n\n  @Input() isPaginated = false;\n  @Input() isServerPaginated = false;\n  @Input() showLoadMore = false;\n  @Input() loadingMoreRows = false;\n\n  @Input() currentPage = 1;\n  @Input() pageSize = 10;\n  @Input() totalPages = 1;\n  @Input() totalItemCount = 0;\n  @Input() visiblePages: number[] = [];\n  @Input() pageSizeSelectOptions: MnSelectOption<number>[] = [];\n  @Input() labels?: MnCollectionLabels;\n\n  @Output() loadMore = new EventEmitter<void>();\n  @Output() pageChange = new EventEmitter<number>();\n  @Output() pageSizeChange = new EventEmitter<number>();\n\n  get showPagination(): boolean {\n    return this.isPaginated && (this.totalPages > 1 || this.isServerPaginated);\n  }\n\n  /** First item number on the current page, 1-based. Zero when there is no data. */\n  get rangeStart(): number {\n    return this.totalItemCount === 0 ? 0 : (this.currentPage - 1) * this.pageSize + 1;\n  }\n\n  /** Last item number on the current page, clamped to the total. */\n  get rangeEnd(): number {\n    return Math.min(this.currentPage * this.pageSize, this.totalItemCount);\n  }\n\n  /**\n   * {@link visiblePages} anchored with the first and last page, so the total page\n   * count is on screen at md+ without consulting the readout.\n   *\n   * e.g. page 5 of 50 → `1 … 4 5 6 … 50`\n   */\n  get pageSlots(): MnPageSlot[] {\n    const pages = this.visiblePages;\n    if (pages.length === 0) return [];\n\n    const first = pages[0];\n    const last = pages[pages.length - 1];\n    const slots: MnPageSlot[] = pages.map(page => ({page, anchor: false}));\n\n    if (first > 1) {\n      // Only insert a gap when the anchor isn't already adjacent to the window.\n      if (first > 2) slots.unshift({page: null, anchor: true});\n      slots.unshift({page: 1, anchor: true});\n    }\n    if (last < this.totalPages) {\n      if (last < this.totalPages - 1) slots.push({page: null, anchor: true});\n      slots.push({page: this.totalPages, anchor: true});\n    }\n    return slots;\n  }\n\n  /** e.g. `Page 5 of 50`. */\n  get pageIndicatorLabel(): string {\n    return this.fill(this.label(this.labels?.pageIndicator, 'mnCollection.pageIndicator', 'Page {{current}} of {{total}}'), {\n      current: this.currentPage,\n      total: this.totalPages,\n    });\n  }\n\n  /** e.g. `41–50 of 250`. */\n  get itemRangeLabel(): string {\n    return this.fill(this.label(this.labels?.itemRange, 'mnCollection.itemRange', '{{start}}–{{end}} of {{total}}'), {\n      start: this.rangeStart,\n      end: this.rangeEnd,\n      total: this.totalItemCount,\n    });\n  }\n\n  /** \"Items per page\" label beside the page-size selector. */\n  get rowsPerPageLabel(): string {\n    return this.label(this.labels?.rowsPerPage, 'mnCollection.rowsPerPage', 'Items per page:');\n  }\n\n  /**\n   * Substitutes `{{name}}` placeholders, matching the interpolation syntax used\n   * by MnLanguageService so the same translation strings work either way.\n   */\n  private fill(template: string, params: Record<string, number>): string {\n    return Object.entries(params).reduce(\n      (result, [key, value]) => result.replace(new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, 'g'), String(value)),\n      template,\n    );\n  }\n\n  /** Label for the load-more button. */\n  get loadMoreLabel(): string {\n    return this.label(this.labels?.loadMore, 'mnCollection.loadMore', 'Load more');\n  }\n\n  /** Accessible label for the first-page control. */\n  get firstPageLabel(): string {\n    return this.label(undefined, 'mnCollection.firstPage', 'First page');\n  }\n\n  /** Accessible label for the previous-page control. */\n  get previousPageLabel(): string {\n    return this.label(undefined, 'mnCollection.previousPage', 'Previous page');\n  }\n\n  /** Accessible label for the next-page control. */\n  get nextPageLabel(): string {\n    return this.label(undefined, 'mnCollection.nextPage', 'Next page');\n  }\n\n  /** Accessible label for the last-page control. */\n  get lastPageLabel(): string {\n    return this.label(undefined, 'mnCollection.lastPage', 'Last page');\n  }\n\n  /**\n   * Wrapper classes for one slot in the page strip, shrinking it in two steps as\n   * the footer narrows. Container queries, so the measurement is the footer's own\n   * width — the same strip is wide on a page and cramped in a modal.\n   *\n   * The first/last anchors and their gaps drop below 640px, where « and » already\n   * jump to either end. Below 380px every number except the current one drops too:\n   * the strip would otherwise wrap onto a second line and push the footer over the\n   * table, and the \"Page 3 of 9\" readout beside it already says where the user is.\n   * The arrows survive both steps, so navigation never depends on a number.\n   */\n  slotVisibility(slot: MnPageSlot): string {\n    if (slot.anchor) return 'hidden @min-[640px]:inline-flex';\n    return slot.page === this.currentPage ? 'inline-flex' : 'hidden @min-[380px]:inline-flex';\n  }\n\n  /**\n   * Accessible label for a page-number button.\n   * @param page The page the button jumps to.\n   * @returns The label, naming the page.\n   */\n  pageLabel(page: number): string {\n    const template = this.label(undefined, 'mnCollection.page', 'Page {{page}}');\n    return template.replace('{{page}}', String(page));\n  }\n\n  /**\n   * Resolves a label three ways, in order: the consumer's explicit text, the\n   * conventional `mnCollection.*` key when the app defines one, and finally a\n   * readable English default.\n   *\n   * Mirrors `MnCollectionBase.resolveLabel`; this component is presentational and\n   * does not extend that base, but its chrome must be just as translatable — the\n   * page-size label and the item-range readout are on screen for every paged\n   * collection in the app.\n   *\n   * @param explicit The label the host passed in, if any.\n   * @param key The conventional translation key to try.\n   * @param fallback The English text used when neither resolves.\n   * @returns The resolved label.\n   */\n  private label(explicit: string | undefined, key: string, fallback: string): string {\n    return explicit ?? this.lang.translateIfPresent(key) ?? fallback;\n  }\n}\n","<!-- 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      type=\"button\"\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      {{ loadMoreLabel }}\n    </button>\n  </div>\n}\n\n<!-- Pagination controls -->\n@if (showPagination) {\n  <div class=\"@container 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 @min-[640px]:flex items-center gap-2\">\n        <span>{{ rowsPerPageLabel }}</span>\n        <mn-lib-select\n          (ngModelChange)=\"pageSizeChange.emit($event)\"\n          [ngModel]=\"pageSize\"\n          [props]=\"{\n            id: idPrefix + '-page-size',\n            ariaLabel: rowsPerPageLabel,\n            options: pageSizeSelectOptions,\n            size: 'sm'\n          }\"\n        ></mn-lib-select>\n      </div>\n    } @else {\n      <div class=\"hidden @min-[640px]: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\"\n          class=\"@min-[640px]:hidden text-xs opacity-70 whitespace-nowrap\">{{ pageIndicatorLabel }}</span>\n\n    <div class=\"flex flex-wrap items-center justify-center gap-0.5 @min-[640px]:gap-1\">\n      <span class=\"text-xs mr-2 hidden @min-[640px]: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        [attr.aria-label]=\"firstPageLabel\"\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        type=\"button\"\n      >«\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        [attr.aria-label]=\"previousPageLabel\"\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        type=\"button\"\n      >‹\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]=\"pageLabel(slot.page)\"\n              [data]=\"{ size: 'sm', variant: 'text', color: slot.page === currentPage ? 'primary' : 'gray' }\"\n              class=\"px-1.5 @min-[640px]:px-2.5 py-1 rounded underline underline-offset-2 transition-colors text-xs\"\n              mnButton\n              type=\"button\"\n            >{{ slot.page }}\n            </button>\n          } @else {\n            <span aria-hidden=\"true\" class=\"px-0.5 text-xs opacity-50 select-none\">…</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        [attr.aria-label]=\"nextPageLabel\"\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        type=\"button\"\n      >›\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        [attr.aria-label]=\"lastPageLabel\"\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        type=\"button\"\n      >»\n      </button>\n    </div>\n  </div>\n}\n","import {TemplateRef} from '@angular/core';\nimport {MnSkeletonProps} from 'mn-angular-lib/button';\nimport {MnCollectionLabels, MnSelectableCollectionDataSource} from '../mn-collection';\nimport {MnActionIcon, MnDropdownActionColor} from 'mn-angular-lib/forms';\n\n// ── Column Sort Type ──\nexport enum ColumnSortType {\n  ALPHABETICAL = 'ALPHABETICAL',\n  NUMERICAL = 'NUMERICAL',\n  DATE = 'DATE',\n  NONE = 'NONE',\n}\n\n// ── Sort State ──\nexport type SortState = {\n  columnKey: string;\n  direction: 'asc' | 'desc';\n}\n\n// ── Appearance ──\nexport type TableAppearance = {\n  striped?: boolean;\n  hover?: boolean;\n  compact?: boolean;\n  bordered?: boolean;\n  /**\n   * How column widths are computed. Defaults to `stable`.\n   *\n   * - `stable` (default): the best of both. The first render with rows on screen\n   *   uses the browser's automatic layout, so each column is sized in proportion to\n   *   its real content; those measured widths are then pinned and the table switches\n   *   to a fixed layout. Columns therefore keep sensible, content-derived\n   *   proportions **and** stop moving when the rows change underneath — a new page,\n   *   a filter or a search cannot resize them. Widths are re-measured only when the\n   *   table itself is resized (or a {@link ColumnBase.hiddenBelow} column appears or\n   *   disappears), never when the rows change. Content that no longer fits is\n   *   truncated with an ellipsis and exposed as a `title` tooltip.\n   * - `auto`: the plain browser layout. Every column is re-sized to its widest cell\n   *   on every change, so the columns shift on each new page, filter and search.\n   *   Use it for a static table, or when a cell must never be truncated.\n   * - `fixed`: widths are **data-independent**. Nothing is measured — not the cell\n   *   content, and not the header text either. Each column is either its declared\n   *   {@link ColumnBase.width} or an even share of whatever is left over:\n   *   `(table width − Σ declared widths) ÷ number of undeclared visible columns`.\n   *   Only worth choosing over `stable` when every column declares a `width`, or\n   *   when a deliberate even split is what you want: with widths undeclared, a\n   *   two-character status column is handed exactly as much room as a long\n   *   description.\n   */\n  layout?: 'auto' | 'fixed' | 'stable';\n}\n\n// ── Column Filter Type ──\n/**\n * The control rendered for a column filter, and the shape of the value it produces:\n * - `text` → `string` (free-text, debounced)\n * - `select` → `string` (single choice; empty string means \"no filter\")\n * - `multi-select` → `string[]` (OR semantics across the chosen values)\n * - `boolean` → `boolean` (tri-state: any / true / false)\n */\nexport type ColumnFilterType = 'text' | 'select' | 'multi-select' | 'boolean';\n\n// ── Column Filter Option ──\nexport type ColumnFilterOption = {\n  label: string;\n  value: string;\n}\n\n/** Every value shape a column filter can hold, discriminated by {@link ColumnFilterType}. */\nexport type ColumnFilterValue = string | string[] | boolean;\n\n/** Map of column key to its current filter value. */\nexport type ColumnFilterState = Record<string, ColumnFilterValue | undefined>;\n\n/**\n * One active column filter, as handed to\n * {@link TableDataSource.onColumnFilterChange}. Only columns whose filter is\n * actually set are included, so the array maps straight onto query params.\n */\nexport type MnColumnFilter = {\n  key: string;\n  type: ColumnFilterType;\n  value: ColumnFilterValue;\n}\n\n// ── Column Skeleton ──\n/**\n * Customizes the loading-skeleton placeholder rendered in a column's cells.\n * Either a partial {@link MnSkeletonProps} (shape/width/height/animated) or a\n * `TemplateRef` for a fully custom placeholder. When omitted, a text-shaped\n * skeleton at 75% width is used (matching the previous default).\n */\nexport type ColumnSkeleton = Partial<MnSkeletonProps> | TemplateRef<unknown>;\n\n// ── Row Action ──\n/**\n * A presentation value that is either fixed for the whole column or derived per row.\n *\n * The function form is what lets one action cover a state that flips — an\n * activate/deactivate toggle, a pin/unpin — instead of declaring two actions and hiding\n * one of them per row. It is only for *presentation*: visibility stays with `hidden` and\n * interactivity with `disabled`, both of which are always predicates.\n *\n * Resolved on every change detection, so the accessor must be cheap and side-effect free.\n */\nexport type MnRowValue<T, V> = V | ((row: T) => V);\n\n/**\n * A per-row command rendered in an actions column (see {@link ColumnBase.actions}).\n * Unlike a cell it carries no display value — choosing it invokes {@link run} with the\n * row. The table renders actions inline as buttons and collapses them into a ⋯ menu\n * (mn-dropdown) once the table is narrower than 450px.\n */\nexport type MnTableRowAction<T> = {\n  /** Visible label. Falls back to `labelKey`'s resolved text when omitted. */\n  label?: MnRowValue<T, string>;\n  /** Translation key for the label, resolved via MnLanguageService and kept updated on locale change. */\n  labelKey?: MnRowValue<T, string>;\n  /**\n   * Optional leading icon: a template (an `<mn-icon>`, a bespoke `<svg>`, …), or lucide\n   * icon data such as `LucidePencil.icon`, which the table renders itself. The data form\n   * lets an action be declared without an `<ng-template>` stub and a `@ViewChild` per\n   * glyph, which is what makes shared action factories practical.\n   */\n  icon?: MnRowValue<T, MnActionIcon>;\n  /** Invoked with the row when the action is chosen. */\n  run: (row: T) => void;\n  /**\n   * Predicate deciding whether the action is hidden for a given row. A hidden action is\n   * dropped entirely for that row (not shown, not counted). When every action is hidden\n   * for a row its cell is left empty — no buttons and no ⋯ menu. Use this for \"row 1 has\n   * actions, row 2 doesn't\", or per-permission actions (e.g. only admins can delete).\n   */\n  hidden?: (row: T) => boolean;\n  /** Predicate deciding whether the action is disabled (shown but non-interactive) for a row. */\n  disabled?: (row: T) => boolean;\n  /**\n   * Tints the action's button and its ⋯-menu item. Defaults to `'primary'` (or\n   * `'danger'` when {@link danger} is set), matching the built-in look. Whatever colour\n   * an action shows inline is carried into the collapsed bottom-sheet item too.\n   */\n  color?: MnRowValue<T, MnDropdownActionColor>;\n  /** Renders the action in a destructive style (e.g. \"Delete\"). Shorthand for\n   *  `color: 'danger'`. */\n  danger?: boolean;\n};\n\n// ── Column Definition ──\n/** Everything about a column that is independent of filtering. */\nexport type ColumnBase<T> = {\n  key: string;\n  header: string | TemplateRef<unknown>;\n  /** Translation key for the column header. When set, mn-table resolves it via MnLanguageService and keeps it updated on locale change. */\n  headerKey?: string;\n  /**\n   * How a data cell is rendered — a string accessor or a `TemplateRef`. Optional only\n   * because an {@link actions} column renders commands instead of a value; every value\n   * column must set it.\n   */\n  cell?: ((row: T) => string) | TemplateRef<unknown>;\n  /**\n   * Turns this column into an actions column: per-row command buttons rendered inline,\n   * automatically collapsing into a ⋯ menu (mn-dropdown) once the table is narrower than\n   * 450px. When set, {@link cell} is ignored.\n   */\n  actions?: MnTableRowAction<T>[];\n  /**\n   * How each inline action button is presented on a wide table:\n   * - `'both'` (default) — icon (when provided) followed by the label;\n   * - `'icon'` — icon only; the label becomes the button's accessible name and hover\n   *   tooltip. An action without an icon falls back to showing its label so it is never\n   *   blank;\n   * - `'label'` — text only, no icon.\n   *\n   * The collapsed ⋯ menu always lists full labels regardless of this setting, so\n   * `'icon'` still reads clearly once the actions move into the bottom sheet on mobile.\n   */\n  actionsInline?: 'icon' | 'label' | 'both';\n  /** Alternative cell renderer shown below the given breakpoint. When set, `cell` is hidden below this breakpoint and `cellSm` is shown instead. */\n  cellSm?: { below: 'sm' | 'md' | 'lg'; cell: ((row: T) => string) | TemplateRef<unknown> };\n  sortType?: ColumnSortType;\n  getRawValueToSort?: (row: T) => unknown;\n  width?: string;\n  align?: 'left' | 'center' | 'right';\n  hiddenBelow?: 'sm' | 'md' | 'lg';\n  /** Customizes the loading-skeleton placeholder shown in this column's cells while data loads. */\n  skeleton?: ColumnSkeleton;\n}\n\n/** Filter presentation props shared by every filterable column. */\ntype ColumnFilterCommon = {\n  /** Whether this column supports per-column filtering. */\n  filterable: true;\n  /** Placeholder text for the filter input. For `select`, it also labels the \"no filter\" option. */\n  filterPlaceholder?: string;\n  /** Translation key for the filter placeholder. When set, mn-table resolves it via MnLanguageService. */\n  filterPlaceholderKey?: string;\n  /** Whether the filter input is disabled. */\n  filterDisabled?: boolean;\n  /** Autocomplete attribute for the filter input. */\n  filterAutocomplete?: string;\n}\n\n/**\n * The filter half of a {@link ColumnDefinition}, discriminated on `filterType` so\n * `filterOptions` is required exactly where it applies and `filterFn` receives the\n * value shape that filter type actually produces.\n *\n * Every branch declares every filter key (inapplicable ones as `never`) so a column\n * can be read and written generically — e.g. mn-table resolving `filterPlaceholderKey`\n * across all columns — without narrowing first.\n */\ntype ColumnFilterConfig<T> =\n  | (ColumnFilterCommon & {\n  filterType?: 'text';\n  filterOptions?: never;\n  /** Custom predicate. Receives the row and the trimmed text the user typed. */\n  filterFn?: (row: T, filterValue: string) => boolean;\n})\n  | (ColumnFilterCommon & {\n  filterType: 'select';\n  filterOptions: ColumnFilterOption[];\n  /** Custom predicate. Receives the row and the selected option value. */\n  filterFn?: (row: T, filterValue: string) => boolean;\n})\n  | (ColumnFilterCommon & {\n  filterType: 'multi-select';\n  filterOptions: ColumnFilterOption[];\n  /** Custom predicate. Receives the row and every selected option value. */\n  filterFn?: (row: T, filterValue: string[]) => boolean;\n})\n  | (ColumnFilterCommon & {\n  filterType: 'boolean';\n  filterOptions?: never;\n  /** Custom predicate. Receives the row and the chosen true/false state. */\n  filterFn?: (row: T, filterValue: boolean) => boolean;\n})\n  | {\n  filterable?: false;\n  filterType?: never;\n  filterOptions?: never;\n  filterFn?: never;\n  filterPlaceholder?: string;\n  filterPlaceholderKey?: string;\n  filterDisabled?: never;\n  filterAutocomplete?: never;\n};\n\nexport type ColumnDefinition<T> = ColumnBase<T> & ColumnFilterConfig<T>;\n\n// ── Table Data Source ──\nexport type TableDataSource<T> = MnSelectableCollectionDataSource<T> & {\n  /** Accessible name of the scrollable table region; without it the `mnCollection.dataTable` convention key is used. */\n  ariaLabel?: string;\n  columns: ColumnDefinition<T>[];\n\n  // Sorting\n  defaultSort?: SortState;\n\n  // Row interaction\n  onRowClick?: (row: T) => void;\n\n  // Appearance\n  appearance?: TableAppearance;\n\n  // Toolbar\n  /** Template rendered on the left side of the toolbar (before the search field). */\n  toolbarLeftTemplate?: TemplateRef<unknown>;\n  /** Template rendered on the right side of the toolbar (after the search field). */\n  toolbarRightTemplate?: TemplateRef<unknown>;\n\n  // Responsive filters\n  /**\n   * Label for the toggle button that opens the stacked filter panel on small\n   * screens (below 640px). Defaults to \"Filters\".\n   */\n  filtersLabel?: string;\n  /** Translation key for {@link filtersLabel}. Resolved via MnLanguageService. */\n  filtersLabelKey?: string;\n  /**\n   * Label for the action that resets every column filter in the small-screen\n   * panel. Defaults to \"Clear all\".\n   */\n  clearFiltersLabel?: string;\n  /** Translation key for {@link clearFiltersLabel}. Resolved via MnLanguageService. */\n  clearFiltersLabelKey?: string;\n  /** Labels for the range / boolean filter controls. */\n  filterLabels?: MnTableFilterLabels;\n\n  // Server-side filtering\n  /**\n   * Callback invoked when a column filter changes (server-side filtering).\n   * When provided, mn-table skips client-side column filtering entirely and\n   * delegates to the consumer, exactly as {@link MnCollectionDataSource.onServerSearch}\n   * does for search: the table resets to page 1 and hands over every active filter.\n   *\n   * Required whenever filterable columns are combined with\n   * `paginationMode: 'paginated'` — client-side filtering would otherwise only\n   * filter the page the server already returned, while the paginator kept\n   * reporting the unfiltered `totalItems`.\n   *\n   * Text filters are debounced (300ms); every other filter type fires immediately.\n   */\n  onColumnFilterChange?: (filters: MnColumnFilter[]) => void;\n}\n\n// ── Filter control labels ──\n/**\n * User-facing labels for the filter controls that need more than a placeholder.\n * Each has a `*Key` counterpart resolved via MnLanguageService on init and on\n * every locale change.\n */\nexport type MnTableFilterLabels = {\n  /** Unset option of a boolean filter. Defaults to \"Any\". */\n  any?: string;\n  anyKey?: string;\n  /** True option of a boolean filter. Defaults to \"Yes\". */\n  yes?: string;\n  yesKey?: string;\n  /** False option of a boolean filter. Defaults to \"No\". */\n  no?: string;\n  noKey?: string;\n  /**\n   * Summary a multi-select filter collapses to from the second selection onwards.\n   * The `{count}` token is replaced with how many are selected. Defaults to\n   * `{count} selected`. A column header has room for about one value, so listing\n   * them all would overflow the cell the moment a second one is picked.\n   */\n  selected?: string;\n  /** Translation key for {@link selected}. */\n  selectedKey?: string;\n}\n\n/** @deprecated Use {@link MnCollectionLabels}. */\nexport type TableLabels = MnCollectionLabels;\n","import {ColumnDefinition, ColumnFilterType, ColumnFilterValue} from './mn-table.types';\n\n/**\n * Pure helpers backing mn-table's per-column filters: the empty value and\n * \"is it set?\" test for each filter type, and the default client-side predicate\n * applied when a column supplies no `filterFn`.\n *\n * Kept free of Angular so the filter semantics can be unit-tested directly.\n */\n\n/** The reset/unset value for a filter type. */\nexport function emptyFilterValue(type: ColumnFilterType): ColumnFilterValue {\n  switch (type) {\n    case 'multi-select':\n      return [];\n    case 'boolean':\n    case 'text':\n    case 'select':\n    default:\n      return '';\n  }\n}\n\n/**\n * Whether a filter value should actually narrow the rows. Empty strings and\n * empty arrays are inactive; `false` on a boolean filter is active (it means\n * \"show only the false rows\"), which is why a plain truthiness check is not\n * enough.\n */\nexport function isFilterValueActive(value: ColumnFilterValue | undefined): boolean {\n  if (value === undefined || value === null) return false;\n  if (typeof value === 'boolean') return true;\n  if (typeof value === 'string') return value.trim().length > 0;\n  return Array.isArray(value) && value.length > 0;\n}\n\n/**\n * The value a filter compares against for a row: the column's\n * `getRawValueToSort` when present (the only option for template cells, which\n * have no string to read), otherwise the rendered cell string.\n */\nexport function resolveFilterableValue<T>(column: ColumnDefinition<T>, row: T): unknown {\n  if (column.getRawValueToSort) return column.getRawValueToSort(row);\n  if (typeof column.cell === 'function') return column.cell(row);\n  return '';\n}\n\n/**\n * The default predicate for a filter type, used when the column supplies no\n * `filterFn`. Semantics per type:\n * - `text` — case-insensitive substring match\n * - `select` — exact string equality\n * - `multi-select` — equality against any selected value (OR)\n * - `boolean` — truthiness of the raw value equals the chosen state\n */\nexport function defaultFilterPredicate(\n  type: ColumnFilterType,\n  raw: unknown,\n  value: ColumnFilterValue,\n): boolean {\n  switch (type) {\n    case 'select':\n      return String(raw ?? '') === String(value);\n\n    case 'multi-select': {\n      const selected = value as string[];\n      return selected.some(option => String(raw ?? '') === option);\n    }\n\n    case 'boolean':\n      return Boolean(raw) === value;\n\n    case 'text':\n    default:\n      return String(raw ?? '')\n        .toLowerCase()\n        .includes(String(value).trim().toLowerCase());\n  }\n}\n\n/**\n * Whether a row passes a column's active filter — the column's own `filterFn`\n * when it has one, otherwise {@link defaultFilterPredicate}.\n *\n * `filterFn` is declared per filter type on {@link ColumnDefinition}, so at this\n * generic call site the union of signatures is not callable and the value shape\n * is widened once here. Consumers keep the precise per-type signature where they\n * declare the column, which is where it matters.\n */\nexport function matchesColumnFilter<T>(\n  column: ColumnDefinition<T>,\n  row: T,\n  value: ColumnFilterValue,\n): boolean {\n  const filterFn = column.filterFn as ((row: T, filterValue: ColumnFilterValue) => boolean) | undefined;\n  if (filterFn) return filterFn(row, value);\n  return defaultFilterPredicate(column.filterType ?? 'text', resolveFilterableValue(column, row), value);\n}\n","import {Directive, ElementRef, inject, Input, OnChanges, Renderer2} from '@angular/core';\n\n/**\n * Attribute directive that applies responsive-hiding classes to table cells/headers.\n * Hides the element by default and shows it as `table-cell` at the specified breakpoint.\n *\n * The breakpoints are **container** queries against the table's own width, not the\n * viewport: a table inside a modal (or any narrow column) is far narrower than the\n * window, so viewport breakpoints would reveal columns the table has no room for.\n * mn-table marks its chrome `@container` for exactly this.\n *\n * Because of that, `sm`/`md`/`lg` mean \"the table is at least this wide\", and the\n * thresholds are **not** the viewport values of the same names — see {@link classMap}.\n *\n * Uses a static class map so Tailwind CSS can detect the full class names at build time.\n *\n * Usage: `<td [mnHiddenBelow]=\"column.hiddenBelow\">`\n */\n@Directive({\n  selector: '[mnHiddenBelow]',\n  standalone: true,\n})\nexport class MnHiddenBelowDirective implements OnChanges {\n  /** The breakpoint below which the element is hidden. */\n  @Input() mnHiddenBelow: 'sm' | 'md' | 'lg' | undefined;\n\n  private readonly el = inject(ElementRef);\n  private readonly renderer = inject(Renderer2);\n\n  private appliedClasses: string[] = [];\n\n  /**\n   * Static mapping of breakpoints to their full Tailwind class names, so Tailwind\n   * can detect them at build time.\n   *\n   * These are **container** widths, deliberately lower than the viewport\n   * breakpoints they are named after. A table almost never gets the whole window:\n   * a page table sits inside a docked sidebar plus page padding, which on a\n   * 1280px screen leaves it under 900px. Reusing 1024px for `lg` would demand a\n   * ~1400px window before an `lg` column ever appeared — hiding columns on the\n   * most ordinary laptop. These values instead express how much room the column\n   * itself needs, which is what a container query should measure.\n   */\n  private readonly classMap: Record<string, string[]> = {\n    sm: ['hidden', '@min-[480px]:table-cell'],\n    md: ['hidden', '@min-[640px]:table-cell'],\n    lg: ['hidden', '@min-[800px]:table-cell'],\n  };\n\n  ngOnChanges(): void {\n    // Remove previously applied classes\n    for (const cls of this.appliedClasses) {\n      this.renderer.removeClass(this.el.nativeElement, cls);\n    }\n    this.appliedClasses = [];\n\n    if (this.mnHiddenBelow && this.classMap[this.mnHiddenBelow]) {\n      const classes = this.classMap[this.mnHiddenBelow];\n      for (const cls of classes) {\n        this.renderer.addClass(this.el.nativeElement, cls);\n      }\n      this.appliedClasses = classes;\n    }\n  }\n}\n","import {Directive, ElementRef, inject, Input, OnChanges, Renderer2} from '@angular/core';\n\n/**\n * Attribute directive that hides an element below the given breakpoint and shows it at/above.\n * Uses `hidden` + `{bp}:inline` so the element is invisible on small screens.\n *\n * Usage: `<span [mnShowAbove]=\"'sm'\">`\n */\n@Directive({\n  selector: '[mnShowAbove]',\n  standalone: true,\n})\nexport class MnShowAboveDirective implements OnChanges {\n  /** The breakpoint at/above which the element becomes visible. */\n  @Input() mnShowAbove: 'sm' | 'md' | 'lg' | undefined;\n\n  private readonly el = inject(ElementRef);\n  private readonly renderer = inject(Renderer2);\n\n  private appliedClasses: string[] = [];\n\n  /** Static mapping of breakpoints to their full Tailwind class names. */\n  private readonly classMap: Record<string, string[]> = {\n    sm: ['hidden', '@min-[480px]:inline'],\n    md: ['hidden', '@min-[640px]:inline'],\n    lg: ['hidden', '@min-[800px]:inline'],\n  };\n\n  ngOnChanges(): void {\n    for (const cls of this.appliedClasses) {\n      this.renderer.removeClass(this.el.nativeElement, cls);\n    }\n    this.appliedClasses = [];\n\n    if (this.mnShowAbove && this.classMap[this.mnShowAbove]) {\n      const classes = this.classMap[this.mnShowAbove];\n      for (const cls of classes) {\n        this.renderer.addClass(this.el.nativeElement, cls);\n      }\n      this.appliedClasses = classes;\n    }\n  }\n}\n","import {Directive, ElementRef, inject, Input, OnChanges, Renderer2} from '@angular/core';\n\n/**\n * Attribute directive that shows an element below the given breakpoint and hides it at/above.\n * Uses `inline` by default + `{bp}:hidden` so the element is only visible on small screens.\n *\n * Usage: `<span [mnShowBelow]=\"'sm'\">`\n */\n@Directive({\n  selector: '[mnShowBelow]',\n  standalone: true,\n})\nexport class MnShowBelowDirective implements OnChanges {\n  /** The breakpoint below which the element is visible. */\n  @Input() mnShowBelow: 'sm' | 'md' | 'lg' | undefined;\n\n  private readonly el = inject(ElementRef);\n  private readonly renderer = inject(Renderer2);\n\n  private appliedClasses: string[] = [];\n\n  /** Static mapping of breakpoints to their full Tailwind class names. */\n  private readonly classMap: Record<string, string[]> = {\n    sm: ['inline', '@min-[480px]:hidden'],\n    md: ['inline', '@min-[640px]:hidden'],\n    lg: ['inline', '@min-[800px]:hidden'],\n  };\n\n  ngOnChanges(): void {\n    for (const cls of this.appliedClasses) {\n      this.renderer.removeClass(this.el.nativeElement, cls);\n    }\n    this.appliedClasses = [];\n\n    if (this.mnShowBelow && this.classMap[this.mnShowBelow]) {\n      const classes = this.classMap[this.mnShowBelow];\n      for (const cls of classes) {\n        this.renderer.addClass(this.el.nativeElement, cls);\n      }\n      this.appliedClasses = classes;\n    }\n  }\n}\n","import {\n  afterEveryRender,\n  afterNextRender,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  HostListener,\n  inject,\n  Output,\n  TemplateRef,\n  ViewChild,\n} from '@angular/core';\nimport {takeUntilDestroyed} from '@angular/core/rxjs-interop';\nimport {NgClass, NgTemplateOutlet} from '@angular/common';\nimport {debounceTime, Subject} from 'rxjs';\nimport {\n  ColumnDefinition,\n  ColumnFilterState,\n  ColumnFilterType,\n  ColumnFilterValue,\n  ColumnSortType,\n  MnColumnFilter,\n  MnRowValue,\n  MnTableRowAction,\n  SortState,\n  TableDataSource,\n} from './mn-table.types';\nimport {emptyFilterValue, isFilterValueActive, matchesColumnFilter} from './mn-table-filter.util';\nimport {MnSkeleton, MnSkeletonProps} from 'mn-angular-lib/button';\nimport {MnSelect, MnSelectOption} from 'mn-angular-lib/forms';\nimport {MnMultiSelect, MnMultiSelectOption} from 'mn-angular-lib/forms';\nimport {MnActionIcon, MnDropdown, MnDropdownAction, MnDropdownActionColor} from 'mn-angular-lib/forms';\nimport {MnCheckbox} from 'mn-angular-lib/forms';\nimport {MnHiddenBelowDirective} from './mn-hidden-below.directive';\nimport {MnShowAboveDirective} from './mn-show-above.directive';\nimport {MnShowBelowDirective} from './mn-show-below.directive';\nimport {MnInputField} from 'mn-angular-lib/forms';\nimport {FormsModule} from '@angular/forms';\nimport {MnCollectionPagination, MnSelectableCollectionBase} from '../mn-collection';\nimport {MnButton} from 'mn-angular-lib/button';\nimport {MnBottomSheet} from 'mn-angular-lib/bottom-sheet';\nimport { LucideDynamicIcon } from '@lucide/angular';\nimport * as lucide from 'lucide';\nimport { lucideIcons } from 'mn-angular-lib/core';\n\n/** Lucide icons this file renders. */\nconst ICONS = lucideIcons({ Funnel: lucide.Funnel, X: lucide.X });\n\n@Component({\n  selector: 'mn-table',\n  standalone: true,\n  imports: [NgClass, NgTemplateOutlet, MnCheckbox, MnHiddenBelowDirective, MnShowAboveDirective, MnShowBelowDirective, MnInputField, MnSelect, MnMultiSelect, MnDropdown, MnSkeleton, FormsModule, MnCollectionPagination, MnButton, MnBottomSheet, LucideDynamicIcon],\n  templateUrl: './mn-table.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // Block-level so the host has a definite width for the @container chrome inside it.\n  host: {class: 'block'},\n})\nexport class MnTable<T = object>\n  extends MnSelectableCollectionBase<T, TableDataSource<T>> {\n  /** Lucide icons the template renders. */\n  protected readonly icons = ICONS;\n\n  @Output() sortChange = new EventEmitter<SortState | null>();\n  @Output() rowClick = new EventEmitter<T>();\n\n  currentSort: SortState | null = null;\n\n  /** Per-column filter values keyed by column key. */\n  columnFilters: ColumnFilterState = {};\n\n  /** Viewport width (px) below which the inline filter row collapses into a panel. */\n  private static readonly FILTER_COLLAPSE_WIDTH = 640;\n\n  /**\n   * True when the viewport is narrow enough that the per-column filter inputs no\n   * longer fit under their headers; the inline row is then replaced by a toggle\n   * button and a stacked filter panel.\n   */\n  protected filtersCollapsed = false;\n\n  /** Whether the small-screen filter bottom sheet is currently open. */\n  protected filtersPanelOpen = false;\n\n  /** Small-screen filter sheet, held so the close button can play its exit. */\n  @ViewChild('filtersSheet') protected filtersSheet?: MnBottomSheet;\n\n  protected override readonly componentName = 'MnTable';\n\n  protected get trackedToolbarTemplate(): TemplateRef<unknown> | undefined {\n    return this.dataSource?.toolbarLeftTemplate;\n  }\n\n  @ViewChild('collectionBody') protected collectionBody?: ElementRef<HTMLElement>;\n\n  // ── Column Filters ──\n  /** Debounces server-side text filters so typing doesn't fire a request per keystroke. */\n  private readonly filterDebounce = new Subject<void>();\n  /**\n   * Most rows shown per page on mobile (< md). A **cap**, not an override: a data\n   * source asking for fewer rows keeps its own size. Raising a small page size on\n   * a phone is the opposite of what it is for — it pushes the paginator below the\n   * fold, which is most damaging inside a modal, where the sheet is already short\n   * and its footer is pinned over the bottom of the table.\n   */\n  private static readonly MOBILE_PAGE_SIZE = 10;\n  /**\n   * The component's own element, measured for every responsive decision. Typed via\n   * the annotation, not `inject(ElementRef<HTMLElement>)` — that form is a generic\n   * call on the token and leaves `nativeElement` untyped.\n   */\n  private readonly host: ElementRef<HTMLElement> = inject(ElementRef);\n\n  /** Whether the consumer owns filtering (server-side), mirroring {@link isServerSearched}. */\n  get isServerFiltered(): boolean {\n    return !!this.dataSource.onColumnFilterChange;\n  }\n\n  /** Every column filter that is actually set, in column order. */\n  get activeColumnFilters(): MnColumnFilter[] {\n    return this.dataSource.columns\n      .filter(col => col.filterable && isFilterValueActive(this.columnFilters[col.key]))\n      .map(col => ({\n        key: col.key,\n        type: this.filterTypeOf(col),\n        value: this.columnFilters[col.key] as ColumnFilterValue,\n      }));\n  }\n\n  /** Whether at least one column filter is active. */\n  get hasActiveFilters(): boolean {\n    return this.dataSource.columns.some(\n      col => col.filterable && isFilterValueActive(this.columnFilters[col.key]),\n    );\n  }\n\n  /**\n   * Updates a column filter value and either re-filters locally or hands the\n   * active filters to the consumer. Server-side text filters are debounced;\n   * every other type commits immediately.\n   */\n  onColumnFilter(column: ColumnDefinition<T>, value: ColumnFilterValue): void {\n    this.columnFilters[column.key] = value;\n    this.currentPage = 1;\n\n    if (this.isServerFiltered) {\n      if (this.filterTypeOf(column) === 'text') {\n        this.filterDebounce.next();\n      } else {\n        this.emitServerFilters();\n      }\n    } else {\n      this.applyFilter(false);\n    }\n    this.cdr.markForCheck();\n  }\n\n  /** Updates a tri-state boolean filter from its select ('' = any). */\n  onBooleanFilter(column: ColumnDefinition<T>, raw: string): void {\n    this.onColumnFilter(column, raw === '' ? '' : raw === 'true');\n  }\n\n  /** The effective filter type of a column, defaulting to text. */\n  filterTypeOf(column: ColumnDefinition<T>): ColumnFilterType {\n    return column.filterType ?? 'text';\n  }\n\n  /** Whether a specific column's filter currently narrows the rows. */\n  isColumnFilterActive(column: ColumnDefinition<T>): boolean {\n    return isFilterValueActive(this.columnFilters[column.key]);\n  }\n\n  /** Filter options formatted for mn-multi-select for a given column. */\n  getFilterMultiSelectOptions(column: ColumnDefinition<T>): MnMultiSelectOption<string>[] {\n    return (column.filterOptions ?? []).map(opt => ({label: opt.label, value: String(opt.value)}));\n  }\n\n  /** Label for the small-screen filters toggle button. */\n  get filtersButtonLabel(): string {\n    return this.resolveLabel(this.dataSource.filtersLabelKey, 'mnCollection.filters', this.dataSource.filtersLabel ?? 'Filters');\n  }\n\n  /**\n   * Summary a multi-select filter collapses to once more than one option is picked.\n   * Resolved with the `{count}` token intact for mn-multi-select to fill in.\n   */\n  get filterSelectedLabel(): string {\n    return this.resolveLabel(this.dataSource.filterLabels?.selectedKey, 'mnCollection.filterSelected', this.dataSource.filterLabels?.selected ?? '{count} selected');\n  }\n\n  /** Current text/select filter value for a column. */\n  textFilterValue(column: ColumnDefinition<T>): string {\n    const value = this.columnFilters[column.key];\n    return typeof value === 'string' ? value : '';\n  }\n\n  /** Current multi-select filter value for a column. */\n  multiFilterValue(column: ColumnDefinition<T>): string[] {\n    const value = this.columnFilters[column.key];\n    return Array.isArray(value) ? value : [];\n  }\n\n  /** Current boolean filter value for a column, as the select's string value. */\n  booleanFilterValue(column: ColumnDefinition<T>): string {\n    const value = this.columnFilters[column.key];\n    return typeof value === 'boolean' ? String(value) : '';\n  }\n\n  /** Resets every column filter and re-applies (or re-requests) filtering. */\n  clearAllFilters(): void {\n    this.seedFilterValues();\n    this.currentPage = 1;\n    if (this.isServerFiltered) {\n      this.emitServerFilters();\n    } else {\n      this.applyFilter(false);\n    }\n    this.cdr.markForCheck();\n  }\n\n  /** Whether any column has filtering enabled. */\n  get hasColumnFilters(): boolean {\n    return this.dataSource.columns.some(c => c.filterable);\n  }\n\n  /** Label for the \"clear all filters\" action in the small-screen panel. */\n  get clearFiltersButtonLabel(): string {\n    return this.resolveLabel(this.dataSource.clearFiltersLabelKey, 'mnCollection.clearAll', this.dataSource.clearFiltersLabel ?? 'Clear all');\n  }\n\n  /** Accessible label for the filter sheet's close button. */\n  get filtersCloseLabel(): string {\n    return this.resolveLabel(undefined, 'mnCollection.close', 'Close');\n  }\n\n  /** Heading for the selection summary, with the count filled in. */\n  get selectionSummaryTitle(): string {\n    const labels = this.dataSource.selectionSummaryLabels;\n    const template = this.resolveLabel(labels?.titleKey, 'mnCollection.selectedCount', labels?.title ?? 'Selected ({{count}})');\n    return template.replace('{{count}}', String(this.selectedIds.size));\n  }\n\n  /** Label for the summary's clear-everything action. */\n  get selectionClearAllLabel(): string {\n    const labels = this.dataSource.selectionSummaryLabels;\n    return this.resolveLabel(labels?.clearAllKey, 'mnCollection.clearAll', labels?.clearAll ?? 'Clear all');\n  }\n\n  /** Opens the small-screen filter bottom sheet. */\n  openFiltersPanel(): void {\n    this.filtersPanelOpen = true;\n  }\n\n  /** Plays the sheet's slide-down exit, then unmounts it. */\n  async closeFiltersPanel(): Promise<void> {\n    await this.filtersSheet?.startClosing();\n    this.filtersPanelOpen = false;\n    this.cdr.markForCheck();\n  }\n  private readonly baseTableClasses = 'w-full border-collapse overflow-y-hidden';\n  /**\n   * Column widths measured from the automatic layout and pinned, keyed by column\n   * key, for `stable`. Empty until the first render that has real rows on screen,\n   * and cleared whenever the table is resized so the next render re-measures.\n   */\n  private pinnedWidths = new Map<string, string>();\n\n  /** Sets sort/filter state seeded from the data source before the first filter pass. */\n  protected override beforeInitialFilter(): void {\n    super.beforeInitialFilter();\n\n    // Force the mobile row count below `md`; use the consumer's pageSize (or 10) above it.\n    this.desktopPageSize = this.dataSource.pageSize ?? 10;\n    this.applyResponsivePageSize(false);\n\n    // Seed the filter layout for the initial viewport (no markForCheck pre-render).\n    this.updateFilterLayout(false);\n\n    this.currentSort = this.dataSource.defaultSort ?? null;\n    this.seedFilterValues();\n  }\n  /**\n   * Whether {@link pinColumnWidths} has run. Tracked separately from\n   * {@link pinnedWidths} being non-empty, because the widest column is deliberately\n   * left unpinned and a table with a single flexible column therefore pins nothing.\n   */\n  private widthsPinned = false;\n\n  /**\n   * Recomputes whether the inline filter row should collapse into the panel.\n   * Closes the panel when returning to the wide layout so reopened state never\n   * leaks across the breakpoint. Marks for check only when the layout flips.\n   */\n  private updateFilterLayout(reflow: boolean): void {\n    const collapsed = this.isFilterViewport();\n    if (collapsed === this.filtersCollapsed) return;\n    this.filtersCollapsed = collapsed;\n    if (!collapsed) this.filtersPanelOpen = false;\n    if (reflow) this.cdr.markForCheck();\n  }\n\n  sort(column: ColumnDefinition<T>): void {\n    if (!column.sortType || column.sortType === ColumnSortType.NONE) return;\n\n    if (this.currentSort?.columnKey === column.key) {\n      this.currentSort = this.currentSort.direction === 'asc'\n        ? {columnKey: column.key, direction: 'desc'}\n        : null;\n    } else {\n      this.currentSort = {columnKey: column.key, direction: 'asc'};\n    }\n\n    this.sortChange.emit(this.currentSort);\n    this.applyFilter(false);\n  }\n\n  onRowClick(row: T): void {\n    if (this.hasSelection) {\n      this.toggle(row);\n    }\n    this.dataSource.onRowClick?.(row);\n    this.rowClick.emit(row);\n  }\n\n  // ── Sorting ──\n\n  /**\n   * Resolves the skeleton placeholder config for a column's cells.\n   * Falls back to a text-shaped bar at 75% width (the previous default); any\n   * fields the column provides override that default.\n   */\n  getColumnSkeletonData(column: ColumnDefinition<T>): Partial<MnSkeletonProps> {\n    const skeleton = column.skeleton;\n    const overrides = skeleton && !this.isTemplateRef(skeleton) ? skeleton : {};\n    return {shape: 'text', width: '75%', ...overrides};\n  }\n\n  getSortIcon(column: ColumnDefinition<T>): string {\n    if (!this.currentSort || this.currentSort.columnKey !== column.key) return '';\n    return this.currentSort.direction === 'asc' ? '▲' : '▼';\n  }\n\n  /**\n   * Accessible name for a column's inline filter control: the header text, or the column key when\n   * the header is a template.\n   * @param column - The filtered column.\n   */\n  filterLabel(column: ColumnDefinition<T>): string {\n    return typeof column.header === 'string' ? this.headerText(column) : column.key;\n  }\n\n  /**\n   * A string column's header text. `headerKey` is translated here, at render time, rather than\n   * only in `resolveTranslationKeys`: that runs on init and on a locale change, so a column a\n   * consumer adds afterwards (a permission-gated actions or image column) kept an empty header,\n   * which a screen reader announces as a nameless column.\n   * @param column - The column whose header is shown.\n   * @returns The translated key when the column has one, otherwise its literal header, or an\n   *   empty string for a template header (rendered through its own outlet instead).\n   */\n  headerText(column: ColumnDefinition<T>): string {\n    if (column.headerKey) {\n      return this.lang.t(column.headerKey);\n    }\n    return typeof column.header === 'string' ? column.header : '';\n  }\n\n  isSortable(column: ColumnDefinition<T>): boolean {\n    return !!column.sortType && column.sortType !== ColumnSortType.NONE;\n  }\n\n  // ── Row interaction ──\n\n  constructor() {\n    super();\n    // Server-side text filtering only: client-side filtering stays instant per keystroke.\n    this.filterDebounce\n      .pipe(debounceTime(300), takeUntilDestroyed())\n      .subscribe(() => {\n        this.emitServerFilters();\n        this.cdr.markForCheck();\n      });\n\n    // Watch the table's own box rather than the window: inside a modal, a sidebar\n    // or a narrow grid cell the table resizes without the window ever changing,\n    // and the window resizes without the table's share of it changing.\n    if (typeof ResizeObserver !== 'undefined') {\n      const observer = new ResizeObserver(() => this.onHostResize());\n      observer.observe(this.host.nativeElement);\n      inject(DestroyRef).onDestroy(() => observer.disconnect());\n    }\n\n    // `beforeInitialFilter` runs while the host may not be attached or laid out\n    // yet, so its width reads 0 and {@link measuredWidth} has to guess from the\n    // window — the one guess that is wrong for a table in a modal. Re-evaluate\n    // once after the first render, when the real width is available.\n    afterNextRender(() => this.onHostResize());\n\n    // The `stable` layout has to let the browser lay the table out automatically\n    // once before it can capture the result. This runs after every render because\n    // the first render usually has no rows yet (a server fetch is still in flight);\n    // the guards below make it a no-op until real rows are on screen, and the\n    // pinned widths then stop it from measuring again.\n    afterEveryRender(() => {\n      if (this.layoutMode !== 'stable') return;\n      if (this.widthsPinned || this.isLoadingState) return;\n      if (this.paginatedItems.length === 0) return;\n      this.pinColumnWidths();\n    });\n  }\n\n  /**\n   * Classes for the `<table>` element. `table-fixed` is added once column widths\n   * are no longer allowed to follow the content: always for the `fixed` layout, and\n   * for `stable` from the moment its widths have been measured and pinned.\n   */\n  get tableClasses(): string {\n    return this.widthsArePinned ? `${this.baseTableClasses} table-fixed` : this.baseTableClasses;\n  }\n\n  /** Page size to use at/above the `md` breakpoint (consumer's pageSize, or the user's selection). */\n  private desktopPageSize = 10;\n\n  /** Label for the summary's expand/collapse control. */\n  get selectionSummaryToggleLabel(): string {\n    const labels = this.dataSource.selectionSummaryLabels;\n    if (this.selectionSummaryExpanded) {\n      return this.resolveLabel(labels?.showLessKey, 'mnCollection.showLess', labels?.showLess ?? 'Show less');\n    }\n    const template = this.resolveLabel(labels?.showMoreKey, 'mnCollection.showMore', labels?.showMore ?? '+{{count}} more');\n    return template.replace('{{count}}', String(this.hiddenSelectionCount));\n  }\n\n  /** Placeholder and accessible name for the search box. */\n  get searchPlaceholderLabel(): string {\n    return this.resolveLabel(\n      this.dataSource.searchPlaceholderKey,\n      'mnCollection.search',\n      this.dataSource.searchPlaceholder ?? 'Search...',\n    );\n  }\n\n  /** Screen-reader-only header text of the selection column, so that column is never nameless. */\n  get selectionColumnLabel(): string {\n    return this.resolveLabel(undefined, 'mnCollection.selectionColumn', 'Selection');\n  }\n\n  /** Accessible name for the scrollable table region. */\n  get tableRegionLabel(): string {\n    return this.resolveLabel(this.dataSource.ariaLabel, 'mnCollection.dataTable', 'Data table');\n  }\n\n  /**\n   * Fewer tags once the table is narrow. A tag holding a person's full name takes\n   * a whole line at phone width, so the eight that read as a compact header on a\n   * wide table become eight stacked lines in a modal sheet — the summary then\n   * occupies more of the screen than the rows it is summarising.\n   *\n   * Reuses {@link filtersCollapsed} rather than measuring again: it is already\n   * maintained on every resize and means exactly \"this table is under 640px\".\n   * The heading still states the true total, so the hidden tags cost no information.\n   */\n  protected override get defaultSelectionSummaryLimit(): number {\n    return this.filtersCollapsed ? 5 : 8;\n  }\n\n  /** Tracks the desktop page size when the user picks one (selector only shows at >= md). */\n  override onPageSizeChange(newSize: number): void {\n    this.desktopPageSize = newSize;\n    super.onPageSizeChange(newSize);\n  }\n\n  /** The effective column-width strategy, defaulting to `stable`. */\n  get layoutMode(): 'auto' | 'fixed' | 'stable' {\n    return this.dataSource.appearance?.layout ?? 'stable';\n  }\n\n  /**\n   * Whether column widths have stopped following the cell content — `fixed` always,\n   * `stable` once {@link pinColumnWidths} has captured them. Drives `table-fixed`\n   * and the cell truncation together, so a cell is never clipped while the column\n   * it sits in could still have grown to fit it.\n   */\n  get widthsArePinned(): boolean {\n    return this.layoutMode === 'fixed' || (this.layoutMode === 'stable' && this.widthsPinned);\n  }\n\n  /** Any / Yes / No options for a boolean column filter. */\n  getBooleanFilterOptions(column: ColumnDefinition<T>): MnSelectOption<string>[] {\n    const labels = this.dataSource.filterLabels;\n    return [\n      {\n        label: column.filterPlaceholder ?? this.resolveLabel(labels?.anyKey, 'mnCollection.filterAny', labels?.any ?? 'Any'),\n        value: ''\n      },\n      {label: this.resolveLabel(labels?.yesKey, 'mnCollection.filterYes', labels?.yes ?? 'Yes'), value: 'true'},\n      {label: this.resolveLabel(labels?.noKey, 'mnCollection.filterNo', labels?.no ?? 'No'), value: 'false'},\n    ];\n  }\n\n  /**\n   * The width to render for a column: the consumer's own declared width always\n   * wins, then a width pinned by the `stable` layout, otherwise none.\n   * @param column The column being rendered.\n   * @returns A CSS width, or `null` to leave it to the layout algorithm.\n   */\n  columnWidth(column: ColumnDefinition<T>): string | null {\n    return column.width ?? this.pinnedWidths.get(column.key) ?? null;\n  }\n\n  /**\n   * The `title` tooltip for a cell, so text truncated by a pinned column stays\n   * readable. Only string cells have text to expose; template cells render their\n   * own markup and are left alone.\n   * @param column The column being rendered.\n   * @param row The row being rendered.\n   * @returns The full cell text, or `null` when there is nothing to expose.\n   */\n  cellTitle(column: ColumnDefinition<T>, row: T): string | null {\n    if (!this.widthsArePinned || typeof column.cell !== 'function') return null;\n    return column.cell(row) || null;\n  }\n\n  /**\n   * Falls back to the first column that renders a plain string, which is almost\n   * always the name-like column a person would use to identify the row. Template\n   * columns are skipped: they render markup this cannot flatten to a tag label.\n   * @param row The selected row.\n   * @returns The label, or null when every column renders a template.\n   */\n  protected override defaultSelectionLabel(row: T): string | null {\n    for (const column of this.dataSource.columns) {\n      if (typeof column.cell !== 'function') continue;\n      const value = column.cell(row);\n      if (value) return value;\n    }\n    return null;\n  }\n\n  /**\n   * Resolves table-specific translation keys (column headers/filters) plus the\n   * shared keys handled by the base.\n   */\n  protected override resolveTranslationKeys(): void {\n    super.resolveTranslationKeys();\n    for (const col of this.dataSource.columns) {\n      if (col.headerKey) {\n        col.header = this.lang.t(col.headerKey);\n      }\n      if (col.filterPlaceholderKey) {\n        col.filterPlaceholder = this.lang.t(col.filterPlaceholderKey);\n      }\n      // Row actions are deliberately not pre-resolved here: `rowActionLabel` translates\n      // at render time (a locale change calls markForCheck, so the next pass picks the\n      // new text up), which keeps a per-row `label`/`labelKey` accessor intact instead\n      // of being flattened to one string for every row.\n    }\n    if (this.dataSource.filtersLabelKey) {\n      this.dataSource.filtersLabel = this.lang.t(this.dataSource.filtersLabelKey);\n    }\n    if (this.dataSource.clearFiltersLabelKey) {\n      this.dataSource.clearFiltersLabel = this.lang.t(this.dataSource.clearFiltersLabelKey);\n    }\n    this.resolveFilterLabelKeys();\n    this.resolveSelectionSummaryKeys();\n  }\n\n  protected applyFilter(searchForItems: boolean): void {\n    let items = this.applySearchFilter(this.dataSource.dataRows.value ?? []);\n\n    // Per-column filters. Skipped entirely when the consumer owns filtering: the\n    // rows already are the filtered set, and re-filtering them locally would\n    // narrow the current page a second time.\n    if (!this.isServerFiltered) {\n      for (const col of this.dataSource.columns) {\n        const filterValue = this.columnFilters[col.key];\n        if (!col.filterable || !isFilterValueActive(filterValue)) continue;\n        items = items.filter(row => matchesColumnFilter(col, row, filterValue as ColumnFilterValue));\n      }\n    }\n\n    items = this.applySorting(items);\n\n    this.filteredItems = items;\n    this.applyPagination();\n\n    if (searchForItems) {\n      this.loadMoreRows();\n    }\n  }\n\n  /**\n   * Re-evaluate on a window resize too. The ResizeObserver covers every change to\n   * the table's own box, but {@link isMobileViewport} reads the window, which can\n   * change without the table's width following it (a fixed-width table, a modal\n   * pinned to a max width).\n   */\n  @HostListener('window:resize')\n  protected onWindowResize(): void {\n    this.onHostResize();\n  }\n\n  /** Re-evaluate responsive page size and filter layout when the table is resized. */\n  private onHostResize(): void {\n    // Pixel widths captured for the old box are meaningless in the new one.\n    this.unpinColumnWidths();\n    this.applyResponsivePageSize(true);\n    this.updateFilterLayout(true);\n  }\n\n  /**\n   * Captures the current, automatically-derived width of every visible column and\n   * pins it, which flips the table to `table-fixed` on the next render.\n   *\n   * Runs only with real rows on screen: measuring the loading skeletons would pin\n   * the placeholder bars' widths rather than the data's. Hidden columns\n   * ({@link ColumnBase.hiddenBelow}) measure 0 and are skipped, so they are free to\n   * size themselves if a resize later reveals them.\n   *\n   * The **widest** column is measured but deliberately left unpinned, so it absorbs\n   * whatever space the pinned ones leave over. Pinning every column instead makes the\n   * widths sum to slightly more than the container — `border-collapse` shares borders\n   * between neighbours, so rounding each cell's measured width over-counts them — and\n   * the table then overflows into a spurious horizontal scrollbar. Leaving one column\n   * elastic also means a later resize squeezes the widest column first instead of\n   * clipping every column equally.\n   */\n  private pinColumnWidths(): void {\n    const headerCells = this.host.nativeElement.querySelectorAll('thead tr:first-child th[data-column-key]');\n    const measured: { key: string; width: number }[] = [];\n    for (const cell of Array.from(headerCells) as HTMLElement[]) {\n      const key = cell.dataset['columnKey'];\n      const width = cell.getBoundingClientRect().width;\n      // A width of 0 means the column is hidden at this container width.\n      if (!key || width <= 0) continue;\n      measured.push({key, width});\n    }\n    if (measured.length === 0) return;\n\n    const widest = measured.reduce((a, b) => (b.width > a.width ? b : a));\n    const pinned = new Map<string, string>();\n    for (const {key, width} of measured) {\n      if (key === widest.key) continue;\n      pinned.set(key, `${Math.round(width)}px`);\n    }\n\n    this.pinnedWidths = pinned;\n    this.widthsPinned = true;\n    // Pinning changes row heights: cells stop wrapping and start truncating, so a\n    // full page becomes shorter than it was during the automatic pass. The reserved\n    // full-page floor was measured against those taller rows and would otherwise\n    // hold the body open, leaving dead space between the last row and the paginator.\n    this.invalidatePageHeight();\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * Drops the pinned widths so the next render with rows re-measures them. Called\n   * when the table is resized: the old pixel widths were shares of a box that no\n   * longer exists, and a resize is also what makes `hiddenBelow` columns come and\n   * go, changing which columns need a share at all.\n   */\n  private unpinColumnWidths(): void {\n    if (!this.widthsPinned) return;\n    this.pinnedWidths = new Map();\n    this.widthsPinned = false;\n    // The window:resize listener marks the view for us; a container-only resize arrives\n    // through the ResizeObserver, which does not.\n    this.cdr.markForCheck();\n    // Row heights are about to change back; the floor measured for the pinned\n    // layout does not describe the automatic one.\n    this.invalidatePageHeight();\n  }\n\n  // ── Template helpers ──\n\n  getCellValue(column: ColumnDefinition<T>, row: T): string {\n    if (typeof column.cell === 'function') return column.cell(row);\n    return '';\n  }\n\n  /** Returns the small-screen cell value for a column with cellSm defined. */\n  getCellSmValue(column: ColumnDefinition<T>, row: T): string {\n    if (column.cellSm && typeof column.cellSm.cell === 'function') return column.cellSm.cell(row);\n    return '';\n  }\n\n  // ── Row actions ──\n\n  /** The actions visible for a given row — those whose `hidden(row)` is not true. */\n  visibleRowActions(column: ColumnDefinition<T>, row: T): MnTableRowAction<T>[] {\n    return (column.actions ?? []).filter(action => !(action.hidden?.(row) ?? false));\n  }\n\n  /** Whether a row has any visible actions at all; when false its cell is left empty. */\n  hasRowActions(column: ColumnDefinition<T>, row: T): boolean {\n    return this.visibleRowActions(column, row).length > 0;\n  }\n\n  /**\n   * Whether a row's actions fold into the ⋯ menu below 450px. They do unless the row has\n   * exactly one visible action that renders as a bare icon: that button is narrower than the\n   * ⋯ trigger it would hide behind, so collapsing it only puts a second tap in front of the\n   * one command the row has.\n   */\n  collapsesRowActions(column: ColumnDefinition<T>, row: T): boolean {\n    const visible = this.visibleRowActions(column, row);\n    if (visible.length !== 1) return true;\n    const [only] = visible;\n    return this.showActionLabel(column, only, row);\n  }\n\n  /**\n   * Resolves a {@link MnRowValue}: either the fixed value, or the accessor applied to\n   * the row. Every per-row presentation field goes through here so the fixed and derived\n   * forms can never drift apart.\n   */\n  private resolveRowValue<V>(value: MnRowValue<T, V> | undefined, row: T): V | undefined {\n    return typeof value === 'function' ? (value as (row: T) => V)(row) : value;\n  }\n\n  /** The resolved label for an inline action button (translation key wins once resolved). */\n  rowActionLabel(action: MnTableRowAction<T>, row: T): string {\n    const labelKey = this.resolveRowValue(action.labelKey, row);\n    if (labelKey) return this.lang.t(labelKey);\n    return this.resolveRowValue(action.label, row) ?? '';\n  }\n\n  /** The resolved leading icon for an action on a given row, if it has one. */\n  rowActionIcon(action: MnTableRowAction<T>, row: T): MnActionIcon | undefined {\n    return this.resolveRowValue(action.icon, row);\n  }\n\n  /** Whether an inline action button should render its icon. */\n  showActionIcon(column: ColumnDefinition<T>, action: MnTableRowAction<T>, row: T): boolean {\n    return (column.actionsInline ?? 'both') !== 'label' && !!this.rowActionIcon(action, row);\n  }\n\n  /**\n   * Whether an inline action button should render its text label. In `'icon'` mode the\n   * label is hidden — unless the action has no icon, in which case it is shown anyway so\n   * the button is never blank.\n   */\n  showActionLabel(column: ColumnDefinition<T>, action: MnTableRowAction<T>, row: T): boolean {\n    if ((column.actionsInline ?? 'both') === 'icon') return !this.rowActionIcon(action, row);\n    return true;\n  }\n\n  /** Whether an action is disabled for the given row. */\n  isRowActionDisabled(action: MnTableRowAction<T>, row: T): boolean {\n    return action.disabled ? action.disabled(row) : false;\n  }\n\n  /**\n   * The effective colour for an action, used identically by the inline button and the\n   * collapsed ⋯-menu item so the two never diverge: an explicit `color`, else `'danger'`\n   * for a destructive action, else the default `'primary'`.\n   */\n  rowActionColor(action: MnTableRowAction<T>, row: T): MnDropdownActionColor {\n    return this.resolveRowValue(action.color, row) ?? (action.danger ? 'danger' : 'primary');\n  }\n\n  /** Invokes an action for a row. */\n  runRowAction(action: MnTableRowAction<T>, row: T): void {\n    action.run(row);\n  }\n\n  /** A stable, unique element id for a row's actions dropdown (aria wiring). */\n  actionsDropdownId(column: ColumnDefinition<T>, row: T): string {\n    return `mn-table-actions-${column.key}-${this.dataSource.getID(row)}`;\n  }\n\n  /** Maps a row's visible actions to mn-dropdown commands, binding the row into each. */\n  rowDropdownActions(column: ColumnDefinition<T>, row: T): MnDropdownAction[] {\n    return this.visibleRowActions(column, row).map(action => ({\n      // Per-row values are resolved here, but `labelKey` stays a *key* so the dropdown\n      // keeps re-translating it on a locale change rather than freezing today's text.\n      label: this.resolveRowValue(action.label, row),\n      labelKey: this.resolveRowValue(action.labelKey, row),\n      icon: this.rowActionIcon(action, row),\n      color: this.rowActionColor(action, row),\n      danger: action.danger,\n      disabled: this.isRowActionDisabled(action, row),\n      run: () => action.run(row),\n    }));\n  }\n\n  trackByKey = (_index: number, column: ColumnDefinition<T>): string => {\n    return column.key;\n  };\n\n  // ── Table CSS classes ──\n\n  /** True when the table is narrower than the filter-collapse breakpoint. */\n  private isFilterViewport(): boolean {\n    return this.measuredWidth() < MnTable.FILTER_COLLAPSE_WIDTH;\n  }\n\n  /**\n   * True when the **window** is below the `md` (768px) breakpoint.\n   *\n   * Deliberately viewport-based, unlike {@link isFilterViewport}: the forced\n   * mobile page size exists to keep a phone screen scrollable, and it is paired\n   * with the rows-per-page selector that mn-collection-pagination hides at the\n   * same viewport breakpoint. Measuring the table's own width instead would let\n   * the two disagree — a 700px table on a desktop would be pinned to the mobile\n   * row count while still offering the selector that overrides it.\n   */\n  private isMobileViewport(): boolean {\n    return typeof window !== 'undefined' && window.innerWidth < 768;\n  }\n\n  /**\n   * The table's own rendered width, which every responsive decision is made\n   * against — the same width the `@container` queries in the template use, so\n   * the TS and CSS halves of the responsive layout can never disagree.\n   *\n   * Falls back to the window width before the host has been laid out (and in\n   * SSR), which is the closest available approximation at that point.\n   * @returns The width in CSS pixels.\n   */\n  private measuredWidth(): number {\n    const width = this.host.nativeElement.getBoundingClientRect().width;\n    if (width > 0) return width;\n    return typeof window === 'undefined' ? Number.MAX_SAFE_INTEGER : window.innerWidth;\n  }\n\n  /**\n   * Applies the breakpoint-appropriate page size: capped at {@link MOBILE_PAGE_SIZE}\n   * below `md`, the desktop size at/above it. When the size actually changes, client-side tables\n   * re-slice locally and server-side tables ask the consumer to refetch, so the\n   * rendered rows update in every pagination mode (used at init and on window resize).\n   */\n  private applyResponsivePageSize(reflow: boolean): void {\n    const target = this.isMobileViewport()\n      ? Math.min(this.desktopPageSize, MnTable.MOBILE_PAGE_SIZE)\n      : this.desktopPageSize;\n    if (target === this.pageSize) return;\n    this.invalidatePageHeight();\n    this.pageSize = target;\n    this.currentPage = 1;\n\n    if (this.dataSource.paginationMode === 'client-side-pagination') {\n      this.applyPagination();\n    } else if (this.isServerPaginated) {\n      // Server owns the slice — tell the consumer to refetch with the new size.\n      this.dataSource.onPageSizeChange?.(target);\n    }\n\n    if (reflow) this.cdr.markForCheck();\n  }\n\n  get totalColumnCount(): number {\n    let count = this.dataSource.columns.length;\n    if (this.hasSelection) count++;\n    return count;\n  }\n\n  // ── Skeleton ──\n\n  /**\n   * Hands the active filters to the consumer. Locks the body height first so the\n   * skeleton swap during the refetch can't collapse the layout, matching\n   * {@link goToPage} and {@link onSearch}.\n   */\n  private emitServerFilters(): void {\n    this.lockBodyHeight();\n    this.dataSource.onColumnFilterChange?.(this.activeColumnFilters);\n  }\n\n  /** Resets every filterable column to its type's empty value. */\n  private seedFilterValues(): void {\n    for (const col of this.dataSource.columns) {\n      if (col.filterable) {\n        this.columnFilters[col.key] = emptyFilterValue(this.filterTypeOf(col));\n      }\n    }\n  }\n\n  // ── Filtering & sorting ──\n\n  /**\n   * Resolves the selection-summary labels from their translation keys. Resolved\n   * without params so the `{{count}}` / `{{label}}` placeholders survive for the\n   * getters to fill in per render.\n   */\n  private resolveSelectionSummaryKeys(): void {\n    const labels = this.dataSource.selectionSummaryLabels;\n    if (!labels) return;\n    if (labels.titleKey) labels.title = this.lang.t(labels.titleKey);\n    if (labels.clearAllKey) labels.clearAll = this.lang.t(labels.clearAllKey);\n    if (labels.removeKey) labels.remove = this.lang.t(labels.removeKey);\n    if (labels.showMoreKey) labels.showMore = this.lang.t(labels.showMoreKey);\n    if (labels.showLessKey) labels.showLess = this.lang.t(labels.showLessKey);\n  }\n\n  /** Resolves the range / boolean filter control labels from their translation keys. */\n  private resolveFilterLabelKeys(): void {\n    const labels = this.dataSource.filterLabels;\n    if (!labels) return;\n    const pairs = [\n      ['anyKey', 'any'], ['yesKey', 'yes'], ['noKey', 'no'], ['selectedKey', 'selected'],\n    ] as const;\n    for (const [keyProp, labelProp] of pairs) {\n      const key = labels[keyProp];\n      if (key) labels[labelProp] = this.lang.t(key);\n    }\n  }\n\n  private applySorting(items: T[]): T[] {\n    if (!this.currentSort) return items;\n\n    const column = this.dataSource.columns.find(c => c.key === this.currentSort!.columnKey);\n    if (!column || !column.sortType || column.sortType === ColumnSortType.NONE) return items;\n\n    const getValue = column.getRawValueToSort ?? ((row: T) => {\n      if (typeof column.cell === 'function') return column.cell(row);\n      return '';\n    });\n\n    const dir = this.currentSort.direction === 'asc' ? 1 : -1;\n\n    return [...items].sort((a, b) => {\n      const va = getValue(a);\n      const vb = getValue(b);\n\n      if (va == null && vb == null) return 0;\n      if (va == null) return 1;\n      if (vb == null) return -1;\n\n      switch (column.sortType) {\n        case ColumnSortType.ALPHABETICAL:\n          return String(va).localeCompare(String(vb)) * dir;\n        case ColumnSortType.NUMERICAL:\n          return (Number(va) - Number(vb)) * dir;\n        case ColumnSortType.DATE:\n          return (new Date(va as string | number).getTime() - new Date(vb as string | number).getTime()) * dir;\n        default:\n          return 0;\n      }\n    });\n  }\n\n  /** Filter options formatted for mn-select for a given column. */\n  getFilterSelectOptions(column: ColumnDefinition<T>): MnSelectOption<string>[] {\n    const placeholder = column.filterPlaceholder ?? this.resolveLabel(undefined, 'mnCollection.filterAll', 'All');\n    return [\n      {label: placeholder, value: ''},\n      ...(column.filterOptions ?? []).map(opt => ({label: opt.label, value: String(opt.value)})),\n    ];\n  }\n\n  /**\n   * Accessible label for a tag's remove button.\n   * @param row The row the tag stands for.\n   * @returns The label, naming the row so screen readers announce which one goes.\n   */\n  selectionRemoveLabel(row: T): string {\n    const labels = this.dataSource.selectionSummaryLabels;\n    const template = this.resolveLabel(labels?.removeKey, 'mnCollection.removeSelected', labels?.remove ?? 'Remove {{label}}');\n    return template.replace('{{label}}', this.selectionLabelFor(row));\n  }\n}\n","<!-- Everything that reflows lives inside a @container, so the breakpoints below\n     measure the table's own width rather than the window's. A table in a modal,\n     a sidebar or a narrow grid cell is far narrower than the viewport, and\n     viewport breakpoints would hand it a desktop layout it has no room for. -->\n<div class=\"@container\">\n  <!-- Selection summary: the whole selection, never paged, filtered or sorted. The\n       table below answers \"what could I pick?\", which is why it is searched and paged;\n       this answers \"what did I pick?\", which a paginated list cannot without hiding\n       most of the answer on some other page. -->\n  @if (showSelectionSummary) {\n    <div class=\"flex flex-col gap-2 rounded-md border border-base-300 bg-base-200/50 p-3 mb-3\">\n      <div class=\"flex items-center justify-between gap-2\">\n        <span class=\"text-sm font-medium text-base-content\">{{ selectionSummaryTitle }}</span>\n        <button\n          (click)=\"clearSelection()\"\n          [data]=\"{ variant: 'text', color: 'gray', size: 'sm', borderRadius: 'md', hover: true }\"\n          class=\"gap-1 shrink-0\"\n          mnButton\n          type=\"button\"\n        >\n          <svg [size]=\"14\" [lucideIcon]=\"icons.X\"></svg>\n          <span>{{ selectionClearAllLabel }}</span>\n        </button>\n      </div>\n      <!-- Only the first few tags render; the rest collapse behind a \"+N more\" control.\n           The heading's count always states the true total, so this hides tags, never\n           information. Expanded, the list is height-capped and scrolls, so even a\n           selection of hundreds cannot push the table off screen. -->\n      <ul\n        [class.max-h-28]=\"selectionSummaryExpanded\"\n        [class.overflow-y-auto]=\"selectionSummaryExpanded\"\n        class=\"flex flex-wrap gap-1.5 list-none m-0 p-0\"\n      >\n        @for (row of visibleSelectionRows; track dataSource.getID(row)) {\n          <li\n            class=\"inline-flex items-center gap-1 rounded-full bg-base-100 border border-base-300 pl-2.5 pr-1 py-0.5 text-xs text-base-content max-w-full\">\n            <span [attr.title]=\"selectionLabelFor(row)\" class=\"truncate\">{{ selectionLabelFor(row) }}</span>\n            <button\n              (click)=\"removeSelection(row)\"\n              [attr.aria-label]=\"selectionRemoveLabel(row)\"\n              class=\"shrink-0 rounded-full p-0.5 hover:bg-base-300 transition-colors cursor-pointer\"\n              type=\"button\"\n            >\n              <svg [size]=\"12\" [lucideIcon]=\"icons.X\"></svg>\n            </button>\n          </li>\n        }\n        @if (hiddenSelectionCount > 0 || selectionSummaryExpanded) {\n          <li>\n            <button\n              (click)=\"toggleSelectionSummary()\"\n              [attr.aria-expanded]=\"selectionSummaryExpanded\"\n              [data]=\"{ variant: 'text', color: 'primary', size: 'sm', borderRadius: 'md', hover: true }\"\n              class=\"text-xs\"\n              mnButton\n              type=\"button\"\n            >\n              {{ selectionSummaryToggleLabel }}\n            </button>\n          </li>\n        }\n      </ul>\n    </div>\n  }\n\n  <!-- Toolbar: custom toolbar template + search. Only rendered when it has content,\n       so an unsearchable table without toolbar templates emits no empty spacer. -->\n@if (isSearchable || dataSource.toolbarLeftTemplate || dataSource.toolbarRightTemplate || (hasColumnFilters && filtersCollapsed)) {\n  <div class=\"flex flex-col @min-[420px]:flex-row @min-[420px]:items-center justify-between gap-2 mb-3\">\n    <div class=\"flex items-center gap-2 w-full @min-[420px]:w-auto\">\n    @if (dataSource.toolbarLeftTemplate) {\n      <div class=\"flex flex-col w-full @min-[420px]:w-auto @min-[420px]:flex-row\">\n        <ng-container [ngTemplateOutlet]=\"dataSource.toolbarLeftTemplate\"></ng-container>\n      </div>\n    }\n  </div>\n    <div\n      class=\"flex flex-col @min-[420px]:flex-row @min-[420px]:items-center gap-2 w-full @min-[420px]:flex-1 @min-[560px]:flex-none @min-[560px]:w-auto\">\n    @if (isSearchable) {\n      <!-- Enter must not submit a surrounding form: the search box belongs to the\n           table's chrome, not to whatever form the table happens to sit in. -->\n      <mn-lib-input-field\n        (keydown.enter)=\"$event.preventDefault()\"\n        class=\"w-full @min-[420px]:flex-1 @min-[560px]:max-w-64\"\n        [props]=\"{\n            id: 'mn-table-search',\n            type: 'search',\n            label: '',\n            ariaLabel: searchPlaceholderLabel,\n            placeholder: searchPlaceholderLabel,\n            size: 'sm',\n            borderRadius: 'md',\n            fullWidth: true\n          }\"\n        [ngModel]=\"searchValue\"\n        (ngModelChange)=\"onSearch($event)\"\n      ></mn-lib-input-field>\n    }\n    @if (dataSource.toolbarRightTemplate) {\n      <div class=\"flex flex-col w-full @min-[420px]:w-auto @min-[420px]:flex-row\">\n        <ng-container [ngTemplateOutlet]=\"dataSource.toolbarRightTemplate\"></ng-container>\n      </div>\n    }\n    <!-- Small-screen filter toggle: replaces the inline per-column filter row below 640px -->\n    @if (hasColumnFilters && filtersCollapsed) {\n      <button\n        type=\"button\"\n        mnButton\n        [data]=\"{ variant: 'outline', color: 'primary', size: 'md', borderRadius: 'md', hover: true }\"\n        class=\"w-full @min-[420px]:w-auto gap-1.5\"\n        [attr.aria-expanded]=\"filtersPanelOpen\"\n        aria-controls=\"mn-table-filters-panel\"\n        (click)=\"openFiltersPanel()\"\n      >\n        <svg [lucideIcon]=\"icons.Funnel\" [size]=\"15\"></svg>\n        <span>{{ filtersButtonLabel }}</span>\n      </button>\n    }\n  </div>\n</div>\n}\n\n<!-- Small-screen filters: full-width fields decoupled from column widths, presented\n     as a bottom sheet so they overlay rather than push the table down. -->\n@if (hasColumnFilters && filtersCollapsed && filtersPanelOpen) {\n  <mn-bottom-sheet\n    #filtersSheet\n    (dismiss)=\"filtersPanelOpen = false\"\n    [ariaLabel]=\"filtersButtonLabel\"\n    [growWithKeyboard]=\"true\"\n    [maxHeightVh]=\"80\"\n  >\n    <div id=\"mn-table-filters-panel\" class=\"flex flex-col gap-3 px-4 pb-4\">\n      <span class=\"text-base font-semibold text-base-content\">{{ filtersButtonLabel }}</span>\n      @for (column of dataSource.columns; track column.key) {\n        @if (column.filterable) {\n          <div class=\"flex flex-col gap-1\">\n            <label\n              class=\"text-xs font-medium text-base-content/70\"\n              [attr.for]=\"'mn-table-filter-panel-' + column.key\"\n            >\n              @if (isTemplateRef(column.header)) {\n                <ng-container [ngTemplateOutlet]=\"$any(column.header)\"></ng-container>\n              } @else {\n                {{ headerText(column) }}\n              }\n            </label>\n            <ng-container\n              [ngTemplateOutletContext]=\"{ $implicit: column, idScope: 'panel' }\"\n              [ngTemplateOutlet]=\"filterField\"\n            ></ng-container>\n          </div>\n        }\n      }\n      @if (hasActiveFilters) {\n        <button\n          type=\"button\"\n          mnButton\n          [data]=\"{ variant: 'text', color: 'gray', size: 'sm', borderRadius: 'md', hover: true }\"\n          class=\"self-start gap-1\"\n          (click)=\"clearAllFilters()\"\n        >\n          <svg [lucideIcon]=\"icons.X\" [size]=\"14\"></svg>\n          <span>{{ clearFiltersButtonLabel }}</span>\n        </button>\n      }\n      <div class=\"mt-1 flex min-[400px]:justify-end\">\n        <button\n          type=\"button\"\n          mnButton\n          [data]=\"{ variant: 'fill', color: 'primary', size: 'md', borderRadius: 'md', hover: true }\"\n          class=\"w-full min-[400px]:w-auto\"\n          (click)=\"closeFiltersPanel()\"\n        >\n          <span>{{ filtersCloseLabel }}</span>\n        </button>\n      </div>\n    </div>\n  </mn-bottom-sheet>\n}\n\n<!-- Announces loading. The skeletons are aria-hidden, so without this a screen reader hears\n     nothing while rows load. The region stays in the DOM and only its text changes, which is\n     what makes assistive tech read it; one inserted with its text already set is often missed. -->\n<span class=\"sr-only\" role=\"status\">{{ isLoadingState ? loadingLabel : '' }}</span>\n\n<!-- Table wrapper with horizontal scroll -->\n  <div #collectionBody [attr.aria-busy]=\"isLoadingState || null\" [attr.aria-label]=\"tableRegionLabel\" [style.min-height.px]=\"bodyMinHeight\"\n     class=\"overflow-x-auto\"\n     role=\"region\">\n  <table [class]=\"tableClasses\">\n    <thead>\n      <tr class=\"bg-base-100\">\n        <!-- Selection column header. It always carries a screen-reader-only name: a single-select\n             table has nothing else in this cell, and a multi-select one only a checkbox, so\n             without it the column is announced as a nameless header (axe empty-table-header). -->\n        @if (hasSelection) {\n          <th class=\"w-10 text-center text-sm px-2 py-2\">\n            <span class=\"sr-only\">{{ selectionColumnLabel }}</span>\n            @if (isMultiSelect) {\n              <mn-lib-checkbox\n                (checkedChange)=\"toggleAll()\"\n                [checked]=\"allSelected\"\n                [props]=\"{ id: 'mn-table-select-all', size: 'sm' }\"\n              ></mn-lib-checkbox>\n            }\n          </th>\n        }\n\n        <!-- Data columns -->\n        @for (column of dataSource.columns; track column.key) {\n          <th\n            [attr.data-column-key]=\"column.key\"\n            [class.truncate]=\"widthsArePinned\"\n            [class.cursor-pointer]=\"isSortable(column)\"\n            [class.select-none]=\"isSortable(column)\"\n            [class.hover:bg-base-200]=\"isSortable(column)\"\n            [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n            [class.text-center]=\"column.align === 'center'\"\n            [class.text-right]=\"column.align === 'right'\"\n            [mnHiddenBelow]=\"column.hiddenBelow\"\n            [style.width]=\"columnWidth(column)\"\n            [attr.aria-sort]=\"currentSort?.columnKey === column.key ? (currentSort!.direction === 'asc' ? 'ascending' : 'descending') : null\"\n            class=\"text-sm px-2 py-1 @min-[640px]:px-4 @min-[640px]:py-2 whitespace-nowrap\"\n            (click)=\"sort(column)\"\n          >\n            <!-- The header content is declared once; a sortable column wraps it in a real button so\n                 the sort is reachable by keyboard. The button's click stops there, so the th's own\n                 click (which keeps the cell padding clickable) does not sort a second time. -->\n            <ng-template #headerContent>\n              @if (isTemplateRef(column.header)) {\n                <ng-container [ngTemplateOutlet]=\"$any(column.header)\"></ng-container>\n              } @else {\n                <span>{{ headerText(column) }}</span>\n              }\n              @if (isSortable(column)) {\n                <span class=\"text-[0.65rem] opacity-70 min-w-3 inline-block\" aria-hidden=\"true\">{{ getSortIcon(column) }}</span>\n              }\n            </ng-template>\n            @if (isSortable(column)) {\n              <button type=\"button\" class=\"inline-flex items-center gap-1 cursor-pointer\" (click)=\"$event.stopPropagation(); sort(column)\">\n                <ng-container [ngTemplateOutlet]=\"headerContent\"></ng-container>\n              </button>\n            } @else {\n              <span class=\"inline-flex items-center gap-1\">\n                <ng-container [ngTemplateOutlet]=\"headerContent\"></ng-container>\n              </span>\n            }\n          </th>\n        }\n\n      </tr>\n\n      <!-- Per-column filter row (wide screens only; collapses into a panel below 640px).\n           The cells are `td`, not `th`: they hold form controls, not headings, and a\n           column without a filter would otherwise be an empty header, which assistive tech\n           announces as a nameless column (axe `empty-table-header`). `font-normal` stays\n           so a consumer's thead styling cannot make the controls bold. -->\n      @if (hasColumnFilters && !filtersCollapsed) {\n        <tr class=\"bg-base-100 border-b border-base-300 font-normal\">\n          @if (hasSelection) {\n            <td class=\"px-2 py-1 font-normal\"></td>\n          }\n          @for (column of dataSource.columns; track column.key) {\n            <td\n              class=\"px-4 py-2 font-normal\"\n              [mnHiddenBelow]=\"column.hiddenBelow\"\n            >\n              @if (column.filterable) {\n                <!-- Every filter renders as an ordinary control right under its\n                     header. The rich types used to hide behind a button that opened\n                     a floating panel, which cost a click to discover, a click to\n                     apply, and hid whether a column was even filterable. -->\n                <ng-container\n                  [ngTemplateOutletContext]=\"{ $implicit: column, idScope: 'inline' }\"\n                  [ngTemplateOutlet]=\"filterField\"\n                ></ng-container>\n              }\n            </td>\n          }\n        </tr>\n      }\n    </thead>\n\n    <tbody>\n      <!-- Loading state -->\n        @if (isLoadingState) {\n        @for (_ of skeletonRows; track $index) {\n          <tr>\n            @if (hasSelection) {\n              <td class=\"px-2 py-3\">\n                <mn-skeleton [data]=\"{ shape: 'rectangle', width: '1rem', height: '1rem' }\"></mn-skeleton>\n              </td>\n            }\n            @for (column of dataSource.columns; track column.key) {\n              <td class=\"px-4 py-3\"\n                [mnHiddenBelow]=\"column.hiddenBelow\"\n                  [style.width]=\"columnWidth(column)\"\n              >\n                @if (isTemplateRef(column.skeleton)) {\n                  <ng-container [ngTemplateOutlet]=\"$any(column.skeleton)\"></ng-container>\n                } @else {\n                  <mn-skeleton [data]=\"getColumnSkeletonData(column)\"></mn-skeleton>\n                }\n              </td>\n            }\n          </tr>\n        }\n        } @else if (isErrorState) {\n          <!-- Error state -->\n          <tr class=\"bg-base-100\">\n            <td [attr.colspan]=\"totalColumnCount\" class=\"text-center text-xs py-8\">\n              @if (dataSource.errorTemplate) {\n                <ng-container [ngTemplateOutlet]=\"dataSource.errorTemplate\"></ng-container>\n              } @else {\n                <div class=\"flex flex-col items-center gap-2 text-error\">\n                  <p class=\"text-sm\">{{ dataSource.errorMessage }}</p>\n                </div>\n              }\n            </td>\n          </tr>\n      } @else {\n        <!-- Empty state -->\n        @if (filteredItems.length === 0) {\n          <tr class=\"bg-base-100\">\n            <td [attr.colspan]=\"totalColumnCount\" class=\"text-center text-xs py-8\">\n              @if (dataSource.emptyTemplate) {\n                <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n              } @else {\n                <div class=\"flex flex-col items-center gap-2 text-base-content/50\">\n                  @if (dataSource.emptyIcon !== null) {\n                    <svg [lucideIcon]=\"dataSource.emptyIcon ?? defaultEmptyIcon\" [size]=\"32\" [strokeWidth]=\"1.5\"></svg>\n                  }\n                  <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n                </div>\n              }\n            </td>\n          </tr>\n        }\n\n        <!-- Data rows -->\n        @for (row of paginatedItems; track trackByID($index, row); let odd = $odd; let last = $last) {\n          <tr\n            class=\"bg-base-100 transition-colors duration-150 hover:cursor-pointer\"\n            [ngClass]=\"{'bg-primary/10': isSelected(row)}\"\n            [class.bg-base-200]=\"!isSelected(row) && odd && dataSource.appearance?.striped\"\n            [class.hover:bg-base-200]=\"dataSource.appearance?.hover !== false\"\n            [class.cursor-pointer]=\"!!dataSource.onRowClick\"\n            [class.border-b]=\"!last\"\n            [class.border-base-300]=\"!last\"\n            [class.border-b-1]=\"last\"\n            [class.border-black]=\"last\"\n            [class.shadow-3xl]=\"last\"\n            (click)=\"onRowClick(row)\"\n          >\n            <!-- Selection checkbox -->\n            @if (hasSelection) {\n              <td (click)=\"$event.stopPropagation()\" class=\"w-10 text-center px-2 py-2\">\n                <mn-lib-checkbox\n                  (checkedChange)=\"toggle(row)\"\n                  [checked]=\"isSelected(row)\"\n                  [props]=\"{ id: 'mn-table-row-' + $index, size: 'sm' }\"\n                ></mn-lib-checkbox>\n              </td>\n            }\n\n            <!-- Data cells -->\n            @for (column of dataSource.columns; track column.key) {\n              <td\n                [attr.title]=\"cellTitle(column, row)\"\n                [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n                [class.text-center]=\"column.align === 'center'\"\n                [class.text-right]=\"column.align === 'right'\"\n                [class.truncate]=\"widthsArePinned\"\n                [mnHiddenBelow]=\"column.hiddenBelow\"\n                [style.width]=\"columnWidth(column)\"\n                class=\"text-xs px-2 py-1 @min-[640px]:px-4 @min-[640px]:py-2\"\n              >\n                @if (column.actions) {\n                  <!-- Actions column: inline command buttons that collapse into a ⋯ menu\n                       once the table is narrower than 450px (container query), for every\n                       row with actions. A row with no visible actions renders nothing.\n                       A row with a single icon-only action never collapses: one icon button\n                       is narrower than the ⋯ trigger it would hide behind, so folding it\n                       only costs a tap. -->\n                  @if (hasRowActions(column, row)) {\n                  <div class=\"inline-flex items-center gap-1\"\n                       [class.justify-end]=\"(column.align ?? 'left') === 'right'\">\n                    @if (collapsesRowActions(column, row)) {\n                      <span class=\"hidden items-center gap-1 @min-[450px]:inline-flex\">\n                        <ng-container [ngTemplateOutletContext]=\"{ column: column, row: row }\"\n                                      [ngTemplateOutlet]=\"actionButtons\"></ng-container>\n                      </span>\n                      <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n                      <span class=\"@min-[450px]:hidden\" (click)=\"$event.stopPropagation()\">\n                        <mn-lib-dropdown [datasource]=\"{\n                          id: actionsDropdownId(column, row),\n                          actions: rowDropdownActions(column, row),\n                          menuLabel: headerText(column),\n                          size: 'sm'\n                        }\"></mn-lib-dropdown>\n                      </span>\n                    } @else {\n                      <span class=\"inline-flex items-center gap-1\">\n                        <ng-container [ngTemplateOutletContext]=\"{ column: column, row: row }\"\n                                      [ngTemplateOutlet]=\"actionButtons\"></ng-container>\n                      </span>\n                    }\n                  </div>\n                  }\n                } @else if (column.cellSm) {\n                  <!-- Default cell: hidden below the cellSm breakpoint -->\n                  <span [mnShowAbove]=\"column.cellSm.below\">\n                    @if (isTemplateRef(column.cell)) {\n                      <ng-container [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"\n                                    [ngTemplateOutlet]=\"$any(column.cell)\"></ng-container>\n                    } @else {\n                      {{ getCellValue(column, row) }}\n                    }\n                  </span>\n                  <!-- Small cell: shown only below the cellSm breakpoint -->\n                  <span [mnShowBelow]=\"column.cellSm.below\">\n                    @if (isTemplateRef(column.cellSm.cell)) {\n                      <ng-container [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"\n                                    [ngTemplateOutlet]=\"$any(column.cellSm.cell)\"></ng-container>\n                    } @else {\n                      {{ getCellSmValue(column, row) }}\n                    }\n                  </span>\n                } @else {\n                  @if (isTemplateRef(column.cell)) {\n                    <ng-container [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"\n                                  [ngTemplateOutlet]=\"$any(column.cell)\"></ng-container>\n                  } @else {\n                    {{ getCellValue(column, row) }}\n                  }\n                }\n              </td>\n            }\n\n          </tr>\n        }\n      }\n    </tbody>\n  </table>\n</div>\n\n<!-- Load more + pagination -->\n<mn-collection-pagination\n  (loadMore)=\"loadMoreRows()\"\n  (pageChange)=\"goToPage($event)\"\n  (pageSizeChange)=\"onPageSizeChange($event)\"\n  [currentPage]=\"currentPage\"\n  [isPaginated]=\"isPaginated\"\n  [isServerPaginated]=\"isServerPaginated\"\n  [labels]=\"dataSource.labels\"\n  [loadingMoreRows]=\"loadingMoreRows\"\n  [pageSizeSelectOptions]=\"pageSizeSelectOptions\"\n  [pageSize]=\"pageSize\"\n  [showLoadMore]=\"showLoadMore\"\n  [totalItemCount]=\"totalItemCount\"\n  [totalPages]=\"totalPages\"\n  [visiblePages]=\"visiblePages\"\n  idPrefix=\"mn-table\"\n></mn-collection-pagination>\n</div>\n\n<!-- Single source of truth for every filter control, reused by the inline header\n     row and the small-screen panel. `idScope` keeps element ids unique across\n     both placements. -->\n<ng-template #filterField let-column let-idScope=\"idScope\">\n  @switch (filterTypeOf(column)) {\n    @case ('select') {\n      <mn-lib-select\n        (ngModelChange)=\"onColumnFilter(column, $event)\"\n        [disabled]=\"column.filterDisabled ?? false\"\n        [ngModel]=\"textFilterValue(column)\"\n        [props]=\"{\n          id: 'mn-table-filter-' + idScope + '-' + column.key,\n          ariaLabel: filterLabel(column),\n          options: getFilterSelectOptions(column),\n          size: 'sm',\n          fullWidth: true\n        }\"\n      ></mn-lib-select>\n    }\n    @case ('multi-select') {\n      <mn-lib-multi-select\n        (ngModelChange)=\"onColumnFilter(column, $event)\"\n        [disabled]=\"column.filterDisabled ?? false\"\n        [ngModel]=\"multiFilterValue(column)\"\n        [props]=\"{\n          id: 'mn-table-filter-' + idScope + '-' + column.key,\n          ariaLabel: filterLabel(column),\n          options: getFilterMultiSelectOptions(column),\n          placeholder: column.filterPlaceholder ?? '',\n          collapsePlaceholder: filterSelectedLabel,\n          collapseThreshold: 1,\n          size: 'sm',\n          fullWidth: true\n        }\"\n      ></mn-lib-multi-select>\n    }\n    @case ('boolean') {\n      <mn-lib-select\n        (ngModelChange)=\"onBooleanFilter(column, $event)\"\n        [disabled]=\"column.filterDisabled ?? false\"\n        [ngModel]=\"booleanFilterValue(column)\"\n        [props]=\"{\n          id: 'mn-table-filter-' + idScope + '-' + column.key,\n          ariaLabel: filterLabel(column),\n          options: getBooleanFilterOptions(column),\n          size: 'sm',\n          fullWidth: true\n        }\"\n      ></mn-lib-select>\n    }\n    @default {\n      <mn-lib-input-field\n        (keydown.enter)=\"$event.preventDefault()\"\n        (ngModelChange)=\"onColumnFilter(column, $event)\"\n        [disabled]=\"column.filterDisabled ?? false\"\n        [ngModel]=\"textFilterValue(column)\"\n        [props]=\"{\n          id: 'mn-table-filter-' + idScope + '-' + column.key,\n          type: 'text',\n          label: '',\n          placeholder: column.filterPlaceholder ?? '',\n          ariaLabel: column.filterPlaceholder ?? '',\n          autocomplete: column.filterAutocomplete ?? undefined,\n          size: 'sm',\n          borderRadius: 'md',\n          fullWidth: true,\n          hover: true\n        }\"\n      ></mn-lib-input-field>\n    }\n  }\n</ng-template>\n\n<!-- Inline action buttons for an actions column, shared by the wide-table layout and\n     (implicitly) mirrored by the ⋯ menu below 450px. -->\n<ng-template #actionButtons let-column=\"column\" let-row=\"row\">\n  @for (action of visibleRowActions(column, row); track $index) {\n    <button\n      mnButton\n      type=\"button\"\n      [data]=\"{\n        size: 'sm',\n        variant: 'text',\n        color: rowActionColor(action, row),\n        disabled: isRowActionDisabled(action, row)\n      }\"\n      class=\"cursor-pointer\"\n      (click)=\"$event.stopPropagation(); runRowAction(action, row)\"\n      [attr.aria-label]=\"rowActionLabel(action, row)\"\n      [attr.title]=\"showActionLabel(column, action, row) ? null : rowActionLabel(action, row)\"\n    >\n      @if (showActionIcon(column, action, row)) {\n        <span class=\"inline-flex items-center shrink-0\">\n          @let icon = rowActionIcon(action, row);\n          @if (isTemplateRef(icon)) {\n            <ng-container [ngTemplateOutlet]=\"icon\"></ng-container>\n          } @else {\n            <!-- Data icon: sized here to match the sm button's text, so a caller can\n                 declare the action in TypeScript without owning a template. -->\n            <svg [lucideIcon]=\"$any(icon)\" [size]=\"17\"></svg>\n          }\n        </span>\n      }\n      @if (showActionLabel(column, action, row)) {\n        <span>{{ rowActionLabel(action, row) }}</span>\n      }\n    </button>\n  }\n</ng-template>\n","import {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Output,\n  TemplateRef,\n  ViewChild,\n} from '@angular/core';\nimport {NgClass, NgTemplateOutlet} from '@angular/common';\nimport {FormsModule} from '@angular/forms';\nimport {LucideDynamicIcon} from '@lucide/angular';\nimport {ListDataSource} from './mn-list.types';\nimport {MnCheckbox} from 'mn-angular-lib/forms';\nimport {MnInputField} from 'mn-angular-lib/forms';\nimport {MnSkeleton, MnSkeletonProps} from 'mn-angular-lib/button';\nimport {MnCollectionPagination, MnSelectableCollectionBase} from '../mn-collection';\n\n/** Default skeleton lines reproducing the previous two-bar placeholder. */\nconst DEFAULT_LIST_SKELETON_LINES: Partial<MnSkeletonProps>[] = [\n  {shape: 'text', width: '75%'},\n  {shape: 'text', width: '50%', height: '0.75rem'},\n];\n\n@Component({\n  selector: 'mn-list',\n  standalone: true,\n  imports: [NgClass, NgTemplateOutlet, FormsModule, MnCheckbox, MnInputField, MnSkeleton, MnCollectionPagination, LucideDynamicIcon],\n  templateUrl: './mn-list.component.html',\n  styleUrl: './mn-list.component.css',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MnList<T = unknown>\n  extends MnSelectableCollectionBase<T, ListDataSource<T>> {\n  @Output() itemClick = new EventEmitter<T>();\n\n  protected override readonly componentName = 'MnList';\n\n  /** Skeleton lines rendered for each placeholder item, falling back to the default two-bar layout. */\n  get skeletonLines(): Partial<MnSkeletonProps>[] {\n    const skeleton = this.dataSource.skeleton;\n    if (skeleton && !this.isTemplateRef(skeleton)) {\n      return skeleton.lines;\n    }\n    return DEFAULT_LIST_SKELETON_LINES;\n  }\n\n  // ── Item interaction ──\n\n  onItemClick(item: T): void {\n    this.dataSource.onItemClick?.(item);\n    this.itemClick.emit(item);\n  }\n\n  /**\n   * Keyboard activation of a clickable item: Enter and Space open it, as they would a button.\n   * Handled on keydown so Space does not scroll the page first, and only when the item itself has\n   * focus, so a checkbox or button inside the item keeps its own keys.\n   * @param event - The keydown on the item.\n   * @param item - The item the key was pressed on.\n   */\n  onItemKeydown(event: KeyboardEvent, item: T): void {\n    if (!this.dataSource.onItemClick || event.target !== event.currentTarget) return;\n    if (event.key !== 'Enter' && event.key !== ' ') return;\n    event.preventDefault();\n    this.onItemClick(item);\n  }\n\n  // ── Skeleton ──\n\n  /**\n   * The toolbar template the base class watches for identity changes. Prefers the\n   * left slot, then the right, then the deprecated `toolbarTemplate`, so a list\n   * using any single slot still re-renders when that template is swapped.\n   */\n  protected get trackedToolbarTemplate(): TemplateRef<unknown> | undefined {\n    return (\n      this.dataSource?.toolbarLeftTemplate ??\n      this.dataSource?.toolbarRightTemplate ??\n      this.dataSource?.toolbarTemplate\n    );\n  }\n\n  @ViewChild('collectionBody') protected collectionBody?: ElementRef<HTMLElement>;\n\n  // ── Filtering ──\n\n  protected applyFilter(searchForItems: boolean): void {\n    this.filteredItems = this.applySearchFilter(this.dataSource.dataRows.value);\n    this.applyPagination();\n\n    if (searchForItems) {\n      this.loadMoreRows();\n    }\n  }\n\n  /** Accessible name for the scrollable list region. */\n  get listRegionLabel(): string {\n    return this.resolveLabel(undefined, 'mnCollection.dataList', 'Data list');\n  }\n\n  /** Label on the header checkbox that selects or clears every visible row. */\n  get selectAllLabel(): string {\n    return this.resolveLabel(undefined, 'mnCollection.selectAll', 'Select all');\n  }\n}\n","<!-- Toolbar: left template, then search + right template. Below 375px each group\n     takes its own full-width row; from 375px up the left group sits at the start\n     and the search group at the end. Structure and classes mirror mn-table so all\n     collections behave identically at every width. -->\n@if (\n  isSearchable ||\n  dataSource.toolbarLeftTemplate ||\n  dataSource.toolbarRightTemplate ||\n  dataSource.toolbarTemplate\n) {\n  <div class=\"flex flex-col min-[375px]:flex-row min-[375px]:items-center justify-between gap-2 mb-3\">\n    <div class=\"flex items-center gap-2 w-full min-[375px]:w-auto\">\n      @if (dataSource.toolbarLeftTemplate) {\n        <div class=\"flex flex-col w-full min-[375px]:w-auto min-[375px]:flex-row\">\n          <ng-container [ngTemplateOutlet]=\"dataSource.toolbarLeftTemplate\"></ng-container>\n        </div>\n      }\n    </div>\n    <div\n      class=\"flex flex-col min-[375px]:flex-row min-[375px]:items-center gap-2 w-full min-[375px]:flex-1 min-[480px]:flex-none min-[480px]:w-auto\">\n      @if (isSearchable) {\n        <!-- Enter must not submit a surrounding form: the search box is the\n             collection's own chrome, not a field of whatever form it sits in. -->\n        <mn-lib-input-field\n          (keydown.enter)=\"$event.preventDefault()\"\n          (ngModelChange)=\"onSearch($event)\"\n          [ngModel]=\"searchValue\"\n          [props]=\"{\n            id: 'mn-list-search',\n            type: 'search',\n            label: '',\n            ariaLabel: dataSource.searchPlaceholder ?? 'Search...',\n            placeholder: dataSource.searchPlaceholder ?? 'Search...',\n            size: 'sm',\n            borderRadius: 'md',\n            fullWidth: true\n          }\"\n          class=\"w-full min-[375px]:flex-1 min-[480px]:max-w-64\"\n        ></mn-lib-input-field>\n      }\n      <!-- `toolbarTemplate` is the deprecated name for this slot; honouring it here\n           keeps existing callers rendering exactly where they used to. -->\n      @if (dataSource.toolbarRightTemplate ?? dataSource.toolbarTemplate; as rightTemplate) {\n        <div class=\"flex flex-col w-full min-[375px]:w-auto min-[375px]:flex-row\">\n          <ng-container [ngTemplateOutlet]=\"rightTemplate\"></ng-container>\n        </div>\n      }\n    </div>\n  </div>\n}\n\n<!-- Announces loading. The skeletons are aria-hidden, so without this a screen reader hears\n     nothing while rows load. The region stays in the DOM and only its text changes, which is\n     what makes assistive tech read it; one inserted with its text already set is often missed. -->\n<span class=\"sr-only\" role=\"status\">{{ isLoadingState ? loadingLabel : '' }}</span>\n\n<!-- List wrapper -->\n<div\n  #collectionBody\n  [attr.aria-busy]=\"isLoadingState || null\"\n  [style.min-height.px]=\"bodyMinHeight\"\n  class=\"w-full\"\n  [class.border]=\"dataSource.appearance?.bordered\"\n  [class.border-base-300]=\"dataSource.appearance?.bordered\"\n  [class.rounded]=\"dataSource.appearance?.bordered\"\n  role=\"list\"\n  [attr.aria-label]=\"listRegionLabel\"\n>\n  <!-- Loading state -->\n  @if (isLoadingState) {\n    @for (_ of skeletonRows; track $index) {\n      <div [class.py-2]=\"dataSource.appearance?.compact\" class=\"px-4 py-3\" role=\"listitem\">\n        @if (isTemplateRef(dataSource.skeleton)) {\n          <ng-container [ngTemplateOutlet]=\"$any(dataSource.skeleton)\"></ng-container>\n        } @else {\n          <div class=\"flex flex-col gap-1\">\n            @for (line of skeletonLines; track $index) {\n              <mn-skeleton [data]=\"line\"></mn-skeleton>\n            }\n          </div>\n        }\n      </div>\n      @if (!$last && (dataSource.appearance?.dividers !== false)) {\n        <div class=\"border-b border-base-300\"></div>\n      }\n    }\n  } @else if (isErrorState) {\n    <!-- Error state -->\n    <div class=\"text-center text-xs py-8\" role=\"listitem\">\n      @if (dataSource.errorTemplate) {\n        <ng-container [ngTemplateOutlet]=\"dataSource.errorTemplate\"></ng-container>\n      } @else {\n        <div class=\"flex flex-col items-center gap-2 text-error\">\n          <p class=\"text-sm\">{{ dataSource.errorMessage }}</p>\n        </div>\n      }\n    </div>\n  } @else {\n    <!-- Empty state -->\n    @if (filteredItems.length === 0) {\n      <div class=\"text-center text-xs py-8\" role=\"listitem\">\n        @if (dataSource.emptyTemplate) {\n          <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n        } @else {\n          <div class=\"flex flex-col items-center gap-2 text-base-content/50\">\n            @if (dataSource.emptyIcon !== null) {\n              <svg [lucideIcon]=\"dataSource.emptyIcon ?? defaultEmptyIcon\" [size]=\"32\" [strokeWidth]=\"1.5\"></svg>\n            }\n            <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n          </div>\n        }\n      </div>\n    }\n\n    <!-- Select all (multi-select) -->\n    @if (isMultiSelect && filteredItems.length > 0) {\n      <div class=\"flex items-center gap-2 px-4 py-2 bg-base-200 text-sm\">\n        <mn-lib-checkbox\n          (checkedChange)=\"toggleAll()\"\n          [checked]=\"allSelected\"\n          [props]=\"{ id: 'mn-list-select-all', label: selectAllLabel, size: 'sm' }\"\n        ></mn-lib-checkbox>\n      </div>\n      @if (dataSource.appearance?.dividers !== false) {\n        <div class=\"border-b border-base-300\"></div>\n      }\n    }\n\n    <!-- Data items -->\n    @for (item of paginatedItems; track trackByID($index, item); let odd = $odd; let last = $last) {\n      <div\n        class=\"flex items-center gap-2 bg-base-100 transition-colors duration-150\"\n        [ngClass]=\"{'bg-primary/10': isSelected(item)}\"\n        [class.bg-base-200]=\"!isSelected(item) && odd && dataSource.appearance?.dividers !== false\"\n        [class.hover:bg-base-200]=\"dataSource.appearance?.hover !== false\"\n        [class.cursor-pointer]=\"!!dataSource.onItemClick\"\n        [class.px-4]=\"true\"\n        [class.py-3]=\"!dataSource.appearance?.compact\"\n        [class.py-2]=\"dataSource.appearance?.compact\"\n        role=\"listitem\"\n        (keydown)=\"onItemKeydown($event, item)\"\n        (click)=\"onItemClick(item)\"\n        [attr.tabindex]=\"dataSource.onItemClick ? 0 : null\"\n      >\n        <!-- Selection checkbox -->\n        @if (hasSelection) {\n          <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n          <div (click)=\"$event.stopPropagation()\" class=\"shrink-0\">\n            <mn-lib-checkbox\n              (checkedChange)=\"toggle(item)\"\n              [checked]=\"isSelected(item)\"\n              [props]=\"{ id: 'mn-list-item-' + $index, size: 'sm' }\"\n            ></mn-lib-checkbox>\n          </div>\n        }\n\n        <!-- Item content via template -->\n        <div class=\"flex-1 min-w-0\">\n          <ng-container\n            [ngTemplateOutlet]=\"dataSource.itemTemplate\"\n            [ngTemplateOutletContext]=\"{ $implicit: item, data: item }\"\n          ></ng-container>\n        </div>\n      </div>\n      @if (!last && (dataSource.appearance?.dividers !== false)) {\n        <div class=\"border-b border-base-300\"></div>\n      }\n    }\n  }\n</div>\n\n<!-- Load more + pagination -->\n<mn-collection-pagination\n  (loadMore)=\"loadMoreRows()\"\n  (pageChange)=\"goToPage($event)\"\n  (pageSizeChange)=\"onPageSizeChange($event)\"\n  [currentPage]=\"currentPage\"\n  [isPaginated]=\"isPaginated\"\n  [isServerPaginated]=\"isServerPaginated\"\n  [labels]=\"dataSource.labels\"\n  [loadingMoreRows]=\"loadingMoreRows\"\n  [pageSizeSelectOptions]=\"pageSizeSelectOptions\"\n  [pageSize]=\"pageSize\"\n  [showLoadMore]=\"showLoadMore\"\n  [totalItemCount]=\"totalItemCount\"\n  [totalPages]=\"totalPages\"\n  [visiblePages]=\"visiblePages\"\n  idPrefix=\"mn-list\"\n></mn-collection-pagination>\n","import {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Output,\n  TemplateRef,\n  ViewChild,\n} from '@angular/core';\nimport {NgTemplateOutlet} from '@angular/common';\nimport {FormsModule} from '@angular/forms';\nimport {LucideDynamicIcon} from '@lucide/angular';\nimport {GridDataSource} from './mn-grid.types';\nimport {MnSkeleton, MnSkeletonProps} from 'mn-angular-lib/button';\nimport {MnInputField} from 'mn-angular-lib/forms';\nimport {MnCollectionBase, MnCollectionPagination} from '../mn-collection';\n\n/** Default card skeleton: an image block plus two text bars. */\nconst DEFAULT_GRID_SKELETON_LINES: Partial<MnSkeletonProps>[] = [\n  {shape: 'rectangle', width: '100%', height: '8rem'},\n  {shape: 'text', width: '75%'},\n  {shape: 'text', width: '50%', height: '0.75rem'},\n];\n\n/** Breakpoints a `cols` map may address, ordered small → large. */\nconst GRID_BREAKPOINTS = ['base', 'sm', 'md', 'lg', 'xl'] as const;\n\n/** One of the breakpoints in {@link GRID_BREAKPOINTS}. */\ntype GridBreakpoint = (typeof GRID_BREAKPOINTS)[number];\n\n/** Highest column count with a pre-generated class; larger requests clamp to it. */\nconst MAX_GRID_COLS = 12;\n\n/**\n * Column utilities per breakpoint, indexed by `columns - 1`.\n *\n * Spelled out as literals on purpose: the consuming app's Tailwind scanner reads\n * the shipped bundle, so a name assembled at runtime (`sm:grid-cols-${n}`) would\n * never be generated. Breakpoints are Tailwind's defaults (sm 640, md 768,\n * lg 1024, xl 1280), and each unset one simply inherits the next-smaller class.\n */\nconst GRID_COL_CLASSES: Record<GridBreakpoint, readonly string[]> = {\n  base: [\n    'grid-cols-1', 'grid-cols-2', 'grid-cols-3', 'grid-cols-4', 'grid-cols-5', 'grid-cols-6',\n    'grid-cols-7', 'grid-cols-8', 'grid-cols-9', 'grid-cols-10', 'grid-cols-11', 'grid-cols-12',\n  ],\n  sm: [\n    'sm:grid-cols-1', 'sm:grid-cols-2', 'sm:grid-cols-3', 'sm:grid-cols-4', 'sm:grid-cols-5', 'sm:grid-cols-6',\n    'sm:grid-cols-7', 'sm:grid-cols-8', 'sm:grid-cols-9', 'sm:grid-cols-10', 'sm:grid-cols-11', 'sm:grid-cols-12',\n  ],\n  md: [\n    'md:grid-cols-1', 'md:grid-cols-2', 'md:grid-cols-3', 'md:grid-cols-4', 'md:grid-cols-5', 'md:grid-cols-6',\n    'md:grid-cols-7', 'md:grid-cols-8', 'md:grid-cols-9', 'md:grid-cols-10', 'md:grid-cols-11', 'md:grid-cols-12',\n  ],\n  lg: [\n    'lg:grid-cols-1', 'lg:grid-cols-2', 'lg:grid-cols-3', 'lg:grid-cols-4', 'lg:grid-cols-5', 'lg:grid-cols-6',\n    'lg:grid-cols-7', 'lg:grid-cols-8', 'lg:grid-cols-9', 'lg:grid-cols-10', 'lg:grid-cols-11', 'lg:grid-cols-12',\n  ],\n  xl: [\n    'xl:grid-cols-1', 'xl:grid-cols-2', 'xl:grid-cols-3', 'xl:grid-cols-4', 'xl:grid-cols-5', 'xl:grid-cols-6',\n    'xl:grid-cols-7', 'xl:grid-cols-8', 'xl:grid-cols-9', 'xl:grid-cols-10', 'xl:grid-cols-11', 'xl:grid-cols-12',\n  ],\n};\n\n/**\n * Picks the column utility for a breakpoint, clamped to the range that has one.\n * @param breakpoint Breakpoint the class applies from.\n * @param columns Requested column count.\n * @returns The Tailwind class name.\n */\nfunction gridColClass(breakpoint: GridBreakpoint, columns: number): string {\n  const index = Math.min(Math.max(Math.round(columns), 1), MAX_GRID_COLS) - 1;\n  return GRID_COL_CLASSES[breakpoint][index];\n}\n\n/**\n * Responsive card-grid component. Shares the collection chrome (search, every\n * pagination mode, loading skeleton, empty state, toolbar, i18n) with\n * {@link import('../mn-list').MnList} and {@link import('../mn-table').MnTable}\n * via {@link MnCollectionBase}, and lays items out as cards instead of rows.\n * Selection is intentionally not supported.\n */\n@Component({\n  selector: 'mn-grid',\n  standalone: true,\n  imports: [NgTemplateOutlet, FormsModule, MnSkeleton, MnInputField, MnCollectionPagination, LucideDynamicIcon],\n  templateUrl: './mn-grid.component.html',\n  host: {class: 'block'},\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MnGrid<T = unknown> extends MnCollectionBase<T, GridDataSource<T>> {\n  @Output() itemClick = new EventEmitter<T>();\n\n  protected override readonly componentName = 'MnGrid';\n\n  /** Whether the grid uses auto-fit (minCardWidth) instead of explicit columns. */\n  get isAutoLayout(): boolean {\n    return !!this.dataSource.layout?.minCardWidth;\n  }\n\n  // ── Layout ──\n\n  /**\n   * Classes for the card container: `grid` plus one column utility per\n   * breakpoint the consumer configured. Omitted for the auto-fit layout, whose\n   * columns come from {@link autoTemplateColumns} instead.\n   */\n  get gridClasses(): string {\n    if (this.isAutoLayout) {\n      return 'grid';\n    }\n\n    const cols = this.dataSource.layout?.cols;\n    const classes = ['grid', gridColClass('base', cols?.base ?? 1)];\n\n    for (const breakpoint of GRID_BREAKPOINTS) {\n      if (breakpoint === 'base') continue;\n      const columns = cols?.[breakpoint];\n      if (columns != null) {\n        classes.push(gridColClass(breakpoint, columns));\n      }\n    }\n\n    return classes.join(' ');\n  }\n\n  /** Gap between cards. */\n  get gridGap(): string {\n    return this.dataSource.layout?.gap ?? '1rem';\n  }\n\n  /**\n   * Inline `grid-template-columns` for the auto-fit layout, or null when explicit\n   * `cols` are used (the utilities in {@link gridClasses} then own the columns).\n   * `minCardWidth` is a free-form CSS length, so it can only be expressed inline.\n   */\n  get autoTemplateColumns(): string | null {\n    const minCardWidth = this.dataSource.layout?.minCardWidth;\n    return minCardWidth ? `repeat(auto-fit, minmax(${minCardWidth}, 1fr))` : null;\n  }\n\n  /** Skeleton lines for the default/lines placeholder; null when a custom template is used. */\n  get skeletonLines(): Partial<MnSkeletonProps>[] {\n    const skeleton = this.dataSource.skeleton;\n    if (skeleton && !this.isTemplateRef(skeleton)) {\n      return skeleton.lines;\n    }\n    return DEFAULT_GRID_SKELETON_LINES;\n  }\n\n  // ── Item interaction ──\n\n  /**\n   * The toolbar template the base class watches for identity changes. Prefers the\n   * left slot, then the right, then the deprecated `toolbarTemplate`, so a grid\n   * using any single slot still re-renders when that template is swapped.\n   */\n  protected get trackedToolbarTemplate(): TemplateRef<unknown> | undefined {\n    return (\n      this.dataSource?.toolbarLeftTemplate ??\n      this.dataSource?.toolbarRightTemplate ??\n      this.dataSource?.toolbarTemplate\n    );\n  }\n\n  @ViewChild('collectionBody') protected collectionBody?: ElementRef<HTMLElement>;\n\n  // ── Skeleton ──\n\n  onItemClick(item: T): void {\n    this.dataSource.onItemClick?.(item);\n    this.itemClick.emit(item);\n  }\n\n  /**\n   * Keyboard activation of a clickable item: Enter and Space open it, as they would a button.\n   * Handled on keydown so Space does not scroll the page first, and only when the item itself has\n   * focus, so a checkbox or button inside the item keeps its own keys.\n   * @param event - The keydown on the item.\n   * @param item - The item the key was pressed on.\n   */\n  onItemKeydown(event: KeyboardEvent, item: T): void {\n    if (!this.dataSource.onItemClick || event.target !== event.currentTarget) return;\n    if (event.key !== 'Enter' && event.key !== ' ') return;\n    event.preventDefault();\n    this.onItemClick(item);\n  }\n\n  // ── Filtering ──\n\n  protected applyFilter(searchForItems: boolean): void {\n    let items = this.applySearchFilter(this.dataSource.dataRows.value ?? []);\n\n    // Preview cap: show only the first `maxItems` cards (pager stays hidden).\n    const maxItems = this.dataSource.layout?.maxItems;\n    if (maxItems != null) {\n      items = items.slice(0, maxItems);\n    }\n\n    this.filteredItems = items;\n    this.applyPagination();\n\n    if (searchForItems) {\n      this.loadMoreRows();\n    }\n  }\n\n  /** Accessible name for the scrollable grid region. */\n  get gridRegionLabel(): string {\n    return this.resolveLabel(undefined, 'mnCollection.cardGrid', 'Card grid');\n  }\n}\n","<!-- Toolbar: left template, then search + right template. Below 375px each group\n     takes its own full-width row; from 375px up the left group sits at the start\n     and the search group at the end. Structure and classes mirror mn-table so all\n     collections behave identically at every width. -->\n@if (\n  isSearchable ||\n  dataSource.toolbarLeftTemplate ||\n  dataSource.toolbarRightTemplate ||\n  dataSource.toolbarTemplate\n) {\n  <div class=\"flex flex-col min-[375px]:flex-row min-[375px]:items-center justify-between gap-2 mb-3\">\n    <div class=\"flex items-center gap-2 w-full min-[375px]:w-auto\">\n      @if (dataSource.toolbarLeftTemplate) {\n        <div class=\"flex flex-col w-full min-[375px]:w-auto min-[375px]:flex-row\">\n          <ng-container [ngTemplateOutlet]=\"dataSource.toolbarLeftTemplate\"></ng-container>\n        </div>\n      }\n    </div>\n    <div\n      class=\"flex flex-col min-[375px]:flex-row min-[375px]:items-center gap-2 w-full min-[375px]:flex-1 min-[480px]:flex-none min-[480px]:w-auto\">\n      @if (isSearchable) {\n        <!-- Enter must not submit a surrounding form: the search box is the\n             collection's own chrome, not a field of whatever form it sits in. -->\n        <mn-lib-input-field\n          (keydown.enter)=\"$event.preventDefault()\"\n          (ngModelChange)=\"onSearch($event)\"\n          [ngModel]=\"searchValue\"\n          [props]=\"{\n            id: 'mn-grid-search',\n            type: 'search',\n            label: '',\n            ariaLabel: dataSource.searchPlaceholder ?? 'Search...',\n            placeholder: dataSource.searchPlaceholder ?? 'Search...',\n            size: 'sm',\n            borderRadius: 'md',\n            fullWidth: true\n          }\"\n          class=\"w-full min-[375px]:flex-1 min-[480px]:max-w-64\"\n        ></mn-lib-input-field>\n      }\n      <!-- `toolbarTemplate` is the deprecated name for this slot; honouring it here\n           keeps existing callers rendering exactly where they used to. -->\n      @if (dataSource.toolbarRightTemplate ?? dataSource.toolbarTemplate; as rightTemplate) {\n        <div class=\"flex flex-col w-full min-[375px]:w-auto min-[375px]:flex-row\">\n          <ng-container [ngTemplateOutlet]=\"rightTemplate\"></ng-container>\n        </div>\n      }\n    </div>\n  </div>\n}\n\n<!-- Body: skeleton/data swap region. Wrapper holds its height during a server reload. -->\n<!-- Announces loading. The skeletons are aria-hidden, so without this a screen reader hears\n     nothing while rows load. The region stays in the DOM and only its text changes, which is\n     what makes assistive tech read it; one inserted with its text already set is often missed. -->\n<span class=\"sr-only\" role=\"status\">{{ isLoadingState ? loadingLabel : '' }}</span>\n\n<div #collectionBody [style.min-height.px]=\"bodyMinHeight\">\n<!-- Loading state -->\n  @if (isLoadingState) {\n  <div\n    [class]=\"gridClasses\"\n    [style.gap]=\"gridGap\"\n    [style.grid-template-columns]=\"autoTemplateColumns\"\n    aria-busy=\"true\"\n    [attr.aria-label]=\"loadingLabel\"\n    role=\"list\"\n  >\n    @for (_ of skeletonRows; track $index) {\n      <div role=\"listitem\">\n        @if (isTemplateRef(dataSource.skeleton)) {\n          <ng-container [ngTemplateOutlet]=\"$any(dataSource.skeleton)\"></ng-container>\n        } @else {\n          <div class=\"flex flex-col gap-2 p-4 border border-base-300 rounded-lg\">\n            @for (line of skeletonLines; track $index) {\n              <mn-skeleton [data]=\"line\"></mn-skeleton>\n            }\n          </div>\n        }\n      </div>\n    }\n  </div>\n  } @else if (isErrorState) {\n    <!-- Error state -->\n    @if (dataSource.errorTemplate) {\n      <ng-container [ngTemplateOutlet]=\"dataSource.errorTemplate\"></ng-container>\n    } @else {\n      <div\n        class=\"flex items-center justify-center min-h-[6rem] py-8 rounded-xl border border-dashed border-error/30 bg-base-100\">\n        <p class=\"text-sm text-error\">{{ dataSource.errorMessage }}</p>\n      </div>\n    }\n} @else {\n  <!-- Empty state: a caller-provided template/component (rendered unwrapped, full\n       control over its own layout) or, when none is given, the default text. -->\n  @if (filteredItems.length === 0) {\n    @if (dataSource.emptyTemplate) {\n      <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n    } @else {\n      <div\n        class=\"flex flex-col items-center justify-center gap-2 min-h-[6rem] py-8 rounded-xl border border-dashed border-base-content/15 bg-base-100 text-base-content/40\">\n        @if (dataSource.emptyIcon !== null) {\n          <svg [lucideIcon]=\"dataSource.emptyIcon ?? defaultEmptyIcon\" [size]=\"32\" [strokeWidth]=\"1.5\"></svg>\n        }\n        <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n      </div>\n    }\n  } @else {\n    <!-- Card grid -->\n    <div\n    [class]=\"gridClasses\"\n    [style.gap]=\"gridGap\"\n    [style.grid-template-columns]=\"autoTemplateColumns\"\n    [attr.aria-label]=\"gridRegionLabel\"\n      role=\"list\"\n    >\n      @for (item of paginatedItems; track trackByID($index, item)) {\n        <div\n          (click)=\"onItemClick(item)\"\n          (keydown)=\"onItemKeydown($event, item)\"\n          [attr.tabindex]=\"dataSource.onItemClick ? 0 : null\"\n          [class.cursor-pointer]=\"!!dataSource.onItemClick\"\n          class=\"transition-colors duration-150\"\n          role=\"listitem\"\n        >\n          <ng-container\n            [ngTemplateOutletContext]=\"{ $implicit: item, data: item }\"\n            [ngTemplateOutlet]=\"dataSource.cardTemplate\"\n          ></ng-container>\n        </div>\n      }\n    </div>\n  }\n}\n</div>\n\n<!-- Load more + pagination -->\n<mn-collection-pagination\n  (loadMore)=\"loadMoreRows()\"\n  (pageChange)=\"goToPage($event)\"\n  (pageSizeChange)=\"onPageSizeChange($event)\"\n  [currentPage]=\"currentPage\"\n  [isPaginated]=\"isPaginated\"\n  [isServerPaginated]=\"isServerPaginated\"\n  [labels]=\"dataSource.labels\"\n  [loadingMoreRows]=\"loadingMoreRows\"\n  [pageSizeSelectOptions]=\"pageSizeSelectOptions\"\n  [pageSize]=\"pageSize\"\n  [showLoadMore]=\"showLoadMore\"\n  [totalItemCount]=\"totalItemCount\"\n  [totalPages]=\"totalPages\"\n  [visiblePages]=\"visiblePages\"\n  idPrefix=\"mn-grid\"\n></mn-collection-pagination>\n","/**\n * Public API of the `mn-angular-lib/collection` entry point: collections (table, list, grid, pagination).\n *\n * Each entry point is its own module in the published package, so a consumer's bundler\n * splits it into the chunk that uses it instead of loading the whole library at startup.\n * The root `mn-angular-lib` entry re-exports every entry point.\n */\nexport * from './src/mn-collection';\nexport * from './src/mn-table';\nexport * from './src/mn-list';\nexport * from './src/mn-grid';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["ICONS"],"mappings":"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"}