mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 03:33:30 +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:
@@ -6,7 +6,7 @@ import { firstValueFrom, switchMap } from "rxjs";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { AnchorLinkDirective, CalloutModule, BannerModule } from "@bitwarden/components";
|
||||
import { LinkComponent, CalloutModule, BannerModule } from "@bitwarden/components";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
import { AtRiskPasswordCalloutData, AtRiskPasswordCalloutService } from "@bitwarden/vault";
|
||||
|
||||
@@ -15,7 +15,7 @@ import { AtRiskPasswordCalloutData, AtRiskPasswordCalloutService } from "@bitwar
|
||||
@Component({
|
||||
selector: "vault-at-risk-password-callout",
|
||||
imports: [
|
||||
AnchorLinkDirective,
|
||||
LinkComponent,
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
CalloutModule,
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -113,7 +113,7 @@ export const WithTextButton: Story = {
|
||||
template: `
|
||||
<bit-callout ${formatArgsForCodeSnippet<CalloutComponent>(args)}>
|
||||
<p class="tw-mb-2">The content of the callout</p>
|
||||
<a bitLink> Visit the help center<i aria-hidden="true" class="bwi bwi-fw bwi-sm bwi-angle-right"></i> </a>
|
||||
<a bitLink endIcon="bwi-angle-right">Visit the help center</a>
|
||||
</bit-callout>
|
||||
`,
|
||||
}),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
|
||||
|
||||
import { AnchorLinkDirective } from "../../link";
|
||||
import { LinkComponent } from "../../link";
|
||||
import { TypographyModule } from "../../typography";
|
||||
|
||||
import { BaseCardComponent } from "./base-card.component";
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
component: BaseCardComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [AnchorLinkDirective, TypographyModule],
|
||||
imports: [LinkComponent, TypographyModule],
|
||||
}),
|
||||
],
|
||||
parameters: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { booleanAttribute, Component, ElementRef, inject, input, viewChild } fro
|
||||
import { RouterModule } from "@angular/router";
|
||||
|
||||
import { DrawerService } from "../dialog/drawer.service";
|
||||
import { LinkModule } from "../link";
|
||||
import { LinkComponent, LinkModule } from "../link";
|
||||
import { SideNavService } from "../navigation/side-nav.service";
|
||||
import { SharedModule } from "../shared";
|
||||
|
||||
@@ -52,11 +52,11 @@ export class LayoutComponent {
|
||||
*
|
||||
* @see https://github.com/angular/components/issues/10247#issuecomment-384060265
|
||||
**/
|
||||
private readonly skipLink = viewChild.required<ElementRef<HTMLElement>>("skipLink");
|
||||
private readonly skipLink = viewChild.required<LinkComponent>("skipLink");
|
||||
handleKeydown(ev: KeyboardEvent) {
|
||||
if (isNothingFocused()) {
|
||||
ev.preventDefault();
|
||||
this.skipLink().nativeElement.focus();
|
||||
this.skipLink().el.nativeElement.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./link.directive";
|
||||
export * from "./link.component";
|
||||
export * from "./link.module";
|
||||
|
||||
11
libs/components/src/link/link.component.html
Normal file
11
libs/components/src/link/link.component.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="tw-flex tw-gap-2 tw-items-center">
|
||||
@if (startIcon()) {
|
||||
<i [class]="['bwi', startIcon()]" aria-hidden="true"></i>
|
||||
}
|
||||
<span>
|
||||
<ng-content></ng-content>
|
||||
</span>
|
||||
@if (endIcon()) {
|
||||
<i [class]="['bwi', endIcon()]" aria-hidden="true"></i>
|
||||
}
|
||||
</div>
|
||||
@@ -1,6 +1,14 @@
|
||||
import { input, HostBinding, Directive, inject, ElementRef, booleanAttribute } from "@angular/core";
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
input,
|
||||
booleanAttribute,
|
||||
inject,
|
||||
ElementRef,
|
||||
} from "@angular/core";
|
||||
|
||||
import { AriaDisableDirective } from "../a11y";
|
||||
import { BitwardenIcon } from "../shared/icon";
|
||||
import { ariaDisableElement } from "../utils";
|
||||
|
||||
export const LinkTypes = [
|
||||
@@ -46,16 +54,16 @@ const commonStyles = [
|
||||
"tw-transition",
|
||||
"tw-no-underline",
|
||||
"tw-cursor-pointer",
|
||||
"hover:tw-underline",
|
||||
"hover:tw-decoration-1",
|
||||
"[&:hover_span]:tw-underline",
|
||||
"[&.tw-test-hover_span]:tw-underline",
|
||||
"[&:hover_span]:tw-decoration-[.125em]",
|
||||
"[&.tw-test-hover_span]:tw-decoration-[.125em]",
|
||||
"disabled:tw-no-underline",
|
||||
"disabled:tw-cursor-not-allowed",
|
||||
"disabled:!tw-text-fg-disabled",
|
||||
"disabled:hover:!tw-text-fg-disabled",
|
||||
"disabled:hover:tw-no-underline",
|
||||
"focus-visible:tw-outline-none",
|
||||
"focus-visible:tw-underline",
|
||||
"focus-visible:tw-decoration-1",
|
||||
"focus-visible:before:tw-ring-border-focus",
|
||||
|
||||
// Workaround for html button tag not being able to be set to `display: inline`
|
||||
@@ -72,8 +80,12 @@ const commonStyles = [
|
||||
"before:tw-block",
|
||||
"before:tw-absolute",
|
||||
"before:-tw-inset-x-[0.1em]",
|
||||
"before:-tw-inset-y-[0]",
|
||||
"before:tw-rounded-md",
|
||||
"before:tw-transition",
|
||||
"before:tw-h-full",
|
||||
"before:tw-w-[calc(100%_+_.25rem)]",
|
||||
"before:tw-pointer-events-none",
|
||||
"focus-visible:before:tw-ring-2",
|
||||
"focus-visible:tw-z-10",
|
||||
"aria-disabled:tw-no-underline",
|
||||
@@ -83,47 +95,57 @@ const commonStyles = [
|
||||
"aria-disabled:hover:tw-no-underline",
|
||||
];
|
||||
|
||||
@Directive()
|
||||
abstract class LinkDirective {
|
||||
readonly linkType = input<LinkType>("default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Links and Buttons can use either the `<a>` or `<button>` tags. Choose which based on the action the button takes:
|
||||
|
||||
* - if navigating to a new page, use a `<a>`
|
||||
* - if taking an action on the current page, use a `<button>`
|
||||
|
||||
* Text buttons or links are most commonly used in paragraphs of text or in forms to customize actions or show/hide additional form options.
|
||||
*/
|
||||
@Directive({
|
||||
selector: "a[bitLink]",
|
||||
@Component({
|
||||
selector: "a[bitLink], button[bitLink]",
|
||||
templateUrl: "./link.component.html",
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
"[class]": "classList()",
|
||||
// This is for us to be able to correctly aria-disable the button and capture clicks.
|
||||
// It's normally added via the AriaDisableDirective as a host directive.
|
||||
// But, we're not able to conditionally apply the host directive based on if this is a button or not
|
||||
"[attr.bit-aria-disable]": "isButton ? true : null",
|
||||
},
|
||||
})
|
||||
export class AnchorLinkDirective extends LinkDirective {
|
||||
@HostBinding("class") get classList() {
|
||||
return ["before:-tw-inset-y-[0.125rem]"]
|
||||
.concat(commonStyles)
|
||||
.concat(linkStyles[this.linkType()] ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: "button[bitLink]",
|
||||
hostDirectives: [AriaDisableDirective],
|
||||
})
|
||||
export class ButtonLinkDirective extends LinkDirective {
|
||||
private el = inject(ElementRef<HTMLButtonElement>);
|
||||
|
||||
export class LinkComponent {
|
||||
readonly el = inject(ElementRef<HTMLElement>);
|
||||
/**
|
||||
* The variant of link you want to render
|
||||
* @default "primary"
|
||||
*/
|
||||
readonly linkType = input<LinkType>("primary");
|
||||
/**
|
||||
* The leading icon to display within the link
|
||||
* @default undefined
|
||||
*/
|
||||
readonly startIcon = input<BitwardenIcon | undefined>(undefined);
|
||||
/**
|
||||
* The trailing icon to display within the link
|
||||
* @default undefined
|
||||
*/
|
||||
readonly endIcon = input<BitwardenIcon | undefined>(undefined);
|
||||
/**
|
||||
* Whether the button is disabled
|
||||
* @default false
|
||||
* @note Only applicable if the link is rendered as a button
|
||||
*/
|
||||
readonly disabled = input(false, { transform: booleanAttribute });
|
||||
|
||||
@HostBinding("class") get classList() {
|
||||
return ["before:-tw-inset-y-[0.25rem]"]
|
||||
protected readonly isButton = this.el.nativeElement.tagName === "BUTTON";
|
||||
|
||||
readonly classList = computed(() => {
|
||||
return [!this.isButton && "tw-inline-flex"]
|
||||
.concat(commonStyles)
|
||||
.concat(linkStyles[this.linkType()] ?? []);
|
||||
});
|
||||
|
||||
focus() {
|
||||
this.el.nativeElement.focus();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
ariaDisableElement(this.el.nativeElement, this.disabled);
|
||||
if (this.isButton) {
|
||||
ariaDisableElement(this.el.nativeElement, this.disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { AnchorLinkDirective, ButtonLinkDirective } from "./link.directive";
|
||||
import { LinkComponent } from "./link.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [AnchorLinkDirective, ButtonLinkDirective],
|
||||
exports: [AnchorLinkDirective, ButtonLinkDirective],
|
||||
imports: [LinkComponent],
|
||||
exports: [LinkComponent],
|
||||
})
|
||||
export class LinkModule {}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
|
||||
|
||||
import { formatArgsForCodeSnippet } from "../../../../.storybook/format-args-for-code-snippet";
|
||||
|
||||
import { AnchorLinkDirective, ButtonLinkDirective, LinkTypes } from "./link.directive";
|
||||
import { LinkComponent, LinkTypes } from "./link.component";
|
||||
import { LinkModule } from "./link.module";
|
||||
|
||||
export default {
|
||||
@@ -26,7 +26,7 @@ export default {
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
type Story = StoryObj<ButtonLinkDirective>;
|
||||
type Story = StoryObj<LinkComponent>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: (args) => ({
|
||||
@@ -40,9 +40,9 @@ export const Default: Story = {
|
||||
: "tw-bg-transparent",
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="tw-p-2" [class]="backgroundClass">
|
||||
<a bitLink href="" ${formatArgsForCodeSnippet<ButtonLinkDirective>(args)}>Your text here</a>
|
||||
</div>
|
||||
<div class="tw-p-2" [class]="backgroundClass">
|
||||
<a bitLink href="#" ${formatArgsForCodeSnippet<LinkComponent>(args)}>Your text here</a>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
args: {
|
||||
@@ -181,14 +181,12 @@ export const Buttons: Story = {
|
||||
<button type="button" bitLink [linkType]="linkType">Button</button>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<button type="button" bitLink [linkType]="linkType">
|
||||
<i class="bwi bwi-fw bwi-plus-circle" aria-hidden="true"></i>
|
||||
<button type="button" bitLink [linkType]="linkType" startIcon="bwi-plus-circle">
|
||||
Add Icon Button
|
||||
</button>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<button type="button" bitLink [linkType]="linkType">
|
||||
<i class="bwi bwi-fw bwi-sm bwi-angle-right" aria-hidden="true"></i>
|
||||
<button type="button" bitLink [linkType]="linkType" endIcon="bwi-angle-right">
|
||||
Chevron Icon Button
|
||||
</button>
|
||||
</div>
|
||||
@@ -203,7 +201,7 @@ export const Buttons: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Anchors: StoryObj<AnchorLinkDirective> = {
|
||||
export const Anchors: StoryObj<LinkComponent> = {
|
||||
render: (args) => ({
|
||||
props: {
|
||||
linkType: args.linkType,
|
||||
@@ -220,14 +218,12 @@ export const Anchors: StoryObj<AnchorLinkDirective> = {
|
||||
<a bitLink [linkType]="linkType" href="#">Anchor</a>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<a bitLink [linkType]="linkType" href="#">
|
||||
<i class="bwi bwi-fw bwi-plus-circle" aria-hidden="true"></i>
|
||||
<a bitLink [linkType]="linkType" href="#" startIcon="bwi-plus-circle">
|
||||
Add Icon Anchor
|
||||
</a>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<a bitLink [linkType]="linkType" href="#">
|
||||
<i class="bwi bwi-fw bwi-sm bwi-angle-right" aria-hidden="true"></i>
|
||||
<a bitLink [linkType]="linkType" href="#" endIcon="bwi-angle-right">
|
||||
Chevron Icon Anchor
|
||||
</a>
|
||||
</div>
|
||||
@@ -247,20 +243,57 @@ export const Inline: Story = {
|
||||
props: args,
|
||||
template: /*html*/ `
|
||||
<span class="tw-text-main">
|
||||
On the internet paragraphs often contain <a bitLink href="#">inline links</a>, but few know that <button type="button" bitLink>buttons</button> can be used for similar purposes.
|
||||
On the internet paragraphs often contain <a bitLink href="#">inline links with very long text that might break</a>, but few know that <button type="button" bitLink>buttons</button> can be used for similar purposes.
|
||||
</span>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
|
||||
export const Inactive: Story = {
|
||||
export const WithIcons: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: /*html*/ `
|
||||
<button type="button" bitLink disabled linkType="primary" class="tw-me-2">Primary</button>
|
||||
<button type="button" bitLink disabled linkType="secondary" class="tw-me-2">Secondary</button>
|
||||
<div class="tw-bg-bg-contrast tw-p-2 tw-inline-block">
|
||||
<button type="button" bitLink disabled linkType="contrast">Contrast</button>
|
||||
<div class="tw-p-2" [ngClass]="{ 'tw-bg-transparent': linkType != 'contrast', 'tw-bg-primary-600': linkType === 'contrast' }">
|
||||
<div class="tw-block tw-p-2">
|
||||
<a bitLink [linkType]="linkType" href="#" startIcon="bwi-star">Start icon link</a>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<a bitLink [linkType]="linkType" href="#" endIcon="bwi-external-link">External link</a>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<a bitLink [linkType]="linkType" href="#" startIcon="bwi-angle-left" endIcon="bwi-angle-right">Both icons</a>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<button type="button" bitLink [linkType]="linkType" startIcon="bwi-plus-circle">Add item</button>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<button type="button" bitLink [linkType]="linkType" endIcon="bwi-angle-right">Next</button>
|
||||
</div>
|
||||
<div class="tw-block tw-p-2">
|
||||
<button type="button" bitLink [linkType]="linkType" startIcon="bwi-download" endIcon="bwi-check">Download complete</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
args: {
|
||||
linkType: "primary",
|
||||
},
|
||||
};
|
||||
|
||||
export const Inactive: Story = {
|
||||
render: (args) => ({
|
||||
props: {
|
||||
...args,
|
||||
onClick: () => {
|
||||
alert("Button clicked! (This should not appear when disabled)");
|
||||
},
|
||||
},
|
||||
template: /*html*/ `
|
||||
<button type="button" bitLink (click)="onClick()" disabled linkType="primary" class="tw-me-2">Primary button</button>
|
||||
<a bitLink href="" disabled linkType="primary" class="tw-me-2">Links can not be inactive</a>
|
||||
<button type="button" bitLink disabled linkType="secondary" class="tw-me-2">Secondary button</button>
|
||||
<div class="tw-bg-primary-600 tw-p-2 tw-inline-block">
|
||||
<button type="button" bitLink disabled linkType="contrast">Contrast button</button>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
|
||||
@@ -3,13 +3,13 @@ import { Component, inject } from "@angular/core";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import {
|
||||
ButtonLinkDirective,
|
||||
ButtonModule,
|
||||
CenterPositionStrategy,
|
||||
DialogModule,
|
||||
DialogRef,
|
||||
DialogService,
|
||||
DIALOG_DATA,
|
||||
DialogRef,
|
||||
CenterPositionStrategy,
|
||||
LinkComponent,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
export type AdvancedUriOptionDialogParams = {
|
||||
@@ -22,7 +22,7 @@ export type AdvancedUriOptionDialogParams = {
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
templateUrl: "advanced-uri-option-dialog.component.html",
|
||||
imports: [ButtonLinkDirective, ButtonModule, DialogModule, JslibModule],
|
||||
imports: [LinkComponent, ButtonModule, DialogModule, JslibModule],
|
||||
})
|
||||
export class AdvancedUriOptionDialogComponent {
|
||||
constructor(private dialogRef: DialogRef<boolean>) {}
|
||||
|
||||
@@ -12,9 +12,15 @@
|
||||
</bit-callout>
|
||||
|
||||
<bit-callout *ngIf="showChangePasswordLink()" type="warning" [title]="''">
|
||||
<a bitLink href="#" appStopClick (click)="launchChangePassword()" linkType="secondary">
|
||||
<a
|
||||
bitLink
|
||||
href="#"
|
||||
appStopClick
|
||||
(click)="launchChangePassword()"
|
||||
linkType="secondary"
|
||||
endIcon="bwi-external-link"
|
||||
>
|
||||
{{ "changeAtRiskPassword" | i18n }}
|
||||
<i class="bwi bwi-external-link tw-ml-1" aria-hidden="true"></i>
|
||||
</a>
|
||||
</bit-callout>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
CalloutModule,
|
||||
SearchModule,
|
||||
TypographyModule,
|
||||
AnchorLinkDirective,
|
||||
LinkComponent,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { ChangeLoginPasswordService } from "../abstractions/change-login-password.service";
|
||||
@@ -66,7 +66,7 @@ import { ViewIdentitySectionsComponent } from "./view-identity-sections/view-ide
|
||||
ViewIdentitySectionsComponent,
|
||||
LoginCredentialsViewComponent,
|
||||
AutofillOptionsViewComponent,
|
||||
AnchorLinkDirective,
|
||||
LinkComponent,
|
||||
TypographyModule,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -19,9 +19,9 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import {
|
||||
BadgeModule,
|
||||
ButtonLinkDirective,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
LinkComponent,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
@@ -39,7 +39,7 @@ import { OrgIconDirective } from "../../components/org-icon.directive";
|
||||
TypographyModule,
|
||||
OrgIconDirective,
|
||||
FormFieldModule,
|
||||
ButtonLinkDirective,
|
||||
LinkComponent,
|
||||
BadgeModule,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ import { CipherId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
DIALOG_DATA,
|
||||
DialogRef,
|
||||
AnchorLinkDirective,
|
||||
LinkComponent,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
@@ -32,7 +32,7 @@ export type DecryptionFailureDialogParams = {
|
||||
JslibModule,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
AnchorLinkDirective,
|
||||
LinkComponent,
|
||||
],
|
||||
})
|
||||
export class DecryptionFailureDialogComponent {
|
||||
|
||||
Reference in New Issue
Block a user