mn-angular-lib 1.0.132 → 1.0.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mn-angular-lib",
3
- "version": "1.0.132",
3
+ "version": "1.0.134",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.1.3",
6
6
  "@angular/core": "^21.1.3"
@@ -3089,6 +3089,66 @@ type MnSelectableCollectionDataSource<T> = MnCollectionDataSource<T> & {
3089
3089
  selectedRows?: BehaviorSubject<T[]>;
3090
3090
  /** IDs to pre-select when the component initializes. */
3091
3091
  initialSelectedIds?: string[];
3092
+ /**
3093
+ * Rows behind {@link initialSelectedIds}, for collections whose rows are paged in
3094
+ * from a server. The component can only recognise a selected row once it has been
3095
+ * loaded, so on page 1 of a server-paginated table it knows the *ids* that are
3096
+ * selected but not what they are called — which is exactly what
3097
+ * {@link selectionSummary} needs to render. Supplying the rows here fills that
3098
+ * gap. Unnecessary when every row is client-side: the ids resolve against
3099
+ * `dataRows` on their own.
3100
+ */
3101
+ initialSelectedRows?: T[];
3102
+ /**
3103
+ * Renders an always-visible summary of the current selection above the
3104
+ * collection: a count and one removable tag per selected row.
3105
+ *
3106
+ * It exists because a selection and a paginated list answer different questions.
3107
+ * The list is for *finding* rows and is therefore filtered, searched and paged;
3108
+ * the selection is the answer the user is assembling, and hiding it on page 40
3109
+ * makes people re-pick rows they already had. The summary never pages, filters or
3110
+ * sorts — it always shows the whole selection.
3111
+ */
3112
+ selectionSummary?: boolean;
3113
+ /**
3114
+ * Label for a row inside {@link selectionSummary}. Defaults to the first column
3115
+ * that renders a plain string, falling back to the row's id.
3116
+ */
3117
+ selectionLabel?: (row: T) => string;
3118
+ /**
3119
+ * How many tags {@link selectionSummary} shows before collapsing the rest behind
3120
+ * a "+N more" control. Defaults to 8.
3121
+ *
3122
+ * A summary exists to be taken in at a glance, so it must not grow without bound:
3123
+ * left uncapped, selecting a few hundred rows turns the header into the page and
3124
+ * pushes the table — the thing being worked in — off screen entirely. The count in
3125
+ * the heading always states the true total, so collapsing hides tags, never
3126
+ * information.
3127
+ */
3128
+ selectionSummaryLimit?: number;
3129
+ /** Labels for the {@link selectionSummary} chrome. */
3130
+ selectionSummaryLabels?: {
3131
+ /** Heading, supporting a `{{count}}` placeholder. Defaults to `Selected ({{count}})`. */
3132
+ title?: string;
3133
+ /** Translation key for {@link title}. */
3134
+ titleKey?: string;
3135
+ /** Label for the clear-everything action. Defaults to `Clear all`. */
3136
+ clearAll?: string;
3137
+ /** Translation key for {@link clearAll}. */
3138
+ clearAllKey?: string;
3139
+ /** Accessible label for a tag's remove button, supporting `{{label}}`. */
3140
+ remove?: string;
3141
+ /** Translation key for {@link remove}. */
3142
+ removeKey?: string;
3143
+ /** Expand action, supporting a `{{count}}` placeholder. Defaults to `+{{count}} more`. */
3144
+ showMore?: string;
3145
+ /** Translation key for {@link showMore}. */
3146
+ showMoreKey?: string;
3147
+ /** Collapse action. Defaults to `Show less`. */
3148
+ showLess?: string;
3149
+ /** Translation key for {@link showLess}. */
3150
+ showLessKey?: string;
3151
+ };
3092
3152
  };
3093
3153
 
3094
3154
  /**
@@ -3333,6 +3393,12 @@ declare abstract class MnCollectionBase<T, DS extends MnCollectionDataSource<T>>
3333
3393
  protected abstract applyFilter(searchForItems: boolean): void;
3334
3394
  /** Runs after pageSize is set but before the first {@link applyFilter}. */
3335
3395
  protected beforeInitialFilter(): void;
3396
+ /**
3397
+ * Runs after a fresh batch of rows has been filtered in, for work that needs the
3398
+ * rows to exist. Subclasses override to react to data arriving late; call `super`
3399
+ * to keep the default (currently nothing).
3400
+ */
3401
+ protected onRowsChanged(): void;
3336
3402
  /**
3337
3403
  * Resolves translation keys to display strings via {@link MnLanguageService}.
3338
3404
  * Subclasses override to resolve their own keys; call `super` to keep these.
@@ -3383,15 +3449,100 @@ declare abstract class MnCollectionBase<T, DS extends MnCollectionDataSource<T>>
3383
3449
  declare abstract class MnSelectableCollectionBase<T, DS extends MnSelectableCollectionDataSource<T>> extends MnCollectionBase<T, DS> {
3384
3450
  selectionChange: EventEmitter<T[]>;
3385
3451
  selectedIds: Set<string>;
3452
+ /** Whether the summary is currently showing every tag rather than the first few. */
3453
+ selectionSummaryExpanded: boolean;
3386
3454
  get allSelected(): boolean;
3455
+ /**
3456
+ * The row behind every selected id, kept so the selection survives the rows
3457
+ * themselves going away.
3458
+ *
3459
+ * {@link selectedIds} alone is enough to tick a checkbox, because that only ever
3460
+ * asks about a row already on screen. The summary asks the opposite question —
3461
+ * "what is selected, including what isn't on this page?" — and a server-paginated
3462
+ * collection has long since discarded those rows. Rows are captured as they are
3463
+ * selected and backfilled from {@link MnSelectableCollectionDataSource.initialSelectedRows}
3464
+ * and from each batch that loads.
3465
+ */
3466
+ protected selectedRowsById: Map<string, T>;
3467
+ /**
3468
+ * Whether a seeded initial selection still has to be announced, because none of
3469
+ * its ids matched a loaded row yet. See {@link beforeInitialFilter}.
3470
+ */
3471
+ private pendingInitialEmit;
3472
+ /**
3473
+ * The ids that arrived pre-selected, kept apart from {@link selectedIds} so
3474
+ * {@link prioritizeInitialSelection} has a set that does **not** move as the user
3475
+ * clicks. Null when the collection opened with nothing selected.
3476
+ */
3477
+ private pinnedSelectionIds;
3478
+ /**
3479
+ * Every selected row, in selection order, for the summary. Ids whose row was
3480
+ * never seen are skipped rather than rendered as a bare id.
3481
+ */
3482
+ get selectedSummaryRows(): T[];
3483
+ /** Whether the selection summary should render. */
3484
+ get showSelectionSummary(): boolean;
3485
+ /** How many tags to show before collapsing the remainder. */
3486
+ get selectionSummaryLimit(): number;
3487
+ /**
3488
+ * The tags to render: the first {@link selectionSummaryLimit} rows, or all of them
3489
+ * once expanded. Keeps a large selection from turning the header into the page.
3490
+ */
3491
+ get visibleSelectionRows(): T[];
3492
+ /** How many selected rows are collapsed out of view; 0 when all are shown. */
3493
+ get hiddenSelectionCount(): number;
3494
+ /** Expands or re-collapses the summary's tag list. */
3495
+ toggleSelectionSummary(): void;
3496
+ /**
3497
+ * The label for a row in the summary: the consumer's {@link
3498
+ * MnSelectableCollectionDataSource.selectionLabel}, else the first column that
3499
+ * renders a plain string, else the row's id.
3500
+ * @param row The selected row.
3501
+ * @returns The text to show on the row's tag.
3502
+ */
3503
+ selectionLabelFor(row: T): string;
3504
+ /** Removes one row from the selection, from its tag in the summary. */
3505
+ removeSelection(row: T): void;
3387
3506
  get hasSelection(): boolean;
3388
3507
  get isMultiSelect(): boolean;
3389
3508
  isSelected(item: T): boolean;
3509
+ /** Clears the whole selection, from the summary's clear-all action. */
3510
+ clearSelection(): void;
3390
3511
  toggle(item: T): void;
3391
3512
  toggleAll(): void;
3513
+ /**
3514
+ * Fallback label used when the data source declares no `selectionLabel`.
3515
+ * Subclasses that know how to render a row as text (a table knows its columns)
3516
+ * override this; the base has nothing to go on.
3517
+ * @returns The label, or null when none can be derived.
3518
+ */
3519
+ protected defaultSelectionLabel(_row: T): string | null;
3520
+ /**
3521
+ * Reorders rows so the ones that were already selected when the collection
3522
+ * opened come first, preserving the incoming order within each group.
3523
+ *
3524
+ * Deliberately keyed on the *initial* selection rather than the live one: pinning
3525
+ * what the user is currently ticking would make a row jump to the top the instant
3526
+ * it is clicked, moving the next row under the pointer mid-click. Freezing the set
3527
+ * answers the actual question — "what was already chosen?" — and leaves the list
3528
+ * still while it is being worked with. A row deselected during the session keeps
3529
+ * its place for the same reason.
3530
+ *
3531
+ * Callers apply this only when no explicit sort is active, so a sorted column
3532
+ * always wins.
3533
+ * @param items The rows in their current order.
3534
+ * @returns The rows with the initially-selected ones hoisted to the top.
3535
+ */
3536
+ protected prioritizeInitialSelection(items: T[]): T[];
3392
3537
  /** Seeds selection from `initialSelectedIds` before the first filter pass. */
3393
3538
  protected beforeInitialFilter(): void;
3539
+ /** Announces a deferred initial selection as soon as its rows are loaded. */
3540
+ protected onRowsChanged(): void;
3394
3541
  protected emitSelection(): void;
3542
+ /** Records the row object for every loaded row that is currently selected. */
3543
+ private captureSelectedRows;
3544
+ /** The currently loaded rows whose id is selected. */
3545
+ private resolveSelectedRows;
3395
3546
  static ɵfac: i0.ɵɵFactoryDeclaration<MnSelectableCollectionBase<any, any>, never>;
3396
3547
  static ɵdir: i0.ɵɵDirectiveDeclaration<MnSelectableCollectionBase<any, any>, never, never, {}, { "selectionChange": "selectionChange"; }, never, never, true, never>;
3397
3548
  }
@@ -3697,6 +3848,15 @@ type MnTableFilterLabels = {
3697
3848
  /** False option of a boolean filter. Defaults to "No". */
3698
3849
  no?: string;
3699
3850
  noKey?: string;
3851
+ /**
3852
+ * Summary a multi-select filter collapses to from the second selection onwards.
3853
+ * The `{count}` token is replaced with how many are selected. Defaults to
3854
+ * `{count} selected`. A column header has room for about one value, so listing
3855
+ * them all would overflow the cell the moment a second one is picked.
3856
+ */
3857
+ selected?: string;
3858
+ /** Translation key for {@link selected}. */
3859
+ selectedKey?: string;
3700
3860
  };
3701
3861
  /** @deprecated Use {@link MnCollectionLabels}. */
3702
3862
  type TableLabels = MnCollectionLabels;
@@ -3709,17 +3869,8 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3709
3869
  currentSort: SortState | null;
3710
3870
  /** Per-column filter values keyed by column key. */
3711
3871
  columnFilters: ColumnFilterState;
3712
- /** Filter types compact enough to render directly inside the header cell. */
3713
- private static readonly INLINE_FILTER_TYPES;
3714
- /** Width (px) of the filter popover, mirrored from its `w-64` class for clamping. */
3715
- private static readonly POPOVER_WIDTH;
3716
3872
  /** Viewport width (px) below which the inline filter row collapses into a panel. */
3717
3873
  private static readonly FILTER_COLLAPSE_WIDTH;
3718
- /**
3719
- * Key of the column whose filter popover is open, or `null` when none is.
3720
- * Only the rich filter types ({@link isPopoverFilter}) use a popover.
3721
- */
3722
- protected openFilterKey: string | null;
3723
3874
  /** Bounds rendered by a number-range filter, in input order. */
3724
3875
  protected readonly numberBounds: RangeBound[];
3725
3876
  /**
@@ -3735,15 +3886,8 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3735
3886
  protected collectionBody?: ElementRef<HTMLElement>;
3736
3887
  /** Bounds rendered by a date-range filter, in input order. */
3737
3888
  protected readonly dateBounds: RangeBound[];
3738
- /** Viewport coordinates of the open filter popover. */
3739
- protected popoverPosition: {
3740
- top: number;
3741
- left: number;
3742
- };
3743
3889
  /** Debounces server-side text filters so typing doesn't fire a request per keystroke. */
3744
3890
  private readonly filterDebounce;
3745
- /** The open filter popover, used to tell inside clicks from outside ones. */
3746
- private filterPopover?;
3747
3891
  /**
3748
3892
  * Most rows shown per page on mobile (< md). A **cap**, not an override: a data
3749
3893
  * source asking for fewer rows keeps its own size. Raising a small page size on
@@ -3776,25 +3920,8 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3776
3920
  onBooleanFilter(column: ColumnDefinition<T>, raw: string): void;
3777
3921
  /** The effective filter type of a column, defaulting to text. */
3778
3922
  filterTypeOf(column: ColumnDefinition<T>): ColumnFilterType;
3779
- /** Whether a column's filter renders inline in the header cell (vs. in a popover). */
3780
- isInlineFilter(column: ColumnDefinition<T>): boolean;
3781
- /** Whether a column's filter is rich enough to need the popover panel. */
3782
- isPopoverFilter(column: ColumnDefinition<T>): boolean;
3783
3923
  /** Whether a specific column's filter currently narrows the rows. */
3784
3924
  isColumnFilterActive(column: ColumnDefinition<T>): boolean;
3785
- /** The column whose filter popover is open, or `null`. */
3786
- openFilterColumn(): ColumnDefinition<T> | null;
3787
- /**
3788
- * Opens/closes a column's filter popover, closing any other that was open, and
3789
- * anchors it under the trigger. The popover is positioned `fixed` from the
3790
- * trigger's viewport rect because it renders outside the table's
3791
- * `overflow-x-auto` wrapper, which would otherwise clip it.
3792
- */
3793
- toggleFilterPopover(column: ColumnDefinition<T>, event: Event): void;
3794
- /** Resets a single column's filter (from its popover) and re-applies filtering. */
3795
- clearColumnFilter(column: ColumnDefinition<T>): void;
3796
- /** Closes the filter popover, if one is open. */
3797
- closeFilterPopover(): void;
3798
3925
  /** Filter options formatted for mn-multi-select for a given column. */
3799
3926
  getFilterMultiSelectOptions(column: ColumnDefinition<T>): MnMultiSelectOption<string>[];
3800
3927
  /** Any / Yes / No options for a boolean column filter. */
@@ -3813,18 +3940,15 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3813
3940
  rangeBoundLabel(bound: RangeBound): string;
3814
3941
  /** Resets every column filter and re-applies (or re-requests) filtering. */
3815
3942
  clearAllFilters(): void;
3816
- /**
3817
- * Closes the filter popover when the click landed outside it. Membership is
3818
- * tested against the popover element rather than stopping propagation inside
3819
- * it, so the popover's own controls stay ordinary, focusable elements.
3820
- */
3821
- protected onDocumentClick(event: MouseEvent): void;
3822
3943
  /** Whether any column has filtering enabled. */
3823
3944
  get hasColumnFilters(): boolean;
3824
- /** Closes the filter popover on Escape. */
3825
- protected onEscape(): void;
3826
3945
  /** Label for the small-screen filters toggle button. */
3827
3946
  get filtersButtonLabel(): string;
3947
+ /**
3948
+ * Summary a multi-select filter collapses to once more than one option is picked.
3949
+ * Resolved with the `{count}` token intact for mn-multi-select to fill in.
3950
+ */
3951
+ get filterSelectedLabel(): string;
3828
3952
  /** Label for the "clear all filters" action in the small-screen panel. */
3829
3953
  get clearFiltersButtonLabel(): string;
3830
3954
  /** Opens/closes the stacked filter panel shown on small screens. */
@@ -3869,6 +3993,20 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3869
3993
  get tableClasses(): string;
3870
3994
  /** Page size to use at/above the `md` breakpoint (consumer's pageSize, or the user's selection). */
3871
3995
  private desktopPageSize;
3996
+ /** Heading for the selection summary, with the count filled in. */
3997
+ get selectionSummaryTitle(): string;
3998
+ /** Label for the summary's clear-everything action. */
3999
+ get selectionClearAllLabel(): string;
4000
+ /** Label for the summary's expand/collapse control. */
4001
+ get selectionSummaryToggleLabel(): string;
4002
+ /**
4003
+ * Accessible label for a tag's remove button.
4004
+ * @param row The row the tag stands for.
4005
+ * @returns The label, naming the row so screen readers announce which one goes.
4006
+ */
4007
+ selectionRemoveLabel(row: T): string;
4008
+ /** Tracks the desktop page size when the user picks one (selector only shows at >= md). */
4009
+ onPageSizeChange(newSize: number): void;
3872
4010
  /** The effective column-width strategy, defaulting to `stable`. */
3873
4011
  get layoutMode(): 'auto' | 'fixed' | 'stable';
3874
4012
  /**
@@ -3894,6 +4032,29 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3894
4032
  * @returns The full cell text, or `null` when there is nothing to expose.
3895
4033
  */
3896
4034
  cellTitle(column: ColumnDefinition<T>, row: T): string | null;
4035
+ /**
4036
+ * Falls back to the first column that renders a plain string, which is almost
4037
+ * always the name-like column a person would use to identify the row. Template
4038
+ * columns are skipped: they render markup this cannot flatten to a tag label.
4039
+ * @param row The selected row.
4040
+ * @returns The label, or null when every column renders a template.
4041
+ */
4042
+ protected defaultSelectionLabel(row: T): string | null;
4043
+ /**
4044
+ * Resolves table-specific translation keys (column headers/filters) plus the
4045
+ * shared keys handled by the base.
4046
+ */
4047
+ protected resolveTranslationKeys(): void;
4048
+ protected applyFilter(searchForItems: boolean): void;
4049
+ /**
4050
+ * Re-evaluate on a window resize too. The ResizeObserver covers every change to
4051
+ * the table's own box, but {@link isMobileViewport} reads the window, which can
4052
+ * change without the table's width following it (a fixed-width table, a modal
4053
+ * pinned to a max width).
4054
+ */
4055
+ protected onWindowResize(): void;
4056
+ /** Re-evaluate responsive page size and filter layout when the table is resized. */
4057
+ private onHostResize;
3897
4058
  /**
3898
4059
  * Captures the current, automatically-derived width of every visible column and
3899
4060
  * pins it, which flips the table to `table-fixed` on the next render.
@@ -3919,23 +4080,6 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3919
4080
  * go, changing which columns need a share at all.
3920
4081
  */
3921
4082
  private unpinColumnWidths;
3922
- /**
3923
- * Re-evaluate on a window resize too. The ResizeObserver covers every change to
3924
- * the table's own box, but {@link isMobileViewport} reads the window, which can
3925
- * change without the table's width following it (a fixed-width table, a modal
3926
- * pinned to a max width).
3927
- */
3928
- protected onWindowResize(): void;
3929
- /** Re-evaluate responsive page size and filter layout when the table is resized. */
3930
- private onHostResize;
3931
- /**
3932
- * Resolves table-specific translation keys (column headers/filters) plus the
3933
- * shared keys handled by the base.
3934
- */
3935
- protected resolveTranslationKeys(): void;
3936
- /** Tracks the desktop page size when the user picks one (selector only shows at >= md). */
3937
- onPageSizeChange(newSize: number): void;
3938
- protected applyFilter(searchForItems: boolean): void;
3939
4083
  getCellValue(column: ColumnDefinition<T>, row: T): string;
3940
4084
  /** Returns the small-screen cell value for a column with cellSm defined. */
3941
4085
  getCellSmValue(column: ColumnDefinition<T>, row: T): string;
@@ -3979,6 +4123,12 @@ declare class MnTable<T = object> extends MnSelectableCollectionBase<T, TableDat
3979
4123
  private emitServerFilters;
3980
4124
  /** Resets every filterable column to its type's empty value. */
3981
4125
  private seedFilterValues;
4126
+ /**
4127
+ * Resolves the selection-summary labels from their translation keys. Resolved
4128
+ * without params so the `{{count}}` / `{{label}}` placeholders survive for the
4129
+ * getters to fill in per render.
4130
+ */
4131
+ private resolveSelectionSummaryKeys;
3982
4132
  /** Resolves the range / boolean filter control labels from their translation keys. */
3983
4133
  private resolveFilterLabelKeys;
3984
4134
  private applySorting;