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 @@
-
-