Skip to content

Commit

Permalink
feat(radio-group): migrate to signals (#500)
Browse files Browse the repository at this point in the history
  • Loading branch information
ashley-hunter authored Nov 29, 2024
1 parent be50818 commit b24f65c
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 547 deletions.
3 changes: 2 additions & 1 deletion libs/ui/radio-group/brain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"peerDependencies": {
"@angular/core": ">=18.0.0",
"@angular/cdk": ">=18.0.0",
"@angular/forms": ">=18.0.0"
"@angular/forms": ">=18.0.0",
"@spartan-ng/ui-forms-brain": "0.0.1-alpha.356"
},
"dependencies": {},
"sideEffects": false,
Expand Down
4 changes: 3 additions & 1 deletion libs/ui/radio-group/brain/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { NgModule } from '@angular/core';

import { BrnRadioComponent, BrnRadioGroupComponent } from './lib/brn-radio.component';
import { BrnRadioGroupComponent } from './lib/brn-radio-group.component';
import { BrnRadioComponent } from './lib/brn-radio.component';

export * from './lib/brn-radio-group.component';
export * from './lib/brn-radio.component';

export const BrnRadioGroupImports = [BrnRadioGroupComponent, BrnRadioComponent] as const;
Expand Down
114 changes: 114 additions & 0 deletions libs/ui/radio-group/brain/src/lib/brn-radio-group.component.ts
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 libs/ui/radio-group/brain/src/lib/brn-radio-group.token.ts
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>;
}
Loading

0 comments on commit b24f65c

Please sign in to comment.