1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-02 09:43:29 +00:00
Files
browser/libs/components/src/toggle-group/toggle.component.ts
2025-11-03 15:17:07 -05:00

114 lines
3.2 KiB
TypeScript

import { NgClass } from "@angular/common";
import {
AfterContentChecked,
AfterViewInit,
Component,
ElementRef,
HostBinding,
signal,
input,
viewChild,
} from "@angular/core";
import { ToggleGroupComponent } from "./toggle-group.component";
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-toggle",
templateUrl: "./toggle.component.html",
imports: [NgClass],
})
export class ToggleComponent<TValue> implements AfterContentChecked, AfterViewInit {
id = nextId++;
readonly value = input.required<TValue>();
readonly labelContent = viewChild<ElementRef<HTMLSpanElement>>("labelContent");
readonly bitBadgeContainer = viewChild<ElementRef<HTMLSpanElement>>("bitBadgeContainer");
constructor(private groupComponent: ToggleGroupComponent<TValue>) {}
@HostBinding("tabIndex") tabIndex = "-1";
@HostBinding("class") classList = ["tw-group/toggle", "tw-flex", "tw-min-w-16"];
protected readonly bitBadgeContainerHasChidlren = signal(false);
protected readonly labelTitle = signal<string | null>(null);
get name() {
return this.groupComponent.name;
}
get selected() {
return this.groupComponent.selected() === this.value();
}
get inputClasses() {
return ["tw-peer/toggle-input", "tw-appearance-none", "tw-outline-none"];
}
get labelClasses() {
return [
"tw-h-full",
"tw-w-full",
"tw-flex",
"tw-items-center",
"tw-justify-center",
"tw-gap-1.5",
"!tw-font-medium",
"tw-leading-5",
"tw-transition",
"tw-text-center",
"tw-text-sm",
"tw-border-primary-600",
"!tw-text-primary-600",
"tw-border-solid",
"tw-border-y",
"tw-border-r",
"tw-border-l-0",
"tw-cursor-pointer",
"hover:tw-bg-hover-default",
"group-first-of-type/toggle:tw-border-l",
"group-first-of-type/toggle:tw-rounded-s-full",
"group-last-of-type/toggle:tw-rounded-e-full",
"peer-focus-visible/toggle-input:tw-outline-none",
"peer-focus-visible/toggle-input:tw-ring",
"peer-focus-visible/toggle-input:tw-ring-offset-2",
"peer-focus-visible/toggle-input:tw-ring-primary-600",
"peer-focus-visible/toggle-input:tw-z-10",
"peer-focus-visible/toggle-input:tw-bg-primary-600",
"peer-focus-visible/toggle-input:tw-border-primary-600",
"peer-focus-visible/toggle-input:!tw-text-contrast",
"peer-checked/toggle-input:tw-bg-primary-600",
"peer-checked/toggle-input:tw-border-primary-600",
"peer-checked/toggle-input:!tw-text-contrast",
"tw-py-1.5",
"tw-px-3",
// Fix for bootstrap styles that add bottom margin
"!tw-mb-0",
];
}
onInputInteraction() {
this.groupComponent.onInputInteraction(this.value());
}
ngAfterContentChecked() {
this.bitBadgeContainerHasChidlren.set(
(this.bitBadgeContainer()?.nativeElement.childElementCount ?? 0) > 0,
);
}
ngAfterViewInit() {
const labelText = this.labelContent()?.nativeElement.innerText;
if (labelText) {
this.labelTitle.set(labelText);
}
}
}