1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-20 11:24:07 +00:00

[CL-637] icon api buttons links (#18388)

* update button api to accept icons

* use template outlet in button

* add link component

* create link component to handle anchors and buttons

* remove unnecessary let variables

* fix link focus state styling

* update link underline style

* fix broken skip link focus

* add focus method to link component

* fix typo

* fix off center loading state

* move flex styles to template to fix some minor style overrides

* remove unnecessary variables

* fix interaction states and add styles for test class to work properly

* refactor classes and make variable sreadonly

* fix classes not being applied correctly

* fix bad merge conflict resolution

* simplified button template
This commit is contained in:
Bryan Cunningham
2026-02-04 14:20:44 -05:00
committed by jaasen-livefront
parent 8f724de83c
commit d11fb4302c
17 changed files with 183 additions and 93 deletions

View File

@@ -1,6 +1,14 @@
<span class="tw-relative">
<span [ngClass]="{ 'tw-invisible': showLoadingStyle() }">
<ng-content></ng-content>
<span class="tw-relative tw-flex tw-items-center tw-justify-center">
<span [class.tw-invisible]="showLoadingStyle()" class="tw-flex tw-items-center tw-gap-2">
@if (startIcon()) {
<i class="{{ startIconClasses() }}"></i>
}
<div>
<ng-content></ng-content>
</div>
@if (endIcon()) {
<i class="{{ endIconClasses() }}"></i>
}
</span>
@if (showLoadingStyle()) {
<span class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center">

View File

@@ -1,4 +1,4 @@
import { NgClass } from "@angular/common";
import { NgClass, NgTemplateOutlet } from "@angular/common";
import {
input,
HostBinding,
@@ -14,6 +14,7 @@ import { debounce, interval } from "rxjs";
import { AriaDisableDirective } from "../a11y";
import { ButtonLikeAbstraction, ButtonType, ButtonSize } from "../shared/button-like.abstraction";
import { BitwardenIcon } from "../shared/icon";
import { SpinnerComponent } from "../spinner";
import { ariaDisableElement } from "../utils";
@@ -71,7 +72,7 @@ const buttonStyles: Record<ButtonType, string[]> = {
selector: "button[bitButton], a[bitButton]",
templateUrl: "button.component.html",
providers: [{ provide: ButtonLikeAbstraction, useExisting: ButtonComponent }],
imports: [NgClass, SpinnerComponent],
imports: [NgClass, NgTemplateOutlet, SpinnerComponent],
hostDirectives: [AriaDisableDirective],
})
export class ButtonComponent implements ButtonLikeAbstraction {
@@ -125,12 +126,23 @@ export class ButtonComponent implements ButtonLikeAbstraction {
readonly buttonType = input<ButtonType>("secondary");
readonly startIcon = input<BitwardenIcon | undefined>(undefined);
readonly endIcon = input<BitwardenIcon | undefined>(undefined);
readonly size = input<ButtonSize>("default");
readonly block = input(false, { transform: booleanAttribute });
readonly loading = model<boolean>(false);
readonly startIconClasses = computed(() => {
return ["bwi", this.startIcon()];
});
readonly endIconClasses = computed(() => {
return ["bwi", this.endIcon()];
});
/**
* Determine whether it is appropriate to display a loading spinner. We only want to show
* a spinner if it's been more than 75 ms since the `loading` state began. This prevents

View File

@@ -152,15 +152,13 @@ export const WithIcon: Story = {
template: /*html*/ `
<span class="tw-flex tw-gap-8">
<div>
<button type="button" bitButton [buttonType]="buttonType" [block]="block">
<i class="bwi bwi-plus tw-me-2"></i>
<button type="button" startIcon="bwi-plus" bitButton [buttonType]="buttonType" [block]="block">
Button label
</button>
</div>
<div>
<button type="button" bitButton [buttonType]="buttonType" [block]="block">
<button type="button" endIcon="bwi-plus" bitButton [buttonType]="buttonType" [block]="block">
Button label
<i class="bwi bwi-plus tw-ms-2"></i>
</button>
</div>
</span>