-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(radio-group): migrate to signals (#500)
- Loading branch information
1 parent
be50818
commit b24f65c
Showing
7 changed files
with
226 additions
and
547 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
libs/ui/radio-group/brain/src/lib/brn-radio-group.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* eslint-disable @typescript-eslint/no-empty-function */ | ||
import { BooleanInput } from '@angular/cdk/coercion'; | ||
import { | ||
booleanAttribute, | ||
Component, | ||
computed, | ||
contentChildren, | ||
forwardRef, | ||
input, | ||
model, | ||
output, | ||
signal, | ||
} from '@angular/core'; | ||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | ||
import { ChangeFn, TouchFn } from '@spartan-ng/ui-forms-brain'; | ||
import { provideBrnRadioGroupToken } from './brn-radio-group.token'; | ||
import { BrnRadioChange, BrnRadioComponent } from './brn-radio.component'; | ||
|
||
export const BRN_RADIO_GROUP_CONTROL_VALUE_ACCESSOR = { | ||
provide: NG_VALUE_ACCESSOR, | ||
useExisting: forwardRef(() => BrnRadioGroupComponent), | ||
multi: true, | ||
}; | ||
|
||
@Component({ | ||
selector: 'brn-radio-group', | ||
standalone: true, | ||
providers: [BRN_RADIO_GROUP_CONTROL_VALUE_ACCESSOR, provideBrnRadioGroupToken(BrnRadioGroupComponent)], | ||
host: { | ||
role: 'radiogroup', | ||
'(focusout)': 'onTouched()', | ||
}, | ||
template: '<ng-content />', | ||
}) | ||
export class BrnRadioGroupComponent<T = unknown> implements ControlValueAccessor { | ||
private static _nextUniqueId = 0; | ||
|
||
protected onChange: ChangeFn<T> = () => {}; | ||
|
||
protected onTouched: TouchFn = () => {}; | ||
|
||
public readonly name = input(`brn-radio-group-${BrnRadioGroupComponent._nextUniqueId++}`); | ||
|
||
/** | ||
* The value of the selected radio button. | ||
*/ | ||
public readonly value = model<T>(); | ||
|
||
/** | ||
* Whether the radio group is disabled. | ||
*/ | ||
public disabled = input<boolean, BooleanInput>(false, { | ||
transform: booleanAttribute, | ||
}); | ||
|
||
/** | ||
* Whether the radio group should be required. | ||
*/ | ||
public readonly required = input<boolean, BooleanInput>(false, { | ||
transform: booleanAttribute, | ||
}); | ||
|
||
/** | ||
* The direction of the radio group. | ||
*/ | ||
public readonly direction = input<'ltr' | 'rtl' | null>('ltr'); | ||
|
||
/** | ||
* Event emitted when the group value changes. | ||
*/ | ||
public readonly change = output<BrnRadioChange<T>>(); | ||
|
||
/** | ||
* The internal disabled state of the radio group. This could be switched to a linkedSignal when we can drop v18 support. | ||
* @internal | ||
*/ | ||
public readonly disabledState = computed(() => signal(this.disabled())); | ||
|
||
/** | ||
* Access the radio buttons within the group. | ||
* @internal | ||
*/ | ||
public readonly radioButtons = contentChildren(BrnRadioComponent, { descendants: true }); | ||
|
||
writeValue(value: T): void { | ||
this.value.set(value); | ||
} | ||
|
||
registerOnChange(fn: ChangeFn<T>): void { | ||
this.onChange = fn; | ||
} | ||
|
||
registerOnTouched(fn: TouchFn): void { | ||
this.onTouched = fn; | ||
} | ||
|
||
setDisabledState(isDisabled: boolean): void { | ||
this.disabledState().set(isDisabled); | ||
} | ||
|
||
/** | ||
* Select a radio button. | ||
* @internal | ||
*/ | ||
select(radioButton: BrnRadioComponent<T>, value: T): void { | ||
if (this.value() === value) { | ||
return; | ||
} | ||
|
||
this.value.set(value); | ||
this.onChange(value); | ||
this.change.emit(new BrnRadioChange<T>(radioButton, value)); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
libs/ui/radio-group/brain/src/lib/brn-radio-group.token.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { ExistingProvider, inject, InjectionToken, Type } from '@angular/core'; | ||
import type { BrnRadioGroupComponent } from './brn-radio-group.component'; | ||
|
||
const BrnRadioGroupToken = new InjectionToken<BrnRadioGroupComponent<unknown>>('BrnRadioGroupToken'); | ||
|
||
export function provideBrnRadioGroupToken<T>(component: Type<BrnRadioGroupComponent<T>>): ExistingProvider { | ||
return { provide: BrnRadioGroupToken, useExisting: component }; | ||
} | ||
|
||
export function injectBrnRadioGroup<T = unknown>(): BrnRadioGroupComponent<T> { | ||
return inject(BrnRadioGroupToken) as BrnRadioGroupComponent<T>; | ||
} |
Oops, something went wrong.