mirror of
https://github.com/bitwarden/browser
synced 2025-12-20 10:13:31 +00:00
[CL-946] Migrate ToggleGroup to OnPush (#17718)
Migrates the ToggleGroup and Toggle components to use OnPush.
This commit is contained in:
@@ -1,113 +1,109 @@
|
||||
import { NgClass } from "@angular/common";
|
||||
import {
|
||||
AfterContentChecked,
|
||||
AfterViewInit,
|
||||
afterNextRender,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
contentChild,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
signal,
|
||||
inject,
|
||||
input,
|
||||
signal,
|
||||
viewChild,
|
||||
} from "@angular/core";
|
||||
|
||||
import { BadgeComponent } from "../badge";
|
||||
|
||||
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],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
tabindex: "-1",
|
||||
"[class]": "hostClasses",
|
||||
},
|
||||
})
|
||||
export class ToggleComponent<TValue> implements AfterContentChecked, AfterViewInit {
|
||||
id = nextId++;
|
||||
export class ToggleComponent<TValue> {
|
||||
protected readonly id = "bit-toggle-" + nextId++;
|
||||
|
||||
private readonly groupComponent = inject(ToggleGroupComponent<TValue>);
|
||||
|
||||
readonly value = input.required<TValue>();
|
||||
readonly labelContent = viewChild<ElementRef<HTMLSpanElement>>("labelContent");
|
||||
readonly bitBadgeContainer = viewChild<ElementRef<HTMLSpanElement>>("bitBadgeContainer");
|
||||
protected readonly labelContent = viewChild<ElementRef<HTMLSpanElement>>("labelContent");
|
||||
protected readonly badgeElement = contentChild(BadgeComponent);
|
||||
protected readonly hasBadge = computed(() => !!this.badgeElement());
|
||||
|
||||
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;
|
||||
constructor() {
|
||||
// Set label title after view is initialized
|
||||
afterNextRender(() => {
|
||||
const labelText = this.labelContent()?.nativeElement.innerText;
|
||||
if (labelText) {
|
||||
this.labelTitle.set(labelText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get selected() {
|
||||
return this.groupComponent.selected() === this.value();
|
||||
}
|
||||
protected readonly name = this.groupComponent.name;
|
||||
readonly selected = computed(() => 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() {
|
||||
protected handleInputChange() {
|
||||
this.groupComponent.onInputInteraction(this.value());
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
this.bitBadgeContainerHasChidlren.set(
|
||||
(this.bitBadgeContainer()?.nativeElement.childElementCount ?? 0) > 0,
|
||||
);
|
||||
}
|
||||
protected readonly hostClasses = ["tw-group/toggle", "tw-flex", "tw-min-w-16"];
|
||||
|
||||
ngAfterViewInit() {
|
||||
const labelText = this.labelContent()?.nativeElement.innerText;
|
||||
if (labelText) {
|
||||
this.labelTitle.set(labelText);
|
||||
}
|
||||
}
|
||||
protected readonly inputClasses = [
|
||||
"tw-peer/toggle-input",
|
||||
"tw-appearance-none",
|
||||
"tw-outline-none",
|
||||
];
|
||||
|
||||
protected readonly labelClasses = [
|
||||
"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",
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user