1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 00:03:56 +00:00

[CL-707] Migrate CL codebase to signals (#15340)

This commit is contained in:
Vicki League
2025-07-16 08:39:37 -04:00
committed by GitHub
parent 97ec9a6339
commit 6811ea4c0b
124 changed files with 944 additions and 809 deletions

View File

@@ -3,8 +3,9 @@ import {
Component,
EventEmitter,
HostBinding,
Input,
Output,
input,
model,
} from "@angular/core";
let nextId = 0;
@@ -17,18 +18,18 @@ export class ToggleGroupComponent<TValue = unknown> {
private id = nextId++;
name = `bit-toggle-group-${this.id}`;
@Input({ transform: booleanAttribute }) fullWidth?: boolean;
@Input() selected?: TValue;
readonly fullWidth = input<boolean, unknown>(undefined, { transform: booleanAttribute });
readonly selected = model<TValue>();
@Output() selectedChange = new EventEmitter<TValue>();
@HostBinding("attr.role") role = "radiogroup";
@HostBinding("class")
get classList() {
return ["tw-flex"].concat(this.fullWidth ? ["tw-w-full", "[&>*]:tw-flex-1"] : []);
return ["tw-flex"].concat(this.fullWidth() ? ["tw-w-full", "[&>*]:tw-flex-1"] : []);
}
onInputInteraction(value: TValue) {
this.selected = value;
this.selected.set(value);
this.selectedChange.emit(value);
}
}

View File

@@ -1,71 +1,60 @@
import { Component } from "@angular/core";
import { Component, DebugElement } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { ToggleGroupComponent } from "./toggle-group.component";
import { ToggleGroupModule } from "./toggle-group.module";
describe("Button", () => {
let mockGroupComponent: MockedButtonGroupComponent;
let fixture: ComponentFixture<TestApp>;
let testAppComponent: TestApp;
let radioButton: HTMLInputElement;
describe("Toggle", () => {
let fixture: ComponentFixture<TestComponent>;
let toggleGroup: ToggleGroupComponent;
let toggleButtons: DebugElement[];
beforeEach(async () => {
mockGroupComponent = new MockedButtonGroupComponent();
TestBed.configureTestingModule({
imports: [TestApp],
providers: [{ provide: ToggleGroupComponent, useValue: mockGroupComponent }],
imports: [TestComponent],
});
await TestBed.compileComponents();
fixture = TestBed.createComponent(TestApp);
testAppComponent = fixture.debugElement.componentInstance;
radioButton = fixture.debugElement.query(By.css("input[type=radio]")).nativeElement;
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
toggleGroup = fixture.debugElement.query(By.directive(ToggleGroupComponent)).componentInstance;
toggleButtons = fixture.debugElement.queryAll(By.css("input[type=radio]"));
});
it("should emit value when clicking on radio button", () => {
testAppComponent.value = "value";
const spyFn = jest.spyOn(toggleGroup, "onInputInteraction");
toggleButtons[1].triggerEventHandler("change");
fixture.detectChanges();
radioButton.click();
fixture.detectChanges();
expect(mockGroupComponent.onInputInteraction).toHaveBeenCalledWith("value");
expect(spyFn).toHaveBeenCalledWith(1);
});
it("should check radio button when selected matches value", () => {
testAppComponent.value = "value";
it("should select toggle button only when selected matches value", () => {
fixture.detectChanges();
mockGroupComponent.selected = "value";
expect(toggleButtons[0].nativeElement.checked).toBe(true);
expect(toggleButtons[1].nativeElement.checked).toBe(false);
toggleButtons[1].triggerEventHandler("change");
fixture.detectChanges();
expect(radioButton.checked).toBe(true);
});
it("should not check radio button when selected does not match value", () => {
testAppComponent.value = "value";
fixture.detectChanges();
mockGroupComponent.selected = "nonMatchingValue";
fixture.detectChanges();
expect(radioButton.checked).toBe(false);
expect(toggleButtons[0].nativeElement.checked).toBe(false);
expect(toggleButtons[1].nativeElement.checked).toBe(true);
});
});
class MockedButtonGroupComponent implements Partial<ToggleGroupComponent> {
onInputInteraction = jest.fn();
selected: unknown = null;
}
@Component({
selector: "test-app",
template: ` <bit-toggle [value]="value">Element</bit-toggle>`,
selector: "test-component",
template: `
<bit-toggle-group [(selected)]="selected">
<bit-toggle [value]="0">Zero</bit-toggle>
<bit-toggle [value]="1">One</bit-toggle>
</bit-toggle-group>
`,
imports: [ToggleGroupModule],
})
class TestApp {
value?: string;
class TestComponent {
selected = 0;
}

View File

@@ -7,9 +7,9 @@ import {
Component,
ElementRef,
HostBinding,
Input,
signal,
ViewChild,
input,
} from "@angular/core";
import { ToggleGroupComponent } from "./toggle-group.component";
@@ -24,7 +24,7 @@ let nextId = 0;
export class ToggleComponent<TValue> implements AfterContentChecked, AfterViewInit {
id = nextId++;
@Input() value?: TValue;
readonly value = input<TValue>();
@ViewChild("labelContent") labelContent: ElementRef<HTMLSpanElement>;
@ViewChild("bitBadgeContainer") bitBadgeContainer: ElementRef<HTMLSpanElement>;
@@ -41,7 +41,7 @@ export class ToggleComponent<TValue> implements AfterContentChecked, AfterViewIn
}
get selected() {
return this.groupComponent.selected === this.value;
return this.groupComponent.selected() === this.value();
}
get inputClasses() {
@@ -95,7 +95,7 @@ export class ToggleComponent<TValue> implements AfterContentChecked, AfterViewIn
}
onInputInteraction() {
this.groupComponent.onInputInteraction(this.value);
this.groupComponent.onInputInteraction(this.value());
}
ngAfterContentChecked() {