feat(ui): Added radiobutton-group to ui-libs. (TV-854)

Squashed commit of the following:

commit 04465cb065382fa481a0b257e5f9190b5dcb1c4d
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Nov 4 15:21:21 2021 +0100

    Updated components to use radiobutton-group from ui-libs

commit 5aa465c04ce01659dfb4f339970ed821c4431f5a
Merge: a2f347bd 28d128c1
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Nov 4 10:10:07 2021 +0100

    Merge branch 'develop' into feature/TV-854-radiobutton-group

commit a2f347bdb03411014819a48a935899c7bcffaca0
Merge: b326e0bb 5c12b2b7
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Nov 4 08:35:44 2021 +0100

    Merge branch 'develop' into feature/TV-854-radiobutton-group

commit b326e0bbd843c43cc18661b53e06a214cb7259c8
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Nov 4 08:01:38 2021 +0100

    WIP
This commit is contained in:
Erik Tiekstra
2021-11-04 16:07:33 +01:00
parent 28d128c1e2
commit b9a14ef3cd
20 changed files with 308 additions and 80 deletions

View File

@@ -0,0 +1,4 @@
export enum RadiobuttonGroupDirection {
HORIZONTAL = 'horizontal',
VERTICAL = 'vertical',
}

View File

@@ -0,0 +1,21 @@
<div class="ui-radiobutton-group" [ngClass]="{'ui-radiobutton-group--invalid': uiInvalid}">
<div class="ui-radiobutton-group__radiobuttons" [ngClass]="radiobuttonsModifierClass">
<digi-form-radiobutton
*ngFor="let item of uiRadiobuttons"
class="ui-radiobutton-group__radiobutton"
[afLabel]="getLabelText(item.label)"
[afValue]="item.value"
[afChecked]="currentValue === item.value"
[afName]="name"
[afRequired]="uiRequired"
[afValidation]="uiInvalid ? 'error' : 'neutral'"
[afVariation]="uiSecondary ? 'secondary' : 'primary'"
(afOnChange)="checkForChange($event.detail.target.value)"
></digi-form-radiobutton>
</div>
<div aria-atomic="true" role="alert">
<digi-form-validation-message *ngIf="uiInvalid && uiValidationMessage" af-variation="error"
>{{uiValidationMessage}}</digi-form-validation-message
>
</div>
</div>

View File

@@ -0,0 +1,37 @@
@import 'variables/gutters';
.ui-radiobutton-group {
display: flex;
flex-direction: column;
&--invalid {
gap: var(--digi--layout--gutter--xs);
}
&__radiobuttons {
display: flex;
gap: var(--digi--layout--gutter--s);
flex-direction: column;
&--horizontal {
flex-direction: row;
align-items: center;
gap: $digi--layout--gutter--l;
}
}
&__radiobutton {
::ng-deep .digi-form-radiobutton__circle {
top: 50% !important;
transform: translateY(-50%);
&::after {
top: 50% !important;
left: 50% !important;
}
}
::ng-deep .digi-form-radiobutton__input:focus ~ .digi-form-radiobutton__circle {
box-shadow: var(--digi--ui--box-shadow--focus) !important;
}
}
}

View File

@@ -0,0 +1,26 @@
/* tslint:disable:no-unused-variable */
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RadiobuttonGroupComponent } from './radiobutton-group.component';
describe('RadiobuttonGroupComponent', () => {
let component: RadiobuttonGroupComponent;
let fixture: ComponentFixture<RadiobuttonGroupComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RadiobuttonGroupComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RadiobuttonGroupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,16 @@
import { ReactiveFormsModule } from '@angular/forms';
import { RadiobuttonGroupComponent } from './radiobutton-group.component';
import { UiRadiobuttonGroupModule } from './radiobutton-group.module';
export default { title: 'RadiobuttonGroup', component: RadiobuttonGroupComponent };
const componentModule = {
moduleMetadata: {
imports: [ReactiveFormsModule, UiRadiobuttonGroupModule],
},
};
export const standard = () => ({
...componentModule,
template: '<ui-radiobutton-group></ui-radiobutton-group>',
});

View File

@@ -0,0 +1,122 @@
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EventEmitter,
Injector,
Input,
OnChanges,
Output,
} from '@angular/core';
import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { RadiobuttonGroupDirection } from './radiobutton-group-direction.enum';
import { Radiobutton } from './radiobutton.model';
/**
* A radiobutton-group component.
*
* ## Usage
* ``import {UiRadiobuttonGroupModule} from '@ui/radiobutton-group/radiobutton-group.module';``
*/
@Component({
selector: 'ui-radiobutton-group',
templateUrl: './radiobutton-group.component.html',
styleUrls: ['./radiobutton-group.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: RadiobuttonGroupComponent,
multi: true,
},
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RadiobuttonGroupComponent implements ControlValueAccessor, AfterViewInit, OnChanges {
@Input() uiDirection: RadiobuttonGroupDirection;
@Input() uiInvalid: boolean;
@Input() uiValidationMessage: string;
@Input() uiRadiobuttons: Radiobutton[];
@Input() uiBooleanValues: boolean;
@Input() uiSecondary: boolean;
@Input() uiRequired: boolean;
@Input() uiName: string;
@Input() uiAnnounceIfOptional: boolean;
@Output() uiOnChange = new EventEmitter<any>();
name: string | number;
onTouched: () => {};
private onChange: (value: any) => {};
private _value: any;
constructor(private injector: Injector, private changeDetectorRef: ChangeDetectorRef) {}
get currentValue(): any {
return this._value;
}
get radiobuttonsModifierClass(): string {
if (this.uiDirection === RadiobuttonGroupDirection.HORIZONTAL) {
return `ui-radiobutton-group__radiobuttons--horizontal`;
}
return '';
}
private _transformValue(value: any): any {
return this.uiBooleanValues ? value === 'true' : value;
}
private get _requiredText() {
if (this.uiRequired && !this.uiAnnounceIfOptional) {
return ' (obligatoriskt)';
}
if (!this.uiRequired && this.uiAnnounceIfOptional) {
return ' (frivilligt)';
}
return '';
}
getLabelText(label: string): string {
return `${label}${this._requiredText}`;
}
ngAfterViewInit(): void {
const ngControl: NgControl = this.injector.get(NgControl, null);
if (ngControl) {
this.name = ngControl.name || this.uiName;
}
}
ngOnChanges(): void {
const ngControl: NgControl = this.injector.get(NgControl, null);
if (ngControl) {
this.name = ngControl.name || this.uiName;
}
}
checkForChange(rawValue: any): void {
const value = this._transformValue(rawValue);
if (this._value !== value) {
if (this.onChange) {
this.onChange(value);
}
this._value = value;
this.uiOnChange.emit(value);
}
}
writeValue(value: any): void {
this._value = value;
this.changeDetectorRef.detectChanges();
}
registerOnChange(fn: (value: any) => {}) {
this.onChange = fn;
}
registerOnTouched(fn: () => {}) {
this.onTouched = fn;
}
}

View File

@@ -0,0 +1,11 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RadiobuttonGroupComponent } from './radiobutton-group.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [CommonModule],
declarations: [RadiobuttonGroupComponent],
exports: [RadiobuttonGroupComponent],
})
export class UiRadiobuttonGroupModule {}

View File

@@ -0,0 +1,4 @@
export interface Radiobutton {
value: any;
label: string;
}