mirror of
https://github.com/bitwarden/browser
synced 2026-02-08 04:33:38 +00:00
continue migrating select module
This commit is contained in:
@@ -118,12 +118,12 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
|
||||
/** The label to show in the chip button */
|
||||
protected get label(): string {
|
||||
return this.selectedOption?.label || this.placeholderText();
|
||||
return this.selectedOption?.label() || this.placeholderText();
|
||||
}
|
||||
|
||||
/** The icon to show in the chip button */
|
||||
protected get icon(): string {
|
||||
return this.selectedOption?.icon || this.placeholderIcon();
|
||||
return this.selectedOption?.icon() || this.placeholderIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +172,7 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
*/
|
||||
private findOption(tree: ChipSelectOption<T>, value: T): ChipSelectOption<T> | null {
|
||||
let result = null;
|
||||
if (tree.value !== null && compareValues(tree.value, value)) {
|
||||
if (tree.value !== null && compareValues(tree.value(), value)) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
return;
|
||||
}
|
||||
|
||||
this.notifyOnChange(option?.value ?? null);
|
||||
this.notifyOnChange(option?.value() ?? null);
|
||||
}
|
||||
|
||||
/** Implemented as part of NG_VALUE_ACCESSOR */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, Input, booleanAttribute } from "@angular/core";
|
||||
import { Component, booleanAttribute, input } from "@angular/core";
|
||||
|
||||
import { Option } from "./option";
|
||||
|
||||
@@ -9,27 +9,11 @@ import { Option } from "./option";
|
||||
template: `<ng-template><ng-content></ng-content></ng-template>`,
|
||||
})
|
||||
export class OptionComponent<T = unknown> implements Option<T> {
|
||||
// TODO: Skipped for migration because:
|
||||
// This input overrides a field from a superclass, while the superclass field
|
||||
// is not migrated.
|
||||
@Input()
|
||||
icon?: string;
|
||||
icon = input<string>();
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// This input overrides a field from a superclass, while the superclass field
|
||||
// is not migrated.
|
||||
@Input({ required: true })
|
||||
value: T;
|
||||
value = input.required<T>();
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// This input overrides a field from a superclass, while the superclass field
|
||||
// is not migrated.
|
||||
@Input({ required: true })
|
||||
label: string;
|
||||
label = input.required<string>();
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// This input overrides a field from a superclass, while the superclass field
|
||||
// is not migrated.
|
||||
@Input({ transform: booleanAttribute })
|
||||
disabled: boolean;
|
||||
disabled = input(undefined, { transform: booleanAttribute });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Signal } from "@angular/core";
|
||||
|
||||
export interface Option<T> {
|
||||
icon?: string;
|
||||
value: T | null;
|
||||
label?: string;
|
||||
disabled?: boolean;
|
||||
icon?: Signal<string>;
|
||||
value: Signal<T | null>;
|
||||
label?: Signal<string>;
|
||||
disabled?: Signal<boolean>;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<ng-select
|
||||
[(ngModel)]="selectedOption"
|
||||
[ngModel]="selectedOption()"
|
||||
(ngModelChange)="onChange($event)"
|
||||
[disabled]="disabled"
|
||||
[placeholder]="placeholder()"
|
||||
[items]="items"
|
||||
[items]="items()"
|
||||
(blur)="onBlur()"
|
||||
[labelForId]="labelForId"
|
||||
[clearable]="false"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, signal } from "@angular/core";
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms";
|
||||
import { By } from "@angular/platform-browser";
|
||||
@@ -37,15 +37,15 @@ describe("Select Component", () => {
|
||||
|
||||
describe("initial state", () => {
|
||||
it("selected option should update when items input changes", () => {
|
||||
expect(select.selectedOption?.value).toBeUndefined();
|
||||
expect(select.selectedOption()?.value).toBeUndefined();
|
||||
|
||||
select.items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Pear", value: "pear" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
];
|
||||
select.items.set([
|
||||
{ label: signal("Apple"), value: signal("apple") },
|
||||
{ label: signal("Pear"), value: signal("pear") },
|
||||
{ label: signal("Banana"), value: signal("banana") },
|
||||
]);
|
||||
|
||||
expect(select.selectedOption?.value).toBe("apple");
|
||||
expect(select.selectedOption()?.value).toBe("apple");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,10 @@ import {
|
||||
Output,
|
||||
EventEmitter,
|
||||
input,
|
||||
Signal,
|
||||
computed,
|
||||
model,
|
||||
signal,
|
||||
} from "@angular/core";
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
@@ -37,31 +41,23 @@ let nextId = 0;
|
||||
templateUrl: "select.component.html",
|
||||
providers: [{ provide: BitFormFieldControl, useExisting: SelectComponent }],
|
||||
imports: [NgSelectModule, ReactiveFormsModule, FormsModule],
|
||||
host: {
|
||||
"[id]": "this.id()",
|
||||
},
|
||||
})
|
||||
export class SelectComponent<T> implements BitFormFieldControl, ControlValueAccessor {
|
||||
@ViewChild(NgSelectComponent) select: NgSelectComponent;
|
||||
|
||||
private _items: Option<T>[] = [];
|
||||
/** Optional: Options can be provided using an array input or using `bit-option` */
|
||||
// TODO: Skipped for migration because:
|
||||
// Accessor inputs cannot be migrated as they are too complex.
|
||||
@Input()
|
||||
get items(): Option<T>[] {
|
||||
return this._items;
|
||||
}
|
||||
set items(next: Option<T>[]) {
|
||||
this._items = next;
|
||||
this._selectedOption = this.findSelectedOption(next, this.selectedValue);
|
||||
}
|
||||
items = model<Option<T>[]>();
|
||||
|
||||
readonly placeholder = input(this.i18nService.t("selectPlaceholder"));
|
||||
@Output() closed = new EventEmitter();
|
||||
|
||||
protected selectedValue: T;
|
||||
protected _selectedOption: Option<T>;
|
||||
get selectedOption() {
|
||||
return this._selectedOption;
|
||||
}
|
||||
protected selectedValue = signal<T>(undefined);
|
||||
selectedOption: Signal<Option<T>> = computed(() =>
|
||||
this.findSelectedOption(this.items(), this.selectedValue()),
|
||||
);
|
||||
protected searchInputId = `bit-select-search-input-${nextId++}`;
|
||||
|
||||
private notifyOnChange?: (value: T) => void;
|
||||
@@ -81,7 +77,7 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
|
||||
if (value == null || value.length == 0) {
|
||||
return;
|
||||
}
|
||||
this.items = value.toArray();
|
||||
this.items.set(value.toArray());
|
||||
}
|
||||
|
||||
@HostBinding("class") protected classes = ["tw-block", "tw-w-full", "tw-h-full"];
|
||||
@@ -91,7 +87,7 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
|
||||
get disabledAttr() {
|
||||
return this.disabled || null;
|
||||
}
|
||||
// TODO: Skipped for migration because:
|
||||
// TODO: Skipped for signal migration because:
|
||||
// Accessor inputs cannot be migrated as they are too complex.
|
||||
@Input()
|
||||
get disabled() {
|
||||
@@ -104,8 +100,7 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
|
||||
|
||||
/**Implemented as part of NG_VALUE_ACCESSOR */
|
||||
writeValue(obj: T): void {
|
||||
this.selectedValue = obj;
|
||||
this._selectedOption = this.findSelectedOption(this.items, this.selectedValue);
|
||||
this.selectedValue.set(obj);
|
||||
}
|
||||
|
||||
/**Implemented as part of NG_VALUE_ACCESSOR */
|
||||
@@ -125,11 +120,13 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
|
||||
|
||||
/**Implemented as part of NG_VALUE_ACCESSOR */
|
||||
protected onChange(option: Option<T> | null) {
|
||||
this.selectedValue.set(option?.value());
|
||||
|
||||
if (!this.notifyOnChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.notifyOnChange(option?.value);
|
||||
this.notifyOnChange(option?.value());
|
||||
}
|
||||
|
||||
/**Implemented as part of NG_VALUE_ACCESSOR */
|
||||
@@ -158,10 +155,7 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
|
||||
}
|
||||
|
||||
/**Implemented as part of BitFormFieldControl */
|
||||
// TODO: Skipped for migration because:
|
||||
// This input is used in combination with `@HostBinding` and migrating would
|
||||
// break.
|
||||
@HostBinding() @Input() id = `bit-multi-select-${nextId++}`;
|
||||
id = input(`bit-multi-select-${nextId++}`);
|
||||
|
||||
/**Implemented as part of BitFormFieldControl */
|
||||
// TODO: Skipped for migration because:
|
||||
@@ -188,7 +182,7 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
|
||||
}
|
||||
|
||||
private findSelectedOption(items: Option<T>[], value: T): Option<T> | undefined {
|
||||
return items.find((item) => item.value === value);
|
||||
return items.find((item) => item.value() === value);
|
||||
}
|
||||
|
||||
/**Emits the closed event. */
|
||||
|
||||
Reference in New Issue
Block a user