diff --git a/libs/components/src/breadcrumbs/breadcrumb.component.html b/libs/components/src/breadcrumbs/breadcrumb.component.html index b0334f1ac09..bca34bb0e8b 100644 --- a/libs/components/src/breadcrumbs/breadcrumb.component.html +++ b/libs/components/src/breadcrumbs/breadcrumb.component.html @@ -1,6 +1,6 @@ @if (icon(); as icon) { - + } diff --git a/libs/components/src/breadcrumbs/breadcrumb.component.ts b/libs/components/src/breadcrumbs/breadcrumb.component.ts index 6c79b449a28..18024c0ef20 100644 --- a/libs/components/src/breadcrumbs/breadcrumb.component.ts +++ b/libs/components/src/breadcrumbs/breadcrumb.component.ts @@ -1,29 +1,55 @@ -import { Component, EventEmitter, Output, TemplateRef, input, viewChild } from "@angular/core"; +import { + ChangeDetectionStrategy, + Component, + TemplateRef, + input, + output, + viewChild, +} from "@angular/core"; import { QueryParamsHandling } from "@angular/router"; -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection +/** + * Individual breadcrumb item used within the `bit-breadcrumbs` component. + * Represents a single navigation step in the breadcrumb trail. + * + * This component should be used as a child of `bit-breadcrumbs` and supports both + * router navigation and custom click handlers. + */ @Component({ selector: "bit-breadcrumb", templateUrl: "./breadcrumb.component.html", + changeDetection: ChangeDetectionStrategy.OnPush, }) export class BreadcrumbComponent { + /** + * Optional icon to display before the breadcrumb text. + */ readonly icon = input(); + /** + * Router link for the breadcrumb. Can be a string or an array of route segments. + */ readonly route = input(); + /** + * Query parameters to include in the router link. + */ readonly queryParams = input>({}); + /** + * How to handle query parameters when navigating. Options include 'merge' or 'preserve'. + */ readonly queryParamsHandling = input(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() - click = new EventEmitter(); + /** + * Emitted when the breadcrumb is clicked. + */ + readonly click = output(); + /** Used by the BreadcrumbsComponent to access the breadcrumb content */ readonly content = viewChild(TemplateRef); onClick(args: unknown) { - this.click.next(args); + this.click.emit(args); } } diff --git a/libs/components/src/breadcrumbs/breadcrumbs.component.html b/libs/components/src/breadcrumbs/breadcrumbs.component.html index b63b21de76b..ee5ad79c739 100644 --- a/libs/components/src/breadcrumbs/breadcrumbs.component.html +++ b/libs/components/src/breadcrumbs/breadcrumbs.component.html @@ -1,4 +1,4 @@ -@for (breadcrumb of beforeOverflow; track breadcrumb; let last = $last) { +@for (breadcrumb of beforeOverflow(); track breadcrumb; let last = $last) { @if (breadcrumb.route(); as route) { 0) { +@if (hasOverflow()) { + @if (beforeOverflow().length > 0) { } - @for (breadcrumb of overflow; track breadcrumb) { + @for (breadcrumb of overflow(); track breadcrumb) { @if (breadcrumb.route(); as route) { - @for (breadcrumb of afterOverflow; track breadcrumb; let last = $last) { + @for (breadcrumb of afterOverflow(); track breadcrumb; let last = $last) { @if (breadcrumb.route(); as route) { ) { - this.breadcrumbs = value.toArray(); - } + /** Whether the breadcrumbs exceed the show limit and require an overflow menu */ + protected readonly hasOverflow = computed(() => this.breadcrumbs().length > this.show()); - protected get beforeOverflow() { - if (this.hasOverflow) { - return this.breadcrumbs.slice(0, this.show() - 1); + /** Breadcrumbs shown before the overflow menu */ + protected readonly beforeOverflow = computed(() => { + const items = this.breadcrumbs(); + const showCount = this.show(); + + if (items.length > showCount) { + return items.slice(0, showCount - 1); } + return items; + }); - return this.breadcrumbs; - } + /** Breadcrumbs hidden in the overflow menu */ + protected readonly overflow = computed(() => { + return this.breadcrumbs().slice(this.show() - 1, -1); + }); - protected get overflow() { - return this.breadcrumbs.slice(this.show() - 1, -1); - } - - protected get afterOverflow() { - return this.breadcrumbs.slice(-1); - } - - protected get hasOverflow() { - return this.breadcrumbs.length > this.show(); - } + /** The last breadcrumb, shown after the overflow menu */ + protected readonly afterOverflow = computed(() => this.breadcrumbs().slice(-1)); } diff --git a/libs/components/src/breadcrumbs/breadcrumbs.stories.ts b/libs/components/src/breadcrumbs/breadcrumbs.stories.ts index 3064ffe3cb4..d0ce221a780 100644 --- a/libs/components/src/breadcrumbs/breadcrumbs.stories.ts +++ b/libs/components/src/breadcrumbs/breadcrumbs.stories.ts @@ -1,4 +1,4 @@ -import { Component, importProvidersFrom } from "@angular/core"; +import { ChangeDetectionStrategy, Component, importProvidersFrom } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; @@ -18,10 +18,9 @@ interface Breadcrumb { route: string; } -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ template: "", + changeDetection: ChangeDetectionStrategy.OnPush, }) class EmptyComponent {}