diff --git a/apps/design-land/src/app/radio/radio.component.html b/apps/design-land/src/app/radio/radio.component.html index b74bda0e4b..33b6ca9129 100644 --- a/apps/design-land/src/app/radio/radio.component.html +++ b/apps/design-land/src/app/radio/radio.component.html @@ -1,2 +1,10 @@

Daff Radio

+ + + + + + + + \ No newline at end of file diff --git a/libs/design-examples/radio/src/basic-radio/basic-radio.component.html b/libs/design-examples/radio/src/basic-radio/basic-radio.component.html index 15e38f6942..19525bf459 100644 --- a/libs/design-examples/radio/src/basic-radio/basic-radio.component.html +++ b/libs/design-examples/radio/src/basic-radio/basic-radio.component.html @@ -1,9 +1,8 @@ -

Basic Radio

- - Terran - Protoss - Zerg + + Card Type + Visa + MasterCard + American Express -
- The best race to play as is: {{this.radioGroup.get('race').value}} -
\ No newline at end of file + +
Selected value: {{ value }}
\ No newline at end of file diff --git a/libs/design-examples/radio/src/basic-radio/basic-radio.component.ts b/libs/design-examples/radio/src/basic-radio/basic-radio.component.ts index 34b5b94f68..1c99d1c4b2 100644 --- a/libs/design-examples/radio/src/basic-radio/basic-radio.component.ts +++ b/libs/design-examples/radio/src/basic-radio/basic-radio.component.ts @@ -2,11 +2,7 @@ import { ChangeDetectionStrategy, Component, } from '@angular/core'; -import { - UntypedFormGroup, - UntypedFormControl, - ReactiveFormsModule, -} from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; @@ -20,9 +16,9 @@ import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; ], }) export class BasicRadioExampleComponent { - radioGroup = new UntypedFormGroup({ - race: new UntypedFormControl('Zerg'), - }); + value: any; - constructor() {} + update(val: any) { + this.value = val; + } } diff --git a/libs/design-examples/radio/src/examples.ts b/libs/design-examples/radio/src/examples.ts index 1beed50165..688678e525 100644 --- a/libs/design-examples/radio/src/examples.ts +++ b/libs/design-examples/radio/src/examples.ts @@ -1,5 +1,13 @@ import { BasicRadioExampleComponent } from './basic-radio/basic-radio.component'; +import { RadioOrientationsExampleComponent } from './radio-orientations/radio-orientations.component'; +import { RadioWithControlExampleComponent } from './radio-with-control/radio-with-control.component'; +import { RadioWithErrorExampleComponent } from './radio-with-error/radio-with-error.component'; +import { RadioWithHintExampleComponent } from './radio-with-hint/radio-with-hint.component'; export const RADIO_EXAMPLES = [ BasicRadioExampleComponent, + RadioWithControlExampleComponent, + RadioWithHintExampleComponent, + RadioWithErrorExampleComponent, + RadioOrientationsExampleComponent, ]; diff --git a/libs/design-examples/radio/src/radio-orientations/radio-orientations.component.html b/libs/design-examples/radio/src/radio-orientations/radio-orientations.component.html new file mode 100644 index 0000000000..33876c4605 --- /dev/null +++ b/libs/design-examples/radio/src/radio-orientations/radio-orientations.component.html @@ -0,0 +1,12 @@ + + Gift Wrapping + None + Standard + Premium + + + \ No newline at end of file diff --git a/libs/design-examples/radio/src/radio-orientations/radio-orientations.component.ts b/libs/design-examples/radio/src/radio-orientations/radio-orientations.component.ts new file mode 100644 index 0000000000..3a3a137814 --- /dev/null +++ b/libs/design-examples/radio/src/radio-orientations/radio-orientations.component.ts @@ -0,0 +1,31 @@ +import { + ChangeDetectionStrategy, + Component, +} from '@angular/core'; +import { + UntypedFormControl, + ReactiveFormsModule, +} from '@angular/forms'; + +import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; + +@Component({ + selector: 'radio-orientations-example', + templateUrl: './radio-orientations.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + DAFF_RADIO_COMPONENTS, + ReactiveFormsModule, + ], +}) +export class RadioOrientationsExampleComponent { + giftWrap = new UntypedFormControl('none'); + + orientationControl: UntypedFormControl = new UntypedFormControl(''); + + options = [ + { value: '', label: 'Default' }, + { value: 'vertical', label: 'Vertical' }, + { value: 'horizontal', label: 'Horizontal' }, + ]; +} diff --git a/libs/design-examples/radio/src/radio-with-control/radio-with-control.component.html b/libs/design-examples/radio/src/radio-with-control/radio-with-control.component.html new file mode 100644 index 0000000000..7af3c0eac9 --- /dev/null +++ b/libs/design-examples/radio/src/radio-with-control/radio-with-control.component.html @@ -0,0 +1,6 @@ + + Card Type + Visa + MasterCard + American Express + diff --git a/libs/design-examples/radio/src/radio-with-control/radio-with-control.component.ts b/libs/design-examples/radio/src/radio-with-control/radio-with-control.component.ts new file mode 100644 index 0000000000..0e9415f997 --- /dev/null +++ b/libs/design-examples/radio/src/radio-with-control/radio-with-control.component.ts @@ -0,0 +1,23 @@ +import { + ChangeDetectionStrategy, + Component, +} from '@angular/core'; +import { + UntypedFormControl, + ReactiveFormsModule, +} from '@angular/forms'; + +import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; + +@Component({ + selector: 'radio-with-control-example', + templateUrl: './radio-with-control.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + DAFF_RADIO_COMPONENTS, + ReactiveFormsModule, + ], +}) +export class RadioWithControlExampleComponent { + ccType = new UntypedFormControl('visa'); +} diff --git a/libs/design-examples/radio/src/radio-with-error/radio-with-error.component.html b/libs/design-examples/radio/src/radio-with-error/radio-with-error.component.html new file mode 100644 index 0000000000..689af1de90 --- /dev/null +++ b/libs/design-examples/radio/src/radio-with-error/radio-with-error.component.html @@ -0,0 +1,8 @@ + + Shipping Method + Standard (5-7 business days) + Express (2-3 business days) + Overnight + Delivery times may vary during peak seasons + Please select a shipping method to continue + diff --git a/libs/design-examples/radio/src/radio-with-error/radio-with-error.component.ts b/libs/design-examples/radio/src/radio-with-error/radio-with-error.component.ts new file mode 100644 index 0000000000..752cd15ab6 --- /dev/null +++ b/libs/design-examples/radio/src/radio-with-error/radio-with-error.component.ts @@ -0,0 +1,23 @@ +import { + ChangeDetectionStrategy, + Component, +} from '@angular/core'; +import { + UntypedFormControl, + ReactiveFormsModule, +} from '@angular/forms'; + +import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; + +@Component({ + selector: 'radio-with-error-example', + templateUrl: './radio-with-error.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + DAFF_RADIO_COMPONENTS, + ReactiveFormsModule, + ], +}) +export class RadioWithErrorExampleComponent { + shippingMethod = new UntypedFormControl('standard'); +} diff --git a/libs/design-examples/radio/src/radio-with-hint/radio-with-hint.component.html b/libs/design-examples/radio/src/radio-with-hint/radio-with-hint.component.html new file mode 100644 index 0000000000..37decd211d --- /dev/null +++ b/libs/design-examples/radio/src/radio-with-hint/radio-with-hint.component.html @@ -0,0 +1,7 @@ + + Shipping Options + Standard (5-7 business days) + Express (2-3 business days) + Overnight (next business day) + Delivery times may vary during peak seasons + diff --git a/libs/design-examples/radio/src/radio-with-hint/radio-with-hint.component.ts b/libs/design-examples/radio/src/radio-with-hint/radio-with-hint.component.ts new file mode 100644 index 0000000000..3f06308b59 --- /dev/null +++ b/libs/design-examples/radio/src/radio-with-hint/radio-with-hint.component.ts @@ -0,0 +1,23 @@ +import { + ChangeDetectionStrategy, + Component, +} from '@angular/core'; +import { + UntypedFormControl, + ReactiveFormsModule, +} from '@angular/forms'; + +import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; + +@Component({ + selector: 'radio-with-hint-example', + templateUrl: './radio-with-hint.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + DAFF_RADIO_COMPONENTS, + ReactiveFormsModule, + ], +}) +export class RadioWithHintExampleComponent { + shippingOptions = new UntypedFormControl('standard'); +} diff --git a/libs/design/radio/README.md b/libs/design/radio/README.md index 3a2df33ac0..c3ad0179d0 100644 --- a/libs/design/radio/README.md +++ b/libs/design/radio/README.md @@ -1,8 +1,8 @@ # Radio -Radio is used to select a single value from a selection of values. +Radio allows users to select a single value from a group of options. ## Overview -It can be hooked into Angular's `FormControl` to accomodate custom functionality. The `DaffRadioSetComponent` serves as a wrapper around a logical group of radios to provide styling. +Use radio when you need users to pick exactly one option from a visible list of choices. Radio buttons are ideal when users need to see and compare all available options at once. It **cannot** be used by itself and must be contained within a ``. @@ -46,7 +46,44 @@ import { CustomComponent } from './custom.component'; export class CustomComponentModule { } ``` -> Deprecation notice: This method is deprecated. It's recommended to update all custom components to standalone. +> **Warning** +> +> This method is deprecated. It's recommended to update all custom components to standalone. + +## Anatomy +Radio must be used inside `` to enable proper state management and grouping. The radio set component manages the selected value and handles the shared `name` attribute for the group. + +### Basic structure +Use `` to group related radio buttons and `` for individual options: + +```html + + Card Type + Visa + MasterCard + American Express + +``` + +## Reactive forms +Radio can be used with Angular's reactive forms by binding a `FormControl` to the radio set: + + ## Accessibility -Radio uses native `` HTML elements to ensure an accesible experience by default. It supports inputs to customize the experience for accessibility by allowing native input for `aria-label` and `aria-labelledby`. \ No newline at end of file +Radio follows the [Radio Group WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/). It uses native `` elements to ensure an accessible experience by default. + +### Daffodil provides +- Native radio button semantics with proper grouping +- `aria-labelledby` on the `radiogroup` associated with the `` + +### Developer responsibilities +- Always provide a visible label for the radio set using `` +- Ensure each radio option has descriptive label text + +### Keyboard interactions +| Key | Action | +| --- | ------ | +| `Tab` | Move focus to the radio group | +| `Up Arrow` / `Left Arrow` | Move focus to and select the previous option | +| `Down Arrow` / `Right Arrow` | Move focus to and select the next option | diff --git a/libs/design/radio/src/cva/radio-cva.directive.spec.ts b/libs/design/radio/src/cva/radio-cva.directive.spec.ts deleted file mode 100644 index d63d2269d2..0000000000 --- a/libs/design/radio/src/cva/radio-cva.directive.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Component } from '@angular/core'; -import { - ComponentFixture, - waitForAsync, - TestBed, -} from '@angular/core/testing'; -import { - ReactiveFormsModule, - UntypedFormControl, -} from '@angular/forms'; -import { By } from '@angular/platform-browser'; - -import { DaffRadioControlValueAccessorDirective } from './radio-cva.directive'; -import { DaffRadioComponent } from '../radio/radio.component'; - -@Component({ - template: ` - - `, - imports: [ - DaffRadioComponent, - DaffRadioControlValueAccessorDirective, - ReactiveFormsModule, - ], -}) -class WrapperComponent { - radio = new UntypedFormControl(); -} - -describe('@daffodil/design/radio | DaffRadioControlValueAccessorDirective | Defaults', () => { - let fixture: ComponentFixture; - let wrapper: WrapperComponent; - let component: DaffRadioComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ - WrapperComponent, - ], - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(WrapperComponent); - wrapper = fixture.componentInstance; - component = fixture.debugElement.query(By.css('daff-radio')).componentInstance; - fixture.detectChanges(); - }); - - it('has the writeValue function for formControls', async () => { - expect(component.checked).toEqual(false); - wrapper.radio.setValue('testValue'); - expect(component.checked).toEqual(true); - }); -}); diff --git a/libs/design/radio/src/cva/radio-cva.directive.ts b/libs/design/radio/src/cva/radio-cva.directive.ts deleted file mode 100644 index 8f51f87998..0000000000 --- a/libs/design/radio/src/cva/radio-cva.directive.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { - Directive, - Input, - OnInit, - Self, - Optional, -} from '@angular/core'; -import { - NgControl, - ControlValueAccessor, -} from '@angular/forms'; - -import { DaffRadioComponent } from '../radio/radio.component'; -import { DaffRadioRegistry } from '../registry/radio-registry'; - -/** - * ControlValueAccessor functionality for the DaffRadio - */ -@Directive({ - // eslint-disable-next-line @angular-eslint/directive-selector - selector: 'daff-radio[ngModel], daff-radio[formControl], daff-radio[formControlName]', -}) -export class DaffRadioControlValueAccessorDirective implements OnInit, ControlValueAccessor { - _onChange: () => void; - _onTouched: () => void; - - /** - * The value of the ControlValueAccessor - */ - @Input() value: any; - - /** - * The name of the ControlValueAccessor - */ - @Input() name: string; - - constructor( - @Optional() @Self() public _control: NgControl, - private _registry: DaffRadioRegistry, - private _radio: DaffRadioComponent, - ) { - if (this._control != null) { - this._control.valueAccessor = this; - } - } - - /** - * @docs-private - */ - ngOnInit(): void { - if (this._control) { - this.writeValue(this._control.value); - this._registry.add(this._control, this); - } - - this._radio.selectionChange.subscribe( - value => value ? this._onChange() : null, - ); - } - /** - * - * writeValue function from the CVA interface - */ - writeValue(value: any): void { - // the this._onChange null check here is necessary because of an ongoing bug in angular forms - // where writeValue can be called before the component initializes: https://github.com/angular/angular/issues/29218 - if (this.value === value && this._onChange) { - this._onChange(); - this.fireSelect(); - } - } - - /** - * registerOnChange implemented from the CVA interface - */ - registerOnChange(fn: any): void { - this._onChange = () => { - fn(this.value); - this._registry.select(this); - }; - } - - /** - * registerOnTouch implemented from the CVA interface - */ - registerOnTouched(fn: any): void { - this._onTouched = fn; - } - - /** - * sets the disabled state. - */ - setDisabledState?(isDisabled: boolean): void { - this._radio.disabled = isDisabled; - } - - /** - calls select function for the radio - */ - fireSelect() { - this._radio.select(); - } - - /** - calls deselect function for the radio - */ - fireDeselect() { - this._radio.deselect(); - } -} diff --git a/libs/design/radio/src/helpers/radio-set-orientation.ts b/libs/design/radio/src/helpers/radio-set-orientation.ts new file mode 100644 index 0000000000..c41aae6e97 --- /dev/null +++ b/libs/design/radio/src/helpers/radio-set-orientation.ts @@ -0,0 +1,18 @@ +/** + * The available orientations for a radio set. + * + * | Orientation | Description | + * | -- | -- | + * | `vertical` | Stacks radio set content from top to bottom. This is the default orientation. | + * | `horizontal` | Places radio set content side-by-side. On smaller screens, horizontal radio sets automatically switch to vertical for responsiveness. | + */ +export type DaffRadioSetOrientation = 'vertical' | 'horizontal'; + +/** + * Enum for representing the available radio set orientations. + * See {@link DaffRadioSetOrientation} for descriptions of each orientation. + */ +export enum DaffRadioSetOrientationEnum { + Vertical = 'vertical', + Horizontal = 'horizontal', +} diff --git a/libs/design/radio/src/public_api.ts b/libs/design/radio/src/public_api.ts index 3797463164..763da43e19 100644 --- a/libs/design/radio/src/public_api.ts +++ b/libs/design/radio/src/public_api.ts @@ -2,4 +2,3 @@ export { DaffRadioModule } from './radio.module'; export { DaffRadioComponent } from './radio/radio.component'; export { DaffRadioSetComponent } from './radio-set/radio-set.component'; export { DAFF_RADIO_COMPONENTS } from './radio'; -export { DaffRadioControlValueAccessorDirective } from './cva/radio-cva.directive'; diff --git a/libs/design/radio/src/radio-set/radio-set.component.html b/libs/design/radio/src/radio-set/radio-set.component.html index 95a0b70bdc..cd37336b21 100644 --- a/libs/design/radio/src/radio-set/radio-set.component.html +++ b/libs/design/radio/src/radio-set/radio-set.component.html @@ -1 +1,22 @@ - \ No newline at end of file +
+ +
+
+ +
+@if (hasHint() || hasErrorMessage()) { +
+ @if (hasHint()) { +
+ +
+ } + @if (hasErrorMessage()) { +
+ +
+ } +
+} \ No newline at end of file diff --git a/libs/design/radio/src/radio-set/radio-set.component.scss b/libs/design/radio/src/radio-set/radio-set.component.scss new file mode 100644 index 0000000000..5b4fbac428 --- /dev/null +++ b/libs/design/radio/src/radio-set/radio-set.component.scss @@ -0,0 +1,39 @@ +@use '../../../scss/typography' as t; + +:host { + $root: '.daff-radio-set'; + display: flex; + flex-direction: column; + gap: 0.75rem; + + #{$root}__label { + font-size: t.$font-size-base; + font-weight: 500; + } + + #{$root}__wrapper { + display: flex; + } + + &.horizontal { + #{$root}__wrapper { + flex-direction: row; + gap: 1rem; + } + } + + &.vertical { + #{$root}__wrapper { + flex-direction: column; + gap: 0.375rem; + } + } + + #{$root}__hint-and-error { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + gap: 0.25rem; + } +} diff --git a/libs/design/radio/src/radio-set/radio-set.component.spec.ts b/libs/design/radio/src/radio-set/radio-set.component.spec.ts index b25fc66d86..a992e843b3 100644 --- a/libs/design/radio/src/radio-set/radio-set.component.spec.ts +++ b/libs/design/radio/src/radio-set/radio-set.component.spec.ts @@ -8,22 +8,22 @@ import { TestBed, } from '@angular/core/testing'; import { - UntypedFormGroup, UntypedFormControl, ReactiveFormsModule, } from '@angular/forms'; import { By } from '@angular/platform-browser'; -import { DAFF_RADIO_COMPONENTS } from '@daffodil/design/radio'; - -import { DaffRadioSetComponent } from './radio-set.component'; +import { + DAFF_RADIO_COMPONENTS, + DaffRadioSetComponent, +} from '@daffodil/design/radio'; @Component({ template: ` - - Apple - Grape - Peach + + Apple + Grape + Peach `, imports: [ @@ -32,9 +32,7 @@ import { DaffRadioSetComponent } from './radio-set.component'; ], }) class WrapperComponent { - radioGroup = new UntypedFormGroup({ - fruit: new UntypedFormControl(), - }); + fruits = new UntypedFormControl(); } describe('@daffodil/design/radio | DaffRadioSetComponent | Defaults', () => { @@ -65,11 +63,10 @@ describe('@daffodil/design/radio | DaffRadioSetComponent | Defaults', () => { }); it('should take a name as an input', () => { - expect(component.name).toBe('fruit'); + expect(component.name()).toBe('fruit'); }); it('should have a role of radiogroup', () => { - const roleAttribute = de.nativeElement.getAttribute('role'); - expect(roleAttribute).toBe('radiogroup'); + expect(de.nativeElement.getAttribute('role')).toBe('radiogroup'); }); }); diff --git a/libs/design/radio/src/radio-set/radio-set.component.ts b/libs/design/radio/src/radio-set/radio-set.component.ts index 32325d8f25..49afcfd7b2 100644 --- a/libs/design/radio/src/radio-set/radio-set.component.ts +++ b/libs/design/radio/src/radio-set/radio-set.component.ts @@ -1,22 +1,196 @@ +/* eslint-disable @angular-eslint/no-input-rename */ import { - Component, - Input, ChangeDetectionStrategy, + Component, + ContentChild, + effect, + inject, + input, + output, + signal, } from '@angular/core'; +import { + ControlValueAccessor, + NgControl, +} from '@angular/forms'; + +import { + DaffErrorMessageComponent, + DaffHintComponent, +} from '@daffodil/design/form'; + +import { + DaffRadioSetOrientation, + DaffRadioSetOrientationEnum, +} from '../helpers/radio-set-orientation'; + +const radioSetUniqueId = 0; @Component({ selector: 'daff-radio-set', templateUrl: './radio-set.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + styleUrl: './radio-set.component.scss', host: { + class: 'daff-radio-set', role: 'radiogroup', + '[class.vertical]': 'orientation() === "vertical"', + '[class.horizontal]': 'orientation() === "horizontal"', }, + changeDetection: ChangeDetectionStrategy.OnPush, }) +export class DaffRadioSetComponent implements ControlValueAccessor { + /** + * @docs-private + */ + @ContentChild(DaffHintComponent) private _hint: DaffHintComponent; + /** + * @docs-private + */ + @ContentChild(DaffErrorMessageComponent) private _error: DaffErrorMessageComponent; + + private ngControl = inject(NgControl, { self: true, optional: true }); + + /** + * The unique id of a radio set. Defaults to an autogenerated value. When using this, + * it's your responsibility to ensure that the id for each radio set is unique. + * + * It gets assigned to the `aria-labelledby` attribute for the radiogroup wrapper. + */ + id = input(`daff-radio-set-${radioSetUniqueId}`); + + /** + * The form element name. + */ + name = input(); + + /** + * Value currently selected for a radio set. This is ignored when a form control is used. + */ + _inputValue = input(undefined, { + alias: 'value', + }); + + /** + * Whether or not a radio set is disabled. This is ignored if a form control is used. + */ + _inputDisabled = input(false, { + alias: 'disabled', + }); + + /** + * The orientation of a radio set. Defaults to `vertical`. + */ + orientation = input(DaffRadioSetOrientationEnum.Vertical, { + transform: (value: DaffRadioSetOrientation | null | undefined): DaffRadioSetOrientation => value || DaffRadioSetOrientationEnum.Vertical, + }); + + /** The tabindex passed down to each radio. Defaults to `0`. */ + tabIndex = input(0); + + /** + * Event fired when the value has changed. + */ + valueChange = output(); + + /** Value currently selected for a radio set. */ + value = signal(undefined); + + /** + * @docs-private + */ + disabled = signal(false); + + /** + * @docs-private + */ + hintId = this.id + '-hint'; + + /** + * @docs-private + */ + errorMessageId = this.id + '-error'; + + /** + * @docs-private + * + * Part of ControlValueAccessor. + */ + _onChange: () => unknown; + + /** + * @docs-private + * + * Part of ControlValueAccessor. + */ + _onTouch: () => unknown; + + constructor() { + if (this.ngControl) { + this.ngControl.valueAccessor = this; + } + + if (!this.ngControl) { + effect(() => { + this.value.set(this._inputValue()); + }); + + effect(() => { + this.disabled.set(this._inputDisabled()); + }); + } + + effect(() => { + this.valueChange.emit(this.value()); + }); + } + + /** + * @docs-private + */ + hasHint() { + return this._hint ? true : false; + } + + /** + * @docs-private + */ + hasErrorMessage() { + return this._error ? true : false; + } -export class DaffRadioSetComponent { + /** + * @docs-private + * + * Part of ControlValueAccessor. + */ + writeValue(obj: any): void { + this.value.set(obj); + } - @Input() name: string; + /** + * @docs-private + * + * Part of ControlValueAccessor. + */ + registerOnChange(fn: any): void { + this._onChange = fn; + } - constructor() { } + /** + * @docs-private + * + * Part of ControlValueAccessor. + */ + registerOnTouched(fn: any): void { + this._onTouch = fn; + } + /** + * @docs-private + * + * Part of ControlValueAccessor. + */ + setDisabledState?(isDisabled: boolean): void { + this.disabled.set(isDisabled); + } } diff --git a/libs/design/radio/src/radio-theme.scss b/libs/design/radio/src/radio-theme.scss new file mode 100644 index 0000000000..908623a8d1 --- /dev/null +++ b/libs/design/radio/src/radio-theme.scss @@ -0,0 +1,27 @@ +@use '../../scss/theming' as *; + +// stylelint-disable selector-class-pattern +@mixin daff-radio-theme($theme) { + $neutral: daff-get-palette($theme, neutral); + $primary: daff-get-palette($theme, primary); + $mode: daff-get-theme-mode($theme); + + .daff-radio { + $root: '.daff-radio'; + + #{$root}__outer-circle { + border: 1px solid daff-color($neutral, 90); + } + + #{$root}__inner-circle { + background-color: daff-color($neutral, 90); + } + + &.focused { + #{$root}__outer-circle { + outline: 2px solid daff-color($primary); + outline-offset: 1.5px; + } + } + } +} diff --git a/libs/design/radio/src/radio.module.ts b/libs/design/radio/src/radio.module.ts index 7f8bdd825b..2d19a2e1a4 100644 --- a/libs/design/radio/src/radio.module.ts +++ b/libs/design/radio/src/radio.module.ts @@ -1,21 +1,33 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { DaffRadioControlValueAccessorDirective } from './cva/radio-cva.directive'; +import { + DaffFormFieldLabelDirective, + DaffHintComponent, + DaffErrorMessageComponent, +} from '@daffodil/design/form'; + import { DaffRadioComponent } from './radio/radio.component'; import { DaffRadioSetComponent } from './radio-set/radio-set.component'; +/** + * @deprecated in favor of standalone components. Deprecated in version 0.90.0. Will be removed in version 1.0.0. + */ @NgModule({ imports: [ CommonModule, DaffRadioComponent, DaffRadioSetComponent, - DaffRadioControlValueAccessorDirective, + DaffFormFieldLabelDirective, + DaffHintComponent, + DaffErrorMessageComponent, ], exports: [ DaffRadioComponent, DaffRadioSetComponent, - DaffRadioControlValueAccessorDirective, + DaffFormFieldLabelDirective, + DaffHintComponent, + DaffErrorMessageComponent, ], }) export class DaffRadioModule { } diff --git a/libs/design/radio/src/radio.ts b/libs/design/radio/src/radio.ts index 1fca455da3..8e12e0314f 100644 --- a/libs/design/radio/src/radio.ts +++ b/libs/design/radio/src/radio.ts @@ -1,4 +1,9 @@ -import { DaffRadioControlValueAccessorDirective } from './cva/radio-cva.directive'; +import { + DaffErrorMessageComponent, + DaffFormFieldLabelDirective, + DaffHintComponent, +} from '@daffodil/design/form'; + import { DaffRadioComponent } from './radio/radio.component'; import { DaffRadioSetComponent } from './radio-set/radio-set.component'; /** @@ -7,5 +12,7 @@ import { DaffRadioSetComponent } from './radio-set/radio-set.component'; export const DAFF_RADIO_COMPONENTS = [ DaffRadioComponent, DaffRadioSetComponent, - DaffRadioControlValueAccessorDirective, + DaffFormFieldLabelDirective, + DaffHintComponent, + DaffErrorMessageComponent, ]; diff --git a/libs/design/radio/src/radio/radio.component.html b/libs/design/radio/src/radio/radio.component.html index 1ab7b3e096..e5d301bdc6 100644 --- a/libs/design/radio/src/radio/radio.component.html +++ b/libs/design/radio/src/radio/radio.component.html @@ -1,14 +1,18 @@ - -