mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 17:53:39 +00:00
[CL-905] Migrate CL/Badge to OnPush (#16959)
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
<div class="tw-inline-flex tw-flex-wrap tw-gap-2">
|
||||
@for (item of filteredItems; track item; let last = $last) {
|
||||
@for (item of filteredItems(); track item; let last = $last) {
|
||||
<span bitBadge [variant]="variant()" [truncate]="truncate()">
|
||||
{{ item }}
|
||||
</span>
|
||||
@if (!last || isFiltered) {
|
||||
@if (!last || isFiltered()) {
|
||||
<span class="tw-sr-only">, </span>
|
||||
}
|
||||
}
|
||||
@if (isFiltered) {
|
||||
@if (isFiltered()) {
|
||||
<span bitBadge [variant]="variant()">
|
||||
{{ "plusNMore" | i18n: (items().length - filteredItems.length).toString() }}
|
||||
{{ "plusNMore" | i18n: (items().length - filteredItems().length).toString() }}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,38 +1,60 @@
|
||||
import { Component, OnChanges, input } from "@angular/core";
|
||||
import { ChangeDetectionStrategy, Component, computed, input } from "@angular/core";
|
||||
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { BadgeModule, BadgeVariant } from "../badge";
|
||||
|
||||
function transformMaxItems(value: number | undefined) {
|
||||
return value == undefined ? undefined : Math.max(1, value);
|
||||
return value == null ? undefined : Math.max(1, value);
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
/**
|
||||
* Displays a collection of badges in a horizontal, wrapping layout.
|
||||
*
|
||||
* The component automatically handles overflow by showing a limited number of badges
|
||||
* followed by a "+N more" badge when `maxItems` is specified and exceeded.
|
||||
*
|
||||
* Each badge inherits the `variant` and `truncate` settings, ensuring visual consistency
|
||||
* across the list. Badges are separated by commas for screen readers to improve accessibility.
|
||||
*/
|
||||
@Component({
|
||||
selector: "bit-badge-list",
|
||||
templateUrl: "badge-list.component.html",
|
||||
imports: [BadgeModule, I18nPipe],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BadgeListComponent implements OnChanges {
|
||||
protected filteredItems: string[] = [];
|
||||
protected isFiltered = false;
|
||||
|
||||
export class BadgeListComponent {
|
||||
/**
|
||||
* The visual variant to apply to all badges in the list.
|
||||
*/
|
||||
readonly variant = input<BadgeVariant>("primary");
|
||||
|
||||
/**
|
||||
* Items to display as badges.
|
||||
*/
|
||||
readonly items = input<string[]>([]);
|
||||
|
||||
/**
|
||||
* Whether to truncate long badge text with ellipsis.
|
||||
*/
|
||||
readonly truncate = input(true);
|
||||
|
||||
/**
|
||||
* Maximum number of badges to display before showing a "+N more" badge.
|
||||
*/
|
||||
readonly maxItems = input(undefined, { transform: transformMaxItems });
|
||||
|
||||
ngOnChanges() {
|
||||
protected readonly filteredItems = computed(() => {
|
||||
const maxItems = this.maxItems();
|
||||
const items = this.items();
|
||||
|
||||
if (maxItems == undefined || this.items().length <= maxItems) {
|
||||
this.filteredItems = this.items();
|
||||
} else {
|
||||
this.filteredItems = this.items().slice(0, maxItems - 1);
|
||||
if (maxItems == null || items.length <= maxItems) {
|
||||
return items;
|
||||
}
|
||||
this.isFiltered = this.items().length > this.filteredItems.length;
|
||||
}
|
||||
return items.slice(0, maxItems - 1);
|
||||
});
|
||||
|
||||
protected readonly isFiltered = computed(() => {
|
||||
return this.items().length > this.filteredItems().length;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user