mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-14 01:01:31 +01:00
[CL-553] Migrate CL to Control Flow syntax (#12390)
This commit is contained in:
parent
444e928895
commit
e5ffc162b8
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgIf, NgClass } from "@angular/common";
|
||||
import { NgClass } from "@angular/common";
|
||||
import { Component, Input, OnChanges } from "@angular/core";
|
||||
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
|
||||
|
||||
@ -18,9 +18,11 @@ const SizeClasses: Record<SizeTypes, string[]> = {
|
||||
|
||||
@Component({
|
||||
selector: "bit-avatar",
|
||||
template: `<img *ngIf="src" [src]="src" title="{{ title || text }}" [ngClass]="classList" />`,
|
||||
template: `@if (src) {
|
||||
<img [src]="src" title="{{ title || text }}" [ngClass]="classList" />
|
||||
}`,
|
||||
standalone: true,
|
||||
imports: [NgIf, NgClass],
|
||||
imports: [NgClass],
|
||||
})
|
||||
export class AvatarComponent implements OnChanges {
|
||||
@Input() border = false;
|
||||
|
@ -1,11 +1,15 @@
|
||||
<div class="tw-inline-flex tw-flex-wrap tw-gap-2">
|
||||
<ng-container *ngFor="let item of filteredItems; let last = last">
|
||||
@for (item of filteredItems; track item; let last = $last) {
|
||||
<span bitBadge [variant]="variant" [truncate]="truncate">
|
||||
{{ item }}
|
||||
</span>
|
||||
<span class="tw-sr-only" *ngIf="!last || isFiltered">, </span>
|
||||
</ng-container>
|
||||
<span *ngIf="isFiltered" bitBadge [variant]="variant">
|
||||
{{ "plusNMore" | i18n: (items.length - filteredItems.length).toString() }}
|
||||
</span>
|
||||
@if (!last || isFiltered) {
|
||||
<span class="tw-sr-only">, </span>
|
||||
}
|
||||
}
|
||||
@if (isFiltered) {
|
||||
<span bitBadge [variant]="variant">
|
||||
{{ "plusNMore" | i18n: (items.length - filteredItems.length).toString() }}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import { Component, Input, OnChanges } from "@angular/core";
|
||||
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
@ -11,7 +11,7 @@ import { BadgeModule, BadgeVariant } from "../badge";
|
||||
selector: "bit-badge-list",
|
||||
templateUrl: "badge-list.component.html",
|
||||
standalone: true,
|
||||
imports: [CommonModule, BadgeModule, I18nPipe],
|
||||
imports: [BadgeModule, I18nPipe],
|
||||
})
|
||||
export class BadgeListComponent implements OnChanges {
|
||||
private _maxItems: number;
|
||||
|
@ -4,21 +4,24 @@
|
||||
[attr.role]="useAlertRole ? 'status' : null"
|
||||
[attr.aria-live]="useAlertRole ? 'polite' : null"
|
||||
>
|
||||
<i class="bwi tw-align-middle tw-text-base" [ngClass]="icon" *ngIf="icon" aria-hidden="true"></i>
|
||||
@if (icon) {
|
||||
<i class="bwi tw-align-middle tw-text-base" [ngClass]="icon" aria-hidden="true"></i>
|
||||
}
|
||||
<!-- Overriding focus-visible color for link buttons for a11y against colored background -->
|
||||
<span class="tw-grow tw-text-base [&>button[bitlink]:focus-visible:before]:!tw-ring-text-main">
|
||||
<ng-content></ng-content>
|
||||
</span>
|
||||
<!-- Overriding hover and focus-visible colors for a11y against colored background -->
|
||||
<button
|
||||
*ngIf="showClose"
|
||||
class="hover:tw-border-text-main focus-visible:before:tw-ring-text-main"
|
||||
type="button"
|
||||
bitIconButton="bwi-close"
|
||||
buttonType="main"
|
||||
size="default"
|
||||
(click)="onClose.emit()"
|
||||
[attr.title]="'close' | i18n"
|
||||
[attr.aria-label]="'close' | i18n"
|
||||
></button>
|
||||
@if (showClose) {
|
||||
<button
|
||||
class="hover:tw-border-text-main focus-visible:before:tw-ring-text-main"
|
||||
type="button"
|
||||
bitIconButton="bwi-close"
|
||||
buttonType="main"
|
||||
size="default"
|
||||
(click)="onClose.emit()"
|
||||
[attr.title]="'close' | i18n"
|
||||
[attr.aria-label]="'close' | i18n"
|
||||
></button>
|
||||
}
|
||||
</div>
|
||||
|
@ -1,3 +1,6 @@
|
||||
<ng-template>
|
||||
<i *ngIf="icon" class="bwi {{ icon }} !tw-mr-2" aria-hidden="true"></i><ng-content></ng-content>
|
||||
@if (icon) {
|
||||
<i class="bwi {{ icon }} !tw-mr-2" aria-hidden="true"></i>
|
||||
}
|
||||
<ng-content></ng-content>
|
||||
</ng-template>
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgIf } from "@angular/common";
|
||||
|
||||
import { Component, EventEmitter, Input, Output, TemplateRef, ViewChild } from "@angular/core";
|
||||
import { QueryParamsHandling } from "@angular/router";
|
||||
|
||||
@ -8,7 +8,6 @@ import { QueryParamsHandling } from "@angular/router";
|
||||
selector: "bit-breadcrumb",
|
||||
templateUrl: "./breadcrumb.component.html",
|
||||
standalone: true,
|
||||
imports: [NgIf],
|
||||
})
|
||||
export class BreadcrumbComponent {
|
||||
@Input()
|
||||
|
@ -1,5 +1,5 @@
|
||||
<ng-container *ngFor="let breadcrumb of beforeOverflow; let last = last">
|
||||
<ng-container *ngIf="breadcrumb.route">
|
||||
@for (breadcrumb of beforeOverflow; track breadcrumb; let last = $last) {
|
||||
@if (breadcrumb.route) {
|
||||
<a
|
||||
bitLink
|
||||
linkType="primary"
|
||||
@ -10,8 +10,8 @@
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="breadcrumb.content"></ng-container>
|
||||
</a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!breadcrumb.route">
|
||||
}
|
||||
@if (!breadcrumb.route) {
|
||||
<button
|
||||
type="button"
|
||||
bitLink
|
||||
@ -21,13 +21,16 @@
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="breadcrumb.content"></ng-container>
|
||||
</button>
|
||||
</ng-container>
|
||||
<i *ngIf="!last" class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="hasOverflow">
|
||||
<i *ngIf="beforeOverflow.length > 0" class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
}
|
||||
@if (!last) {
|
||||
<i class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
}
|
||||
}
|
||||
|
||||
@if (hasOverflow) {
|
||||
@if (beforeOverflow.length > 0) {
|
||||
<i class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
}
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-ellipsis-h"
|
||||
@ -35,10 +38,9 @@
|
||||
size="small"
|
||||
aria-haspopup
|
||||
></button>
|
||||
|
||||
<bit-menu #overflowMenu>
|
||||
<ng-container *ngFor="let breadcrumb of overflow">
|
||||
<ng-container *ngIf="breadcrumb.route">
|
||||
@for (breadcrumb of overflow; track breadcrumb) {
|
||||
@if (breadcrumb.route) {
|
||||
<a
|
||||
bitMenuItem
|
||||
linkType="primary"
|
||||
@ -48,18 +50,17 @@
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="breadcrumb.content"></ng-container>
|
||||
</a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!breadcrumb.route">
|
||||
}
|
||||
@if (!breadcrumb.route) {
|
||||
<button type="button" bitMenuItem linkType="primary" (click)="breadcrumb.onClick($event)">
|
||||
<ng-container [ngTemplateOutlet]="breadcrumb.content"></ng-container>
|
||||
</button>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
}
|
||||
</bit-menu>
|
||||
<i class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
|
||||
<ng-container *ngFor="let breadcrumb of afterOverflow; let last = last">
|
||||
<ng-container *ngIf="breadcrumb.route">
|
||||
@for (breadcrumb of afterOverflow; track breadcrumb; let last = $last) {
|
||||
@if (breadcrumb.route) {
|
||||
<a
|
||||
bitLink
|
||||
linkType="primary"
|
||||
@ -70,8 +71,8 @@
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="breadcrumb.content"></ng-container>
|
||||
</a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!breadcrumb.route">
|
||||
}
|
||||
@if (!breadcrumb.route) {
|
||||
<button
|
||||
type="button"
|
||||
bitLink
|
||||
@ -81,7 +82,9 @@
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="breadcrumb.content"></ng-container>
|
||||
</button>
|
||||
</ng-container>
|
||||
<i *ngIf="!last" class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
@if (!last) {
|
||||
<i class="bwi bwi-angle-right tw-mx-1.5 tw-text-main"></i>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,16 +86,15 @@ export const DisabledWithAttribute: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: `
|
||||
<ng-container *ngIf="disabled">
|
||||
@if (disabled) {
|
||||
<button bitButton disabled [loading]="loading" [block]="block" buttonType="primary" class="tw-mr-2">Primary</button>
|
||||
<button bitButton disabled [loading]="loading" [block]="block" buttonType="secondary" class="tw-mr-2">Secondary</button>
|
||||
<button bitButton disabled [loading]="loading" [block]="block" buttonType="danger" class="tw-mr-2">Danger</button>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!disabled">
|
||||
} @else {
|
||||
<button bitButton [loading]="loading" [block]="block" buttonType="primary" class="tw-mr-2">Primary</button>
|
||||
<button bitButton [loading]="loading" [block]="block" buttonType="secondary" class="tw-mr-2">Secondary</button>
|
||||
<button bitButton [loading]="loading" [block]="block" buttonType="danger" class="tw-mr-2">Danger</button>
|
||||
</ng-container>
|
||||
}
|
||||
`,
|
||||
}),
|
||||
args: {
|
||||
|
@ -3,10 +3,14 @@
|
||||
[ngClass]="calloutClass"
|
||||
[attr.aria-labelledby]="titleId"
|
||||
>
|
||||
<header id="{{ titleId }}" class="tw-mb-1 tw-mt-0 tw-text-base tw-font-semibold" *ngIf="title">
|
||||
<i class="bwi" [ngClass]="[icon, headerClass]" *ngIf="icon" aria-hidden="true"></i>
|
||||
{{ title }}
|
||||
</header>
|
||||
@if (title) {
|
||||
<header id="{{ titleId }}" class="tw-mb-1 tw-mt-0 tw-text-base tw-font-semibold">
|
||||
@if (icon) {
|
||||
<i class="bwi" [ngClass]="[icon, headerClass]" aria-hidden="true"></i>
|
||||
}
|
||||
{{ title }}
|
||||
</header>
|
||||
}
|
||||
<div bitTypography="body2">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ChangeDetectionStrategy, Component } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: "bit-card",
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
template: `<ng-content></ng-content>`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
|
@ -30,78 +30,80 @@
|
||||
<i class="bwi !tw-text-[inherit]" [ngClass]="icon"></i>
|
||||
<span class="tw-truncate">{{ label }}</span>
|
||||
</span>
|
||||
<i
|
||||
*ngIf="!selectedOption"
|
||||
class="bwi tw-mt-0.5"
|
||||
[ngClass]="menuTrigger.isOpen ? 'bwi-angle-up' : 'bwi-angle-down'"
|
||||
></i>
|
||||
@if (!selectedOption) {
|
||||
<i
|
||||
class="bwi tw-mt-0.5"
|
||||
[ngClass]="menuTrigger.isOpen ? 'bwi-angle-up' : 'bwi-angle-down'"
|
||||
></i>
|
||||
}
|
||||
</button>
|
||||
|
||||
<!-- Close button -->
|
||||
<button
|
||||
*ngIf="selectedOption"
|
||||
type="button"
|
||||
[attr.aria-label]="'removeItem' | i18n: label"
|
||||
[disabled]="disabled"
|
||||
class="tw-bg-transparent hover:tw-bg-transparent tw-outline-none tw-rounded-full tw-py-0.5 tw-px-1 tw-mr-1 tw-text-[color:inherit] tw-text-[length:inherit] tw-border-solid tw-border tw-border-transparent hover:tw-border-text-contrast hover:disabled:tw-border-transparent tw-flex tw-items-center tw-justify-center focus-visible:tw-ring-2 tw-ring-text-contrast focus-visible:hover:tw-border-transparent"
|
||||
[ngClass]="{
|
||||
'tw-cursor-not-allowed': disabled,
|
||||
}"
|
||||
(click)="clear()"
|
||||
>
|
||||
<i class="bwi bwi-close tw-text-xs"></i>
|
||||
</button>
|
||||
@if (selectedOption) {
|
||||
<button
|
||||
type="button"
|
||||
[attr.aria-label]="'removeItem' | i18n: label"
|
||||
[disabled]="disabled"
|
||||
class="tw-bg-transparent hover:tw-bg-transparent tw-outline-none tw-rounded-full tw-py-0.5 tw-px-1 tw-mr-1 tw-text-[color:inherit] tw-text-[length:inherit] tw-border-solid tw-border tw-border-transparent hover:tw-border-text-contrast hover:disabled:tw-border-transparent tw-flex tw-items-center tw-justify-center focus-visible:tw-ring-2 tw-ring-text-contrast focus-visible:hover:tw-border-transparent"
|
||||
[ngClass]="{
|
||||
'tw-cursor-not-allowed': disabled,
|
||||
}"
|
||||
(click)="clear()"
|
||||
>
|
||||
<i class="bwi bwi-close tw-text-xs"></i>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<bit-menu #menu (closed)="handleMenuClosed()">
|
||||
<div
|
||||
*ngIf="renderedOptions"
|
||||
class="tw-max-h-80 tw-min-w-32 tw-max-w-80 tw-text-sm"
|
||||
[ngStyle]="menuWidth && { width: menuWidth + 'px' }"
|
||||
>
|
||||
<ng-container *ngIf="getParent(renderedOptions) as parent">
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="viewOption(parent, $event)"
|
||||
class="tw-text-[length:inherit]"
|
||||
[title]="'backTo' | i18n: parent.label ?? placeholderText"
|
||||
>
|
||||
<i slot="start" class="bwi bwi-angle-left" aria-hidden="true"></i>
|
||||
{{ "backTo" | i18n: parent.label ?? placeholderText }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="selectOption(renderedOptions, $event)"
|
||||
[title]="'viewItemsIn' | i18n: renderedOptions.label"
|
||||
class="tw-text-[length:inherit]"
|
||||
>
|
||||
<i slot="start" class="bwi bwi-list" aria-hidden="true"></i>
|
||||
{{ "viewItemsIn" | i18n: renderedOptions.label }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
*ngFor="let option of renderedOptions.children"
|
||||
(click)="option.children?.length ? viewOption(option, $event) : selectOption(option, $event)"
|
||||
[disabled]="option.disabled"
|
||||
[title]="option.label"
|
||||
class="tw-text-[length:inherit]"
|
||||
[attr.aria-haspopup]="option.children?.length ? 'menu' : null"
|
||||
@if (renderedOptions) {
|
||||
<div
|
||||
class="tw-max-h-80 tw-min-w-32 tw-max-w-80 tw-text-sm"
|
||||
[ngStyle]="menuWidth && { width: menuWidth + 'px' }"
|
||||
>
|
||||
<i
|
||||
*ngIf="option.icon"
|
||||
slot="start"
|
||||
class="bwi"
|
||||
[ngClass]="option.icon"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
{{ option.label }}
|
||||
<i *ngIf="option.children?.length" slot="end" class="bwi bwi-angle-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
@if (getParent(renderedOptions); as parent) {
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="viewOption(parent, $event)"
|
||||
class="tw-text-[length:inherit]"
|
||||
[title]="'backTo' | i18n: parent.label ?? placeholderText"
|
||||
>
|
||||
<i slot="start" class="bwi bwi-angle-left" aria-hidden="true"></i>
|
||||
{{ "backTo" | i18n: parent.label ?? placeholderText }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="selectOption(renderedOptions, $event)"
|
||||
[title]="'viewItemsIn' | i18n: renderedOptions.label"
|
||||
class="tw-text-[length:inherit]"
|
||||
>
|
||||
<i slot="start" class="bwi bwi-list" aria-hidden="true"></i>
|
||||
{{ "viewItemsIn" | i18n: renderedOptions.label }}
|
||||
</button>
|
||||
}
|
||||
@for (option of renderedOptions.children; track option) {
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="
|
||||
option.children?.length ? viewOption(option, $event) : selectOption(option, $event)
|
||||
"
|
||||
[disabled]="option.disabled"
|
||||
[title]="option.label"
|
||||
class="tw-text-[length:inherit]"
|
||||
[attr.aria-haspopup]="option.children?.length ? 'menu' : null"
|
||||
>
|
||||
@if (option.icon) {
|
||||
<i slot="start" class="bwi" [ngClass]="option.icon" aria-hidden="true"></i>
|
||||
}
|
||||
{{ option.label }}
|
||||
@if (option.children?.length) {
|
||||
<i slot="end" class="bwi bwi-angle-right"></i>
|
||||
}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</bit-menu>
|
||||
|
@ -46,6 +46,7 @@ export type ChipSelectOption<T> = Option<T> & {
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, AfterViewInit {
|
||||
@ViewChild(MenuComponent) menu: MenuComponent;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgFor, NgIf } from "@angular/common";
|
||||
|
||||
import { Component, HostBinding, Input } from "@angular/core";
|
||||
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
@ -14,18 +14,16 @@ enum CharacterType {
|
||||
|
||||
@Component({
|
||||
selector: "bit-color-password",
|
||||
template: `<span
|
||||
*ngFor="let character of passwordArray; index as i"
|
||||
[class]="getCharacterClass(character)"
|
||||
>
|
||||
<span>{{ character }}</span>
|
||||
<span *ngIf="showCount" class="tw-whitespace-nowrap tw-text-xs tw-leading-5 tw-text-main">{{
|
||||
i + 1
|
||||
}}</span>
|
||||
</span>`,
|
||||
template: `@for (character of passwordArray; track character; let i = $index) {
|
||||
<span [class]="getCharacterClass(character)">
|
||||
<span>{{ character }}</span>
|
||||
@if (showCount) {
|
||||
<span class="tw-whitespace-nowrap tw-text-xs tw-leading-5 tw-text-main">{{ i + 1 }}</span>
|
||||
}
|
||||
</span>
|
||||
}`,
|
||||
preserveWhitespaces: false,
|
||||
standalone: true,
|
||||
imports: [NgFor, NgIf],
|
||||
})
|
||||
export class ColorPasswordComponent {
|
||||
@Input() password: string = null;
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
/**
|
||||
@ -7,7 +6,6 @@ import { Component } from "@angular/core";
|
||||
@Component({
|
||||
selector: "bit-container",
|
||||
templateUrl: "container.component.html",
|
||||
imports: [CommonModule],
|
||||
standalone: true,
|
||||
})
|
||||
export class ContainerComponent {}
|
||||
|
@ -13,9 +13,11 @@
|
||||
class="tw-text-main tw-mb-0 tw-truncate"
|
||||
>
|
||||
{{ title }}
|
||||
<span *ngIf="subtitle" class="tw-text-muted tw-font-normal tw-text-sm">
|
||||
{{ subtitle }}
|
||||
</span>
|
||||
@if (subtitle) {
|
||||
<span class="tw-text-muted tw-font-normal tw-text-sm">
|
||||
{{ subtitle }}
|
||||
</span>
|
||||
}
|
||||
<ng-content select="[bitDialogTitle]"></ng-content>
|
||||
</h1>
|
||||
<button
|
||||
@ -35,9 +37,11 @@
|
||||
'tw-min-h-60': loading,
|
||||
}"
|
||||
>
|
||||
<div *ngIf="loading" class="tw-absolute tw-flex tw-size-full tw-items-center tw-justify-center">
|
||||
<i class="bwi bwi-spinner bwi-spin bwi-lg" [attr.aria-label]="'loading' | i18n"></i>
|
||||
</div>
|
||||
@if (loading) {
|
||||
<div class="tw-absolute tw-flex tw-size-full tw-items-center tw-justify-center">
|
||||
<i class="bwi bwi-spinner bwi-spin bwi-lg" [attr.aria-label]="'loading' | i18n"></i>
|
||||
</div>
|
||||
}
|
||||
<div
|
||||
[ngClass]="{
|
||||
'tw-p-4': !disablePadding,
|
||||
|
@ -11,16 +11,17 @@
|
||||
{{ acceptButtonText }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
*ngIf="showCancelButton"
|
||||
type="button"
|
||||
bitButton
|
||||
bitFormButton
|
||||
buttonType="secondary"
|
||||
(click)="dialogRef.close(false)"
|
||||
>
|
||||
{{ cancelButtonText }}
|
||||
</button>
|
||||
@if (showCancelButton) {
|
||||
<button
|
||||
type="button"
|
||||
bitButton
|
||||
bitFormButton
|
||||
buttonType="secondary"
|
||||
(click)="dialogRef.close(false)"
|
||||
>
|
||||
{{ cancelButtonText }}
|
||||
</button>
|
||||
}
|
||||
</ng-container>
|
||||
</bit-simple-dialog>
|
||||
</form>
|
||||
|
@ -1,7 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { NgIf } from "@angular/common";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { FormGroup, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
@ -39,7 +38,6 @@ const DEFAULT_COLOR: Record<SimpleDialogType, string> = {
|
||||
IconDirective,
|
||||
ButtonComponent,
|
||||
BitFormButtonDirective,
|
||||
NgIf,
|
||||
],
|
||||
})
|
||||
export class SimpleConfigurableDialogComponent {
|
||||
|
@ -12,23 +12,24 @@ import { DialogModule } from "../../dialog.module";
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<div *ngFor="let group of dialogs">
|
||||
<h2>{{ group.title }}</h2>
|
||||
<div class="tw-mb-4 tw-flex tw-flex-row tw-gap-2">
|
||||
<button
|
||||
type="button"
|
||||
*ngFor="let dialog of group.dialogs"
|
||||
bitButton
|
||||
(click)="openSimpleConfigurableDialog(dialog)"
|
||||
>
|
||||
{{ dialog.title }}
|
||||
</button>
|
||||
@for (group of dialogs; track group) {
|
||||
<div>
|
||||
<h2>{{ group.title }}</h2>
|
||||
<div class="tw-mb-4 tw-flex tw-flex-row tw-gap-2">
|
||||
@for (dialog of group.dialogs; track dialog) {
|
||||
<button type="button" bitButton (click)="openSimpleConfigurableDialog(dialog)">
|
||||
{{ dialog.title }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<bit-callout *ngIf="showCallout" [type]="calloutType" title="Dialog Close Result">
|
||||
{{ dialogCloseResult }}
|
||||
</bit-callout>
|
||||
@if (showCallout) {
|
||||
<bit-callout [type]="calloutType" title="Dialog Close Result">
|
||||
{{ dialogCloseResult }}
|
||||
</bit-callout>
|
||||
}
|
||||
`,
|
||||
})
|
||||
class StoryDialogComponent {
|
||||
|
@ -3,12 +3,11 @@
|
||||
@fadeIn
|
||||
>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2 tw-px-4 tw-pt-4 tw-text-center">
|
||||
<ng-container *ngIf="hasIcon; else elseBlock">
|
||||
@if (hasIcon) {
|
||||
<ng-content select="[bitDialogIcon]"></ng-content>
|
||||
</ng-container>
|
||||
<ng-template #elseBlock>
|
||||
} @else {
|
||||
<i class="bwi bwi-exclamation-triangle tw-text-3xl tw-text-warning" aria-hidden="true"></i>
|
||||
</ng-template>
|
||||
}
|
||||
<h1
|
||||
bitDialogTitleContainer
|
||||
bitTypography="h3"
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { NgIf } from "@angular/common";
|
||||
import { Component, ContentChild, Directive } from "@angular/core";
|
||||
|
||||
import { TypographyDirective } from "../../typography/typography.directive";
|
||||
@ -16,7 +15,7 @@ export class IconDirective {}
|
||||
templateUrl: "./simple-dialog.component.html",
|
||||
animations: [fadeIn],
|
||||
standalone: true,
|
||||
imports: [NgIf, DialogTitleContainerDirective, TypographyDirective],
|
||||
imports: [DialogTitleContainerDirective, TypographyDirective],
|
||||
})
|
||||
export class SimpleDialogComponent {
|
||||
@ContentChild(IconDirective) icon!: IconDirective;
|
||||
|
@ -9,11 +9,17 @@
|
||||
>
|
||||
<span bitTypography="body2">
|
||||
<ng-content select="bit-label"></ng-content>
|
||||
<span *ngIf="required" class="tw-text-xs tw-font-normal"> ({{ "required" | i18n }})</span>
|
||||
@if (required) {
|
||||
<span class="tw-text-xs tw-font-normal"> ({{ "required" | i18n }})</span>
|
||||
}
|
||||
</span>
|
||||
<ng-content select="bit-hint" *ngIf="!hasError"></ng-content>
|
||||
@if (!hasError) {
|
||||
<ng-content select="bit-hint"></ng-content>
|
||||
}
|
||||
</span>
|
||||
</label>
|
||||
<div *ngIf="hasError" class="tw-mt-1 tw-text-danger tw-text-xs tw-ml-0.5">
|
||||
<i class="bwi bwi-error"></i> {{ displayError }}
|
||||
</div>
|
||||
@if (hasError) {
|
||||
<div class="tw-mt-1 tw-text-danger tw-text-xs tw-ml-0.5">
|
||||
<i class="bwi bwi-error"></i> {{ displayError }}
|
||||
</div>
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { NgClass, NgIf } from "@angular/common";
|
||||
import { NgClass } from "@angular/common";
|
||||
import { Component, ContentChild, HostBinding, Input } from "@angular/core";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@ -15,7 +15,7 @@ import { BitFormControlAbstraction } from "./form-control.abstraction";
|
||||
selector: "bit-form-control",
|
||||
templateUrl: "form-control.component.html",
|
||||
standalone: true,
|
||||
imports: [NgClass, TypographyDirective, NgIf, I18nPipe],
|
||||
imports: [NgClass, TypographyDirective, I18nPipe],
|
||||
})
|
||||
export class FormControlComponent {
|
||||
@Input() label: string;
|
||||
|
@ -5,10 +5,10 @@
|
||||
<!-- labels inside a form control (checkbox, radio button) should not truncate -->
|
||||
<span [ngClass]="{ 'tw-truncate': !isInsideFormControl }">
|
||||
<ng-content></ng-content>
|
||||
<ng-container *ngIf="isInsideFormControl">
|
||||
@if (isInsideFormControl) {
|
||||
<ng-container *ngTemplateOutlet="endSlotContent"></ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
</span>
|
||||
<ng-container *ngIf="!isInsideFormControl">
|
||||
@if (!isInsideFormControl) {
|
||||
<ng-container *ngTemplateOutlet="endSlotContent"></ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgIf } from "@angular/common";
|
||||
|
||||
import { Component, Input } from "@angular/core";
|
||||
import { AbstractControl, UntypedFormGroup } from "@angular/forms";
|
||||
|
||||
@ -8,15 +8,15 @@ import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
@Component({
|
||||
selector: "bit-error-summary",
|
||||
template: ` <ng-container *ngIf="errorCount > 0">
|
||||
template: ` @if (errorCount > 0) {
|
||||
<i class="bwi bwi-error"></i> {{ "fieldsNeedAttention" | i18n: errorString }}
|
||||
</ng-container>`,
|
||||
}`,
|
||||
host: {
|
||||
class: "tw-block tw-text-danger tw-mt-2",
|
||||
"aria-live": "assertive",
|
||||
},
|
||||
standalone: true,
|
||||
imports: [NgIf, I18nPipe],
|
||||
imports: [I18nPipe],
|
||||
})
|
||||
export class BitErrorSummary {
|
||||
@Input()
|
||||
|
@ -15,63 +15,65 @@
|
||||
<ng-content select="[bitSuffix]"></ng-content>
|
||||
</ng-template>
|
||||
|
||||
<div *ngIf="!readOnly; else readOnlyView" class="tw-w-full tw-relative tw-group/bit-form-field">
|
||||
<div class="tw-absolute tw-size-full tw-top-0 tw-pointer-events-none tw-z-20">
|
||||
<div class="tw-size-full tw-flex">
|
||||
<div
|
||||
class="tw-min-w-3 tw-border-r-0 group-focus-within/bit-form-field:tw-border-r-0 !tw-rounded-l-lg"
|
||||
[ngClass]="inputBorderClasses"
|
||||
></div>
|
||||
<div
|
||||
class="tw-px-1 tw-shrink tw-min-w-0 tw-mt-px tw-border-x-0 tw-border-t-0 group-focus-within/bit-form-field:tw-border-x-0 group-focus-within/bit-form-field:tw-border-t-0 tw-hidden group-has-[bit-label]/bit-form-field:tw-block"
|
||||
[ngClass]="inputBorderClasses"
|
||||
>
|
||||
<label
|
||||
class="tw-flex tw-gap-1 tw-text-sm tw-text-muted -tw-translate-y-[0.675rem] tw-mb-0 tw-max-w-full tw-pointer-events-auto"
|
||||
[attr.for]="input.labelForId"
|
||||
@if (!readOnly) {
|
||||
<div class="tw-w-full tw-relative tw-group/bit-form-field">
|
||||
<div class="tw-absolute tw-size-full tw-top-0 tw-pointer-events-none tw-z-20">
|
||||
<div class="tw-size-full tw-flex">
|
||||
<div
|
||||
class="tw-min-w-3 tw-border-r-0 group-focus-within/bit-form-field:tw-border-r-0 !tw-rounded-l-lg"
|
||||
[ngClass]="inputBorderClasses"
|
||||
></div>
|
||||
<div
|
||||
class="tw-px-1 tw-shrink tw-min-w-0 tw-mt-px tw-border-x-0 tw-border-t-0 group-focus-within/bit-form-field:tw-border-x-0 group-focus-within/bit-form-field:tw-border-t-0 tw-hidden group-has-[bit-label]/bit-form-field:tw-block"
|
||||
[ngClass]="inputBorderClasses"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="labelContent"></ng-container>
|
||||
<span *ngIf="input.required" class="tw-text-[0.625rem] tw-relative tw-bottom-[-1px]">
|
||||
({{ "required" | i18n }})</span
|
||||
<label
|
||||
class="tw-flex tw-gap-1 tw-text-sm tw-text-muted -tw-translate-y-[0.675rem] tw-mb-0 tw-max-w-full tw-pointer-events-auto"
|
||||
[attr.for]="input.labelForId"
|
||||
>
|
||||
</label>
|
||||
<ng-container *ngTemplateOutlet="labelContent"></ng-container>
|
||||
@if (input.required) {
|
||||
<span class="tw-text-[0.625rem] tw-relative tw-bottom-[-1px]">
|
||||
({{ "required" | i18n }})</span
|
||||
>
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="tw-min-w-3 tw-grow tw-border-l-0 group-focus-within/bit-form-field:tw-border-l-0 !tw-rounded-r-lg"
|
||||
[ngClass]="inputBorderClasses"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="tw-gap-1 tw-bg-background tw-rounded-lg tw-flex tw-min-h-11 [&:not(:has(button:enabled)):has(input:read-only)]:tw-bg-secondary-100 [&:not(:has(button:enabled)):has(textarea:read-only)]:tw-bg-secondary-100"
|
||||
>
|
||||
<div
|
||||
#prefixContainer
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-pl-3 tw-py-2"
|
||||
[hidden]="!prefixHasChildren()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="prefixContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
class="tw-min-w-3 tw-grow tw-border-l-0 group-focus-within/bit-form-field:tw-border-l-0 !tw-rounded-r-lg"
|
||||
[ngClass]="inputBorderClasses"
|
||||
></div>
|
||||
class="default-content tw-w-full tw-relative tw-py-2 has-[bit-select]:tw-p-0 has-[bit-multi-select]:tw-p-0 has-[input:read-only:not([hidden])]:tw-bg-secondary-100 has-[textarea:read-only:not([hidden])]:tw-bg-secondary-100"
|
||||
[ngClass]="[
|
||||
prefixHasChildren() ? '' : 'tw-rounded-l-lg tw-pl-3',
|
||||
suffixHasChildren() ? '' : 'tw-rounded-r-lg tw-pr-3',
|
||||
]"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="defaultContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
#suffixContainer
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-pr-3 tw-py-2"
|
||||
[hidden]="!suffixHasChildren()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="suffixContent"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="tw-gap-1 tw-bg-background tw-rounded-lg tw-flex tw-min-h-11 [&:not(:has(button:enabled)):has(input:read-only)]:tw-bg-secondary-100 [&:not(:has(button:enabled)):has(textarea:read-only)]:tw-bg-secondary-100"
|
||||
>
|
||||
<div
|
||||
#prefixContainer
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-pl-3 tw-py-2"
|
||||
[hidden]="!prefixHasChildren()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="prefixContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
class="default-content tw-w-full tw-relative tw-py-2 has-[bit-select]:tw-p-0 has-[bit-multi-select]:tw-p-0 has-[input:read-only:not([hidden])]:tw-bg-secondary-100 has-[textarea:read-only:not([hidden])]:tw-bg-secondary-100"
|
||||
[ngClass]="[
|
||||
prefixHasChildren() ? '' : 'tw-rounded-l-lg tw-pl-3',
|
||||
suffixHasChildren() ? '' : 'tw-rounded-r-lg tw-pr-3',
|
||||
]"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="defaultContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
#suffixContainer
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-pr-3 tw-py-2"
|
||||
[hidden]="!suffixHasChildren()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="suffixContent"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #readOnlyView>
|
||||
} @else {
|
||||
<div class="tw-w-full tw-relative">
|
||||
<label
|
||||
class="tw-flex tw-gap-1 tw-text-sm tw-text-muted tw-mb-0 tw-max-w-full"
|
||||
@ -107,9 +109,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
|
||||
<ng-container [ngSwitch]="input.hasError">
|
||||
<ng-content select="bit-hint" *ngSwitchCase="false"></ng-content>
|
||||
<bit-error [error]="input.error" *ngSwitchCase="true"></bit-error>
|
||||
</ng-container>
|
||||
@switch (input.hasError) {
|
||||
@case (false) {
|
||||
<ng-content select="bit-hint"></ng-content>
|
||||
}
|
||||
@case (true) {
|
||||
<bit-error [error]="input.error"></bit-error>
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import {
|
||||
AfterContentChecked,
|
||||
ChangeDetectionStrategy,
|
||||
@ -16,7 +16,7 @@ import { TypographyModule } from "../typography";
|
||||
@Component({
|
||||
selector: "bit-item-content, [bit-item-content]",
|
||||
standalone: true,
|
||||
imports: [CommonModule, TypographyModule],
|
||||
imports: [TypographyModule],
|
||||
templateUrl: `item-content.component.html`,
|
||||
host: {
|
||||
class:
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
@ -14,7 +13,7 @@ import { ItemActionComponent } from "./item-action.component";
|
||||
@Component({
|
||||
selector: "bit-item",
|
||||
standalone: true,
|
||||
imports: [CommonModule, ItemActionComponent],
|
||||
imports: [ItemActionComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
templateUrl: "item.component.html",
|
||||
providers: [{ provide: A11yRowDirective, useExisting: ItemComponent }],
|
||||
|
@ -23,19 +23,21 @@
|
||||
<ng-content></ng-content>
|
||||
|
||||
<!-- overlay backdrop for side-nav -->
|
||||
<div
|
||||
*ngIf="{
|
||||
@if (
|
||||
{
|
||||
open: sideNavService.open$ | async,
|
||||
} as data"
|
||||
class="tw-pointer-events-none tw-fixed tw-inset-0 tw-z-10 tw-bg-black tw-bg-opacity-0 motion-safe:tw-transition-colors md:tw-hidden"
|
||||
[ngClass]="[data.open ? 'tw-bg-opacity-30 md:tw-bg-opacity-0' : 'tw-bg-opacity-0']"
|
||||
>
|
||||
};
|
||||
as data
|
||||
) {
|
||||
<div
|
||||
*ngIf="data.open"
|
||||
(click)="sideNavService.toggle()"
|
||||
class="tw-pointer-events-auto tw-size-full"
|
||||
></div>
|
||||
</div>
|
||||
class="tw-pointer-events-none tw-fixed tw-inset-0 tw-z-10 tw-bg-black tw-bg-opacity-0 motion-safe:tw-transition-colors md:tw-hidden"
|
||||
[ngClass]="[data.open ? 'tw-bg-opacity-30 md:tw-bg-opacity-0' : 'tw-bg-opacity-0']"
|
||||
>
|
||||
@if (data.open) {
|
||||
<div (click)="sideNavService.toggle()" class="tw-pointer-events-auto tw-size-full"></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</main>
|
||||
<ng-template [cdkPortalOutlet]="drawerPortal()"></ng-template>
|
||||
</div>
|
||||
|
@ -31,7 +31,9 @@
|
||||
[disabled]="disabled"
|
||||
(click)="clear(item)"
|
||||
>
|
||||
<i *ngIf="item.icon != null" class="bwi bwi-fw {{ item.icon }}" aria-hidden="true"></i>
|
||||
@if (item.icon != null) {
|
||||
<i class="bwi bwi-fw {{ item.icon }}" aria-hidden="true"></i>
|
||||
}
|
||||
<span class="tw-truncate">
|
||||
{{ item.labelName }}
|
||||
</span>
|
||||
@ -41,10 +43,14 @@
|
||||
<ng-template ng-option-tmp let-item="item">
|
||||
<div class="tw-flex">
|
||||
<div class="tw-w-7 tw-flex-none">
|
||||
<i *ngIf="isSelected(item)" class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
||||
@if (isSelected(item)) {
|
||||
<i class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
||||
}
|
||||
</div>
|
||||
<div class="tw-mr-2 tw-flex-initial">
|
||||
<i *ngIf="item.icon != null" class="bwi bwi-fw {{ item.icon }}" aria-hidden="true"></i>
|
||||
@if (item.icon != null) {
|
||||
<i class="bwi bwi-fw {{ item.icon }}" aria-hidden="true"></i>
|
||||
}
|
||||
</div>
|
||||
<div class="tw-flex-1">
|
||||
{{ item.listName }}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// @ts-strict-ignore
|
||||
import { coerceBooleanProperty } from "@angular/cdk/coercion";
|
||||
import { hasModifierKey } from "@angular/cdk/keycodes";
|
||||
import { NgIf } from "@angular/common";
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
@ -39,7 +38,7 @@ let nextId = 0;
|
||||
templateUrl: "./multi-select.component.html",
|
||||
providers: [{ provide: BitFormFieldControl, useExisting: MultiSelectComponent }],
|
||||
standalone: true,
|
||||
imports: [NgSelectModule, ReactiveFormsModule, FormsModule, BadgeModule, NgIf, I18nPipe],
|
||||
imports: [NgSelectModule, ReactiveFormsModule, FormsModule, BadgeModule, I18nPipe],
|
||||
})
|
||||
/**
|
||||
* This component has been implemented to only support Multi-select list events
|
||||
|
@ -1 +1,3 @@
|
||||
<div *ngIf="sideNavService.open$ | async" class="tw-h-px tw-w-full tw-bg-secondary-300"></div>
|
||||
@if (sideNavService.open$ | async) {
|
||||
<div class="tw-h-px tw-w-full tw-bg-secondary-300"></div>
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- This a higher order component that composes `NavItemComponent` -->
|
||||
<ng-container *ngIf="!hideIfEmpty || nestedNavComponents.length > 0">
|
||||
@if (!hideIfEmpty || nestedNavComponents.length > 0) {
|
||||
<bit-nav-item
|
||||
[text]="text"
|
||||
[icon]="icon"
|
||||
@ -29,28 +29,29 @@
|
||||
[attr.aria-label]="['toggleCollapse' | i18n, text].join(' ')"
|
||||
></button>
|
||||
</ng-template>
|
||||
|
||||
<!-- Show toggle to the left for trees otherwise to the right -->
|
||||
<ng-container slot="start" *ngIf="variant === 'tree'">
|
||||
<ng-container *ngTemplateOutlet="button"></ng-container>
|
||||
</ng-container>
|
||||
<ng-container slot="end">
|
||||
<ng-content select="[slot=end]"></ng-content>
|
||||
<ng-container *ngIf="variant !== 'tree'">
|
||||
@if (variant === "tree") {
|
||||
<ng-container slot="start">
|
||||
<ng-container *ngTemplateOutlet="button"></ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
<ng-container slot="end">
|
||||
<ng-content select="[slot=end]"></ng-content>
|
||||
@if (variant !== "tree") {
|
||||
<ng-container *ngTemplateOutlet="button"></ng-container>
|
||||
}
|
||||
</ng-container>
|
||||
</bit-nav-item>
|
||||
|
||||
<!-- [attr.aria-controls] of the above button expects a unique ID on the controlled element -->
|
||||
<ng-container *ngIf="sideNavService.open$ | async">
|
||||
<div
|
||||
*ngIf="open"
|
||||
[attr.id]="contentId"
|
||||
[attr.aria-label]="[text, 'submenu' | i18n].join(' ')"
|
||||
role="group"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@if (sideNavService.open$ | async) {
|
||||
@if (open) {
|
||||
<div
|
||||
[attr.id]="contentId"
|
||||
[attr.aria-label]="[text, 'submenu' | i18n].join(' ')"
|
||||
role="group"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import { SideNavService } from "./side-nav.service";
|
||||
],
|
||||
standalone: true,
|
||||
imports: [CommonModule, NavItemComponent, IconButtonModule, I18nPipe],
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class NavGroupComponent extends NavBaseComponent implements AfterContentInit {
|
||||
@ContentChildren(NavBaseComponent, {
|
||||
|
@ -1,20 +1,23 @@
|
||||
<div *ngIf="sideNavService.open" class="tw-sticky tw-top-0 tw-z-50">
|
||||
<a
|
||||
[routerLink]="route"
|
||||
class="tw-px-5 tw-pb-5 tw-pt-7 tw-block tw-bg-background-alt3 tw-outline-none focus-visible:tw-ring focus-visible:tw-ring-inset focus-visible:tw-ring-text-alt2"
|
||||
[attr.aria-label]="label"
|
||||
[title]="label"
|
||||
routerLinkActive
|
||||
[ariaCurrentWhenActive]="'page'"
|
||||
>
|
||||
<bit-icon [icon]="openIcon"></bit-icon>
|
||||
</a>
|
||||
</div>
|
||||
<bit-nav-item
|
||||
class="tw-block tw-pt-7"
|
||||
[hideActiveStyles]="true"
|
||||
[route]="route"
|
||||
[icon]="closedIcon"
|
||||
*ngIf="!sideNavService.open"
|
||||
[text]="label"
|
||||
></bit-nav-item>
|
||||
@if (sideNavService.open) {
|
||||
<div class="tw-sticky tw-top-0 tw-z-50">
|
||||
<a
|
||||
[routerLink]="route"
|
||||
class="tw-px-5 tw-pb-5 tw-pt-7 tw-block tw-bg-background-alt3 tw-outline-none focus-visible:tw-ring focus-visible:tw-ring-inset focus-visible:tw-ring-text-alt2"
|
||||
[attr.aria-label]="label"
|
||||
[title]="label"
|
||||
routerLinkActive
|
||||
[ariaCurrentWhenActive]="'page'"
|
||||
>
|
||||
<bit-icon [icon]="openIcon"></bit-icon>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
@if (!sideNavService.open) {
|
||||
<bit-nav-item
|
||||
class="tw-block tw-pt-7"
|
||||
[hideActiveStyles]="true"
|
||||
[route]="route"
|
||||
[icon]="closedIcon"
|
||||
[text]="label"
|
||||
></bit-nav-item>
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgIf } from "@angular/common";
|
||||
|
||||
import { Component, Input } from "@angular/core";
|
||||
import { RouterLinkActive, RouterLink } from "@angular/router";
|
||||
|
||||
@ -14,7 +14,7 @@ import { SideNavService } from "./side-nav.service";
|
||||
selector: "bit-nav-logo",
|
||||
templateUrl: "./nav-logo.component.html",
|
||||
standalone: true,
|
||||
imports: [NgIf, RouterLinkActive, RouterLink, BitIconComponent, NavItemComponent],
|
||||
imports: [RouterLinkActive, RouterLink, BitIconComponent, NavItemComponent],
|
||||
})
|
||||
export class NavLogoComponent {
|
||||
/** Icon that is displayed when the side nav is closed */
|
||||
|
@ -1,42 +1,46 @@
|
||||
<nav
|
||||
*ngIf="{
|
||||
@if (
|
||||
{
|
||||
open: sideNavService.open$ | async,
|
||||
isOverlay: sideNavService.isOverlay$ | async,
|
||||
} as data"
|
||||
id="bit-side-nav"
|
||||
class="tw-fixed md:tw-sticky tw-inset-y-0 tw-left-0 tw-z-30 tw-flex tw-h-screen tw-flex-col tw-overscroll-none tw-overflow-auto tw-bg-background-alt3 tw-outline-none"
|
||||
[ngClass]="{ 'tw-w-60': data.open }"
|
||||
[ngStyle]="
|
||||
variant === 'secondary' && {
|
||||
'--color-text-alt2': 'var(--color-text-main)',
|
||||
'--color-background-alt3': 'var(--color-secondary-100)',
|
||||
'--color-background-alt4': 'var(--color-secondary-300)',
|
||||
}
|
||||
"
|
||||
[cdkTrapFocus]="data.isOverlay"
|
||||
[attr.role]="data.isOverlay ? 'dialog' : null"
|
||||
[attr.aria-modal]="data.isOverlay ? 'true' : null"
|
||||
(keydown)="handleKeyDown($event)"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
<div class="tw-sticky tw-bottom-0 tw-left-0 tw-z-20 tw-mt-auto tw-w-full tw-bg-background-alt3">
|
||||
<bit-nav-divider></bit-nav-divider>
|
||||
<ng-container *ngIf="data.open">
|
||||
<ng-content select="[slot=footer]"></ng-content>
|
||||
</ng-container>
|
||||
<div class="tw-mx-0.5 tw-my-4 tw-w-[3.75rem]">
|
||||
<button
|
||||
#toggleButton
|
||||
type="button"
|
||||
class="tw-mx-auto tw-block tw-max-w-fit"
|
||||
[bitIconButton]="data.open ? 'bwi-angle-left' : 'bwi-angle-right'"
|
||||
buttonType="light"
|
||||
size="small"
|
||||
(click)="sideNavService.toggle()"
|
||||
[attr.aria-label]="'toggleSideNavigation' | i18n"
|
||||
[attr.aria-expanded]="data.open"
|
||||
aria-controls="bit-side-nav"
|
||||
></button>
|
||||
};
|
||||
as data
|
||||
) {
|
||||
<nav
|
||||
id="bit-side-nav"
|
||||
class="tw-fixed md:tw-sticky tw-inset-y-0 tw-left-0 tw-z-30 tw-flex tw-h-screen tw-flex-col tw-overscroll-none tw-overflow-auto tw-bg-background-alt3 tw-outline-none"
|
||||
[ngClass]="{ 'tw-w-60': data.open }"
|
||||
[ngStyle]="
|
||||
variant === 'secondary' && {
|
||||
'--color-text-alt2': 'var(--color-text-main)',
|
||||
'--color-background-alt3': 'var(--color-secondary-100)',
|
||||
'--color-background-alt4': 'var(--color-secondary-300)',
|
||||
}
|
||||
"
|
||||
[cdkTrapFocus]="data.isOverlay"
|
||||
[attr.role]="data.isOverlay ? 'dialog' : null"
|
||||
[attr.aria-modal]="data.isOverlay ? 'true' : null"
|
||||
(keydown)="handleKeyDown($event)"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
<div class="tw-sticky tw-bottom-0 tw-left-0 tw-z-20 tw-mt-auto tw-w-full tw-bg-background-alt3">
|
||||
<bit-nav-divider></bit-nav-divider>
|
||||
@if (data.open) {
|
||||
<ng-content select="[slot=footer]"></ng-content>
|
||||
}
|
||||
<div class="tw-mx-0.5 tw-my-4 tw-w-[3.75rem]">
|
||||
<button
|
||||
#toggleButton
|
||||
type="button"
|
||||
class="tw-mx-auto tw-block tw-max-w-fit"
|
||||
[bitIconButton]="data.open ? 'bwi-angle-left' : 'bwi-angle-right'"
|
||||
buttonType="light"
|
||||
size="small"
|
||||
(click)="sideNavService.toggle()"
|
||||
[attr.aria-label]="'toggleSideNavigation' | i18n"
|
||||
[attr.aria-expanded]="data.open"
|
||||
aria-controls="bit-side-nav"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</nav>
|
||||
}
|
||||
|
@ -7,13 +7,12 @@
|
||||
attr.aria-valuenow="{{ barWidth }}"
|
||||
[ngStyle]="{ width: barWidth + '%' }"
|
||||
>
|
||||
<div
|
||||
*ngIf="displayText"
|
||||
class="tw-flex tw-h-full tw-flex-wrap tw-items-center tw-overflow-hidden"
|
||||
>
|
||||
<!-- If text is too long to fit, wrap it below to hide -->
|
||||
<div class="tw-h-full"> </div>
|
||||
<div class="tw-pr-1">{{ textContent }}</div>
|
||||
</div>
|
||||
@if (displayText) {
|
||||
<div class="tw-flex tw-h-full tw-flex-wrap tw-items-center tw-overflow-hidden">
|
||||
<!-- If text is too long to fit, wrap it below to hide -->
|
||||
<div class="tw-h-full"> </div>
|
||||
<div class="tw-pr-1">{{ textContent }}</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,16 +1,18 @@
|
||||
<ng-container *ngIf="label">
|
||||
@if (label) {
|
||||
<fieldset>
|
||||
<legend class="tw-mb-1 tw-block tw-text-sm tw-font-semibold tw-text-main">
|
||||
<ng-content select="bit-label"></ng-content>
|
||||
<span *ngIf="required" class="tw-text-xs tw-font-normal"> ({{ "required" | i18n }})</span>
|
||||
@if (required) {
|
||||
<span class="tw-text-xs tw-font-normal"> ({{ "required" | i18n }})</span>
|
||||
}
|
||||
</legend>
|
||||
<ng-container *ngTemplateOutlet="content"></ng-container>
|
||||
</fieldset>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<ng-container *ngIf="!label">
|
||||
@if (!label) {
|
||||
<ng-container *ngTemplateOutlet="content"></ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<ng-template #content>
|
||||
<div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgIf, NgTemplateOutlet } from "@angular/common";
|
||||
import { NgTemplateOutlet } from "@angular/common";
|
||||
import { Component, ContentChild, HostBinding, Input, Optional, Self } from "@angular/core";
|
||||
import { ControlValueAccessor, NgControl, Validators } from "@angular/forms";
|
||||
|
||||
@ -14,7 +14,7 @@ let nextId = 0;
|
||||
selector: "bit-radio-group",
|
||||
templateUrl: "radio-group.component.html",
|
||||
standalone: true,
|
||||
imports: [NgIf, NgTemplateOutlet, I18nPipe],
|
||||
imports: [NgTemplateOutlet, I18nPipe],
|
||||
})
|
||||
export class RadioGroupComponent implements ControlValueAccessor {
|
||||
selected: unknown;
|
||||
|
@ -13,7 +13,9 @@
|
||||
<ng-template ng-option-tmp let-item="item">
|
||||
<div class="tw-flex" [title]="item.label">
|
||||
<div class="tw-mr-2 tw-flex-initial">
|
||||
<i *ngIf="item.icon != null" class="bwi bwi-fw {{ item.icon }}" aria-hidden="true"></i>
|
||||
@if (item.icon != null) {
|
||||
<i class="bwi bwi-fw {{ item.icon }}" aria-hidden="true"></i>
|
||||
}
|
||||
</div>
|
||||
<div class="tw-flex-1 tw-text-ellipsis tw-overflow-hidden">
|
||||
{{ item.label }}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { NgIf } from "@angular/common";
|
||||
|
||||
import {
|
||||
Component,
|
||||
ContentChildren,
|
||||
@ -36,7 +36,7 @@ let nextId = 0;
|
||||
templateUrl: "select.component.html",
|
||||
providers: [{ provide: BitFormFieldControl, useExisting: SelectComponent }],
|
||||
standalone: true,
|
||||
imports: [NgSelectModule, ReactiveFormsModule, FormsModule, NgIf],
|
||||
imports: [NgSelectModule, ReactiveFormsModule, FormsModule],
|
||||
})
|
||||
export class SelectComponent<T> implements BitFormFieldControl, ControlValueAccessor {
|
||||
@ViewChild(NgSelectComponent) select: NgSelectComponent;
|
||||
|
@ -49,11 +49,9 @@ import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
|
||||
<bit-form-field>
|
||||
<bit-label>Your favorite color</bit-label>
|
||||
<bit-select formControlName="favColor">
|
||||
<bit-option
|
||||
*ngFor="let color of colors"
|
||||
[value]="color.value"
|
||||
[label]="color.name"
|
||||
></bit-option>
|
||||
@for (color of colors; track color) {
|
||||
<bit-option [value]="color.value" [label]="color.name"></bit-option>
|
||||
}
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
|
||||
|
@ -36,9 +36,11 @@ class KitchenSinkDialog {
|
||||
|
||||
<p class="tw-mt-4">
|
||||
<bit-breadcrumbs>
|
||||
<bit-breadcrumb *ngFor="let item of navItems" [icon]="item.icon" [route]="[item.route]">
|
||||
{{ item.name }}
|
||||
</bit-breadcrumb>
|
||||
@for (item of navItems; track item) {
|
||||
<bit-breadcrumb [icon]="item.icon" [route]="[item.route]">
|
||||
{{ item.name }}
|
||||
</bit-breadcrumb>
|
||||
}
|
||||
</bit-breadcrumbs>
|
||||
</p>
|
||||
|
||||
|
@ -16,11 +16,15 @@ import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
|
||||
<bit-toggle value="small"> Mid-sized <span bitBadge variant="info">1</span> </bit-toggle>
|
||||
</bit-toggle-group>
|
||||
</div>
|
||||
<ul *ngFor="let company of companyList">
|
||||
<li *ngIf="company.size === selectedToggle || selectedToggle === 'all'">
|
||||
{{ company.name }}
|
||||
</li>
|
||||
</ul>
|
||||
@for (company of companyList; track company) {
|
||||
<ul>
|
||||
@if (company.size === selectedToggle || selectedToggle === "all") {
|
||||
<li>
|
||||
{{ company.name }}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
`,
|
||||
})
|
||||
export class KitchenSinkToggleList {
|
||||
|
@ -5,40 +5,41 @@
|
||||
[attr.aria-label]="label"
|
||||
(keydown)="keyManager.onKeydown($event)"
|
||||
>
|
||||
<button
|
||||
bitTabListItem
|
||||
*ngFor="let tab of tabs; let i = index"
|
||||
type="button"
|
||||
role="tab"
|
||||
[id]="getTabLabelId(i)"
|
||||
[active]="tab.isActive"
|
||||
[disabled]="tab.disabled"
|
||||
[attr.aria-selected]="selectedIndex === i"
|
||||
[attr.tabindex]="selectedIndex === i ? 0 : -1"
|
||||
(click)="selectTab(i)"
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="content"></ng-container>
|
||||
|
||||
<ng-template #content>
|
||||
<ng-template [ngIf]="tab.templateLabel" [ngIfElse]="tabTextLabel">
|
||||
<ng-container [ngTemplateOutlet]="tab.templateLabel.templateRef"></ng-container>
|
||||
@for (tab of tabs; track tab; let i = $index) {
|
||||
<button
|
||||
bitTabListItem
|
||||
type="button"
|
||||
role="tab"
|
||||
[id]="getTabLabelId(i)"
|
||||
[active]="tab.isActive"
|
||||
[disabled]="tab.disabled"
|
||||
[attr.aria-selected]="selectedIndex === i"
|
||||
[attr.tabindex]="selectedIndex === i ? 0 : -1"
|
||||
(click)="selectTab(i)"
|
||||
>
|
||||
<ng-container [ngTemplateOutlet]="content"></ng-container>
|
||||
<ng-template #content>
|
||||
@if (tab.templateLabel) {
|
||||
<ng-container [ngTemplateOutlet]="tab.templateLabel.templateRef"></ng-container>
|
||||
} @else {
|
||||
{{ tab.textLabel }}
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
<ng-template #tabTextLabel>{{ tab.textLabel }}</ng-template>
|
||||
</ng-template>
|
||||
</button>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</bit-tab-header>
|
||||
<div class="tw-px-4 tw-pt-5">
|
||||
<bit-tab-body
|
||||
role="tabpanel"
|
||||
*ngFor="let tab of tabs; let i = index"
|
||||
[id]="getTabContentId(i)"
|
||||
[attr.tabindex]="tab.contentTabIndex"
|
||||
[attr.labeledby]="getTabLabelId(i)"
|
||||
[active]="tab.isActive"
|
||||
[content]="tab.content"
|
||||
[preserveContent]="preserveContent"
|
||||
>
|
||||
</bit-tab-body>
|
||||
@for (tab of tabs; track tab; let i = $index) {
|
||||
<bit-tab-body
|
||||
role="tabpanel"
|
||||
[id]="getTabContentId(i)"
|
||||
[attr.tabindex]="tab.contentTabIndex"
|
||||
[attr.labeledby]="getTabLabelId(i)"
|
||||
[active]="tab.isActive"
|
||||
[content]="tab.content"
|
||||
[preserveContent]="preserveContent"
|
||||
>
|
||||
</bit-tab-body>
|
||||
}
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { FocusKeyManager } from "@angular/cdk/a11y";
|
||||
import { coerceNumberProperty } from "@angular/cdk/coercion";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { NgTemplateOutlet } from "@angular/common";
|
||||
import {
|
||||
AfterContentChecked,
|
||||
AfterContentInit,
|
||||
@ -33,7 +33,7 @@ let nextId = 0;
|
||||
templateUrl: "./tab-group.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
NgTemplateOutlet,
|
||||
TabHeaderComponent,
|
||||
TabListContainerDirective,
|
||||
TabListItemDirective,
|
||||
|
@ -7,15 +7,14 @@
|
||||
<i aria-hidden="true" class="bwi tw-text-xl tw-py-1.5 tw-px-2.5 {{ iconClass }}"></i>
|
||||
<div>
|
||||
<span class="tw-sr-only">{{ variant | i18n }}</span>
|
||||
<p *ngIf="title" data-testid="toast-title" class="tw-font-semibold tw-mb-0">{{ title }}</p>
|
||||
<p
|
||||
bitTypography="body2"
|
||||
*ngFor="let m of messageArray"
|
||||
data-testid="toast-message"
|
||||
class="tw-mb-2 last:tw-mb-0"
|
||||
>
|
||||
{{ m }}
|
||||
</p>
|
||||
@if (title) {
|
||||
<p data-testid="toast-title" class="tw-font-semibold tw-mb-0">{{ title }}</p>
|
||||
}
|
||||
@for (m of messageArray; track m) {
|
||||
<p bitTypography="body2" data-testid="toast-message" class="tw-mb-2 last:tw-mb-0">
|
||||
{{ m }}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
<!-- Overriding hover and focus-visible colors for a11y against colored background -->
|
||||
<button
|
||||
|
Loading…
Reference in New Issue
Block a user