1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 01:33:33 +00:00

[EC 456] Component Library Content Switching Tabs (#3452)

* [EC-456] Rename bitTabItem -> bitTab

* [EC-456] Use templateRefs or text for tab label content

* [EC-456] Add bit-tab-nav-bar component

* [EC-456] Finish content tab switching and nav tabs

* [EC-456] Undo accidental eslintrc.json change

* [EC-456] Fix directive/component selector naming convention

* [EC-456] Cleanup unnecessary InjectionTokens and simplify template label property

* [EC-456] Cleanup one more unnecessary InjectionToken

* [EC-456] Cleanup tab styles to better match Figma. Add internal tab header component for styling header background according to Figma.

* [EC-456] Add sub-folders for nav, content, and shared tab components/directives

* [EC-456] Code/style cleanup

* [EC-456] Remove underscore from protected members

* [EC-456] Cleanup tab stories and forgotten any type.

* [EC-456] Fix dark theme story tab content text color

* [EC-456] Add missing padding to tab header

* [EC-456] Add tab content padding to align with tab headers

* [EC-456] Move bottom tab border to header to span entire content area

* [EC-456] Force text-main tab label color

* [EC-456] Undo text-main change
This commit is contained in:
Shane Melton
2022-09-26 14:41:51 -07:00
committed by GitHub
parent e8936eb4c6
commit debaef2941
21 changed files with 653 additions and 112 deletions

View File

@@ -0,0 +1,13 @@
<a
bitTabListItem
[routerLink]="disabled ? null : route"
routerLinkActive
#rla="routerLinkActive"
[active]="rla.isActive"
[disabled]="disabled"
[attr.aria-disabled]="disabled"
ariaCurrentWhenActive="page"
role="link"
>
<ng-content></ng-content>
</a>

View File

@@ -0,0 +1,51 @@
import { FocusableOption } from "@angular/cdk/a11y";
import { AfterViewInit, Component, HostListener, Input, OnDestroy, ViewChild } from "@angular/core";
import { RouterLinkActive } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
import { TabListItemDirective } from "../shared/tab-list-item.directive";
import { TabNavBarComponent } from "./tab-nav-bar.component";
@Component({
selector: "bit-tab-link",
templateUrl: "tab-link.component.html",
})
export class TabLinkComponent implements FocusableOption, AfterViewInit, OnDestroy {
private destroy$ = new Subject<void>();
@ViewChild(TabListItemDirective) tabItem: TabListItemDirective;
@ViewChild("rla") routerLinkActive: RouterLinkActive;
@Input() route: string;
@Input() disabled = false;
@HostListener("keydown", ["$event"]) onKeyDown(event: KeyboardEvent) {
if (event.code === "Space") {
this.tabItem.click();
}
}
get active() {
return this.routerLinkActive?.isActive ?? false;
}
constructor(private _tabNavBar: TabNavBarComponent) {}
focus(): void {
this.tabItem.focus();
}
ngAfterViewInit() {
// The active state of tab links are tracked via the routerLinkActive directive
// We need to watch for changes to tell the parent nav group when the tab is active
this.routerLinkActive.isActiveChange
.pipe(takeUntil(this.destroy$))
.subscribe((_) => this._tabNavBar.updateActiveLink());
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

View File

@@ -0,0 +1,5 @@
<bit-tab-header>
<nav bitTabListContainer [attr.aria-label]="label" (keydown)="keyManager.onKeydown($event)">
<ng-content></ng-content>
</nav>
</bit-tab-header>

View File

@@ -0,0 +1,43 @@
import { FocusKeyManager } from "@angular/cdk/a11y";
import {
AfterContentInit,
Component,
ContentChildren,
forwardRef,
Input,
QueryList,
} from "@angular/core";
import { TabLinkComponent } from "./tab-link.component";
@Component({
selector: "bit-tab-nav-bar",
templateUrl: "tab-nav-bar.component.html",
})
export class TabNavBarComponent implements AfterContentInit {
@ContentChildren(forwardRef(() => TabLinkComponent)) tabLabels: QueryList<TabLinkComponent>;
@Input() label = "";
/**
* Focus key manager for keeping tab controls accessible.
* https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role#keyboard_interactions
*/
keyManager: FocusKeyManager<TabLinkComponent>;
ngAfterContentInit(): void {
this.keyManager = new FocusKeyManager(this.tabLabels)
.withHorizontalOrientation("ltr")
.withWrap()
.withHomeAndEnd();
}
updateActiveLink() {
// Keep the keyManager in sync with active tabs
const items = this.tabLabels.toArray();
for (let i = 0; i < items.length; i++) {
if (items[i].active) {
this.keyManager.updateActiveItem(i);
}
}
}
}