carbon-components-angular
Version:
Next generation components
693 lines (686 loc) • 24 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, Component, Input, Output, HostBinding, TemplateRef, ContentChildren, forwardRef, HostListener, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i2 from 'carbon-components-angular/icon';
import { IconModule } from 'carbon-components-angular/icon';
/**
* Used to emit changes performed on a `Radio`.
*/
class RadioChange {
constructor(source, value) {
this.source = source;
this.value = value;
}
}
/**
* class: Radio (extends Checkbox)
*
* selector: `n-radio`
*
* source: `src/forms/radio.component.ts`
*
* ```html
* <cds-radio [(ngModel)]="radioState">Radio</cds-radio>
* ```
*
* Also see: [`RadioGroup`](#cds-radio-group)
*/
class Radio {
constructor() {
this.checked = false;
this.name = "";
this.disabled = false;
this.labelPlacement = "right";
/**
* Sets the HTML required attribute
*/
this.required = false;
/**
* Set to `true` for a loading table.
*/
this.skeleton = false;
/**
* The id for the `Radio`.
*/
this.id = `radio-${Radio.radioCount++}`;
/**
* emits when the state of the radio changes
*/
this.change = new EventEmitter();
this.hostClass = true;
/**
* Reflects whether or not the input is disabled at `RadioGroup` level.
*/
this.disabledFromGroup = false;
this._labelledby = "";
/**
* Handler provided by the `RadioGroup` to bubble events up
*/
this.radioChangeHandler = (event) => { };
}
set ariaLabelledby(value) {
this._labelledby = value;
}
get ariaLabelledby() {
if (this._labelledby) {
return this._labelledby;
}
return `label-${this.id}`;
}
get labelLeft() {
return this.labelPlacement === "left";
}
/**
* Synchronizes with the `RadioGroup` in the event of a changed `Radio`.
* Emits the changes of both the `RadioGroup` and `Radio`.
*/
onChange(event) {
event.stopPropagation();
}
onClick(event) {
this.checked = event.target.checked;
const radioEvent = new RadioChange(this, this.value);
this.change.emit(radioEvent);
this.radioChangeHandler(radioEvent);
}
/**
* Method called by `RadioGroup` with a callback function to bubble `RadioChange` events
* @param fn callback that expects a `RadioChange` as an argument
*/
registerRadioChangeHandler(fn) {
this.radioChangeHandler = fn;
}
setDisabledFromGroup(disabled) {
this.disabledFromGroup = disabled;
}
}
/**
* Used to dynamically create unique ids for the `Radio`.
*/
Radio.radioCount = 0;
Radio.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Radio, deps: [], target: i0.ɵɵFactoryTarget.Component });
Radio.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Radio, selector: "cds-radio, ibm-radio", inputs: { checked: "checked", name: "name", disabled: "disabled", labelPlacement: "labelPlacement", ariaLabelledby: "ariaLabelledby", ariaLabel: "ariaLabel", required: "required", value: "value", skeleton: "skeleton", id: "id" }, outputs: { change: "change" }, host: { properties: { "class.cds--radio-button-wrapper": "this.hostClass", "class.cds--radio-button-wrapper--label-left": "this.labelLeft" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: Radio,
multi: true
}
], ngImport: i0, template: `
<input
*ngIf="!skeleton"
class="cds--radio-button"
type="radio"
[checked]="checked"
[disabled]="disabled || disabledFromGroup"
[name]="name"
[id]="id"
[required]="required"
[attr.value]="value"
[attr.aria-labelledby]="ariaLabelledby"
(change)="onChange($event)"
(click)="onClick($event)">
<div *ngIf="skeleton" class="cds--radio-button cds--skeleton"></div>
<label
class="cds--radio-button__label"
[attr.aria-label]="ariaLabel"
[ngClass]="{
'cds--skeleton': skeleton
}"
[for]="id"
id="label-{{id}}">
<span class="cds--radio-button__appearance"></span>
<ng-content></ng-content>
</label>
`, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Radio, decorators: [{
type: Component,
args: [{
selector: "cds-radio, ibm-radio",
template: `
<input
*ngIf="!skeleton"
class="cds--radio-button"
type="radio"
[checked]="checked"
[disabled]="disabled || disabledFromGroup"
[name]="name"
[id]="id"
[required]="required"
[attr.value]="value"
[attr.aria-labelledby]="ariaLabelledby"
(change)="onChange($event)"
(click)="onClick($event)">
<div *ngIf="skeleton" class="cds--radio-button cds--skeleton"></div>
<label
class="cds--radio-button__label"
[attr.aria-label]="ariaLabel"
[ngClass]="{
'cds--skeleton': skeleton
}"
[for]="id"
id="label-{{id}}">
<span class="cds--radio-button__appearance"></span>
<ng-content></ng-content>
</label>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: Radio,
multi: true
}
]
}]
}], propDecorators: { checked: [{
type: Input
}], name: [{
type: Input
}], disabled: [{
type: Input
}], labelPlacement: [{
type: Input
}], ariaLabelledby: [{
type: Input
}], ariaLabel: [{
type: Input
}], required: [{
type: Input
}], value: [{
type: Input
}], skeleton: [{
type: Input
}], id: [{
type: Input
}], change: [{
type: Output
}], hostClass: [{
type: HostBinding,
args: ["class.cds--radio-button-wrapper"]
}], labelLeft: [{
type: HostBinding,
args: ["class.cds--radio-button-wrapper--label-left"]
}] } });
/**
* Get started with importing the module:
*
* ```typescript
* import { RadioModule } from 'carbon-components-angular';
* ```
*
* Ex:
*
* ```html
* <cds-radio-group [(ngModel)]="radio">
* <cds-radio *ngFor="let one of manyRadios" [value]="one">
* Radio {{one}}
* </cds-radio>
* </cds-radio-group>
*
* Radio selected: {{radio}}
* ```
*
* ```ts
* const manyRadios = ["one", "two", "three", "four", "five", "six"];
* ```
*
* [See demo](../../?path=/story/components-radio--basic)
*/
class RadioGroup {
constructor() {
this.orientation = "horizontal";
this.labelPlacement = "right";
/**
* Set to `true` to show the invalid state.
*/
this.invalid = false;
/**
* Set to `true` to show a warning (contents set by warnText)
*/
this.warn = false;
/**
* Emits event notifying other classes of a change using a `RadioChange` class.
*/
this.change = new EventEmitter();
/**
* Binds 'cds--form-item' value to the class for `RadioGroup`.
*/
this.radioButtonGroupClass = true;
/**
* To track whether the `RadioGroup` has been initialized.
*/
this.isInitialized = false;
/**
* Reflects whether or not the input is disabled and cannot be selected.
*/
this._disabled = false;
/**
* Reflects whether or not the dropdown is loading.
*/
this._skeleton = false;
/**
* The value of the selected option within the `RadioGroup`.
*/
this._value = null;
/**
* The `Radio` within the `RadioGroup` that is selected.
*/
this._selected = null;
/**
* The name attribute associated with the `RadioGroup`.
*/
this._name = `radio-group-${RadioGroup.radioGroupCount++}`;
/**
* Needed to properly implement ControlValueAccessor.
*/
this.onTouched = () => { };
/**
* Method set in registerOnChange to propagate changes back to the form.
*/
this.propagateChange = (_) => { };
}
/**
* Sets the passed in `Radio` item as the selected input within the `RadioGroup`.
*/
set selected(selected) {
const alreadySelected = (this._selected && this._selected.value) === (selected && selected.value);
if (alreadySelected) {
// no need to redo
return;
}
if (this._selected) {
this._selected.checked = false;
}
this._selected = selected;
this.value = selected ? selected.value : null;
this.checkSelectedRadio();
}
/**
* Returns the `Radio` that is selected within the `RadioGroup`.
*/
get selected() {
return this._selected;
}
/**
* Sets the value/state of the selected `Radio` within the `RadioGroup` to the passed in value.
*/
set value(newValue) {
if (this._value !== newValue) {
this._value = newValue;
this.updateSelectedRadioFromValue();
this.checkSelectedRadio();
}
}
/**
* Returns the value/state of the selected `Radio` within the `RadioGroup`.
*/
get value() {
return this._value;
}
/**
* Replaces the name associated with the `RadioGroup` with the provided parameter.
*/
set name(name) {
this._name = name;
this.updateRadios();
}
/**
* Returns the associated name of the `RadioGroup`.
*/
get name() {
return this._name;
}
/**
* Set to true to disable the whole radio group
*/
set disabled(disabled) {
this._disabled = disabled;
this.updateRadios();
}
/**
* Returns the disabled value for the `RadioGroup`.
*/
get disabled() {
return this._disabled;
}
/**
* Returns the skeleton value in the `RadioGroup` if there is one.
*/
get skeleton() {
return this._skeleton;
}
/**
* Sets the skeleton value for all `Radio` to the skeleton value of `RadioGroup`.
*/
set skeleton(value) {
this._skeleton = value;
this.updateChildren();
}
/**
* Updates the selected `Radio` to be checked (selected).
*/
checkSelectedRadio() {
if (this.selected && !this._selected.checked) {
this.selected.checked = true;
}
}
/**
* Use the value of the `RadioGroup` to update the selected radio to the right state (selected state).
*/
updateSelectedRadioFromValue() {
let alreadySelected = this._selected != null && this._selected.value === this._value;
if (this.radios && !alreadySelected) {
if (this.selected && this.value) {
this.selected.checked = false;
}
this._selected = null;
this.radios.forEach(radio => {
if (radio.checked || radio.value === this._value) {
this._selected = radio;
}
});
if (this.selected && !this.value) {
this._value = this.selected.value;
}
}
}
/**
* `ControlValueAccessor` method to programmatically disable the `RadioGroup`.
*
* ex: `this.formGroup.get("myRadioGroup").disable();`
*
* @param isDisabled `true` to disable the inputs
*/
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
/**
* Creates a class of `RadioChange` to emit the change in the `RadioGroup`.
*/
emitChangeEvent(event) {
this.change.emit(event);
this.propagateChange(event.value);
this.onTouched();
}
/**
* Synchronizes radio properties.
*/
updateRadios() {
if (this.radios) {
setTimeout(() => {
this.radios.forEach(radio => {
radio.name = this.name;
radio.setDisabledFromGroup(this.disabled);
if (this.labelPlacement === "left") {
radio.labelPlacement = "left";
}
});
});
}
}
/**
* Updates the value of the `RadioGroup` using the provided parameter.
*/
writeValue(value) {
this.value = value;
setTimeout(() => {
this.updateSelectedRadioFromValue();
this.checkSelectedRadio();
});
}
ngAfterContentInit() {
this.radios.changes.subscribe(() => {
this.updateRadios();
this.updateRadioChangeHandler();
});
this.updateChildren();
this.updateRadioChangeHandler();
}
ngAfterViewInit() {
this.updateRadios();
}
/**
* Used to set method to propagate changes back to the form.
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* Registers a callback to be triggered when the control has been touched.
* @param fn Callback to be triggered when the checkbox is touched.
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
focusOut() {
this.onTouched();
}
isTemplate(value) {
return value instanceof TemplateRef;
}
updateChildren() {
if (this.radios) {
this.radios.forEach(child => child.skeleton = this.skeleton);
}
}
updateRadioChangeHandler() {
this.radios.forEach(radio => {
radio.registerRadioChangeHandler((event) => {
if ((this.selected && this.selected.value) === event.value) {
// no need to redo
return;
}
// deselect previous radio
if (this.selected) {
this.selected.checked = false;
}
// update selected and value from the event
this._selected = event.source;
this._value = event.value;
// bubble the event
this.emitChangeEvent(event);
});
});
}
}
/**
* Used for creating the `RadioGroup` 'name' property dynamically.
*/
RadioGroup.radioGroupCount = 0;
RadioGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: RadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
RadioGroup.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: RadioGroup, selector: "cds-radio-group, ibm-radio-group", inputs: { selected: "selected", value: "value", name: "name", disabled: "disabled", skeleton: "skeleton", orientation: "orientation", labelPlacement: "labelPlacement", legend: "legend", ariaLabel: "ariaLabel", ariaLabelledby: "ariaLabelledby", helperText: "helperText", invalid: "invalid", invalidText: "invalidText", warn: "warn", warnText: "warnText" }, outputs: { change: "change" }, host: { listeners: { "focusout": "focusOut()" }, properties: { "class.cds--form-item": "this.radioButtonGroupClass" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: RadioGroup,
multi: true
}
], queries: [{ propertyName: "radios", predicate: i0.forwardRef(function () { return Radio; }) }], ngImport: i0, template: `
<fieldset
class="cds--radio-button-group"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledby]="ariaLabelledby"
[ngClass]="{
'cds--radio-button-group--vertical': orientation === 'vertical',
'cds--radio-button-group--label-left': labelPlacement === 'left',
'cds--radio-button-group--invalid': invalid,
'cds--radio-button-group--warning': !invalid && warn
}"
[attr.data-invalid]="invalid ? true : null">
<legend *ngIf="legend" class="cds--label">
<ng-template *ngIf="isTemplate(legend); else legendLabel;" [ngTemplateOutlet]="legend"></ng-template>
<ng-template #legendLabel>{{legend}}</ng-template>
</legend>
<ng-content></ng-content>
</fieldset>
<div class="cds--radio-button__validation-msg">
<ng-container *ngIf="invalid">
<svg
cdsIcon="warning--filled"
size="16"
class="cds--radio-button__invalid-icon">
</svg>
<div class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(invalidText)">{{ invalidText }}</ng-container>
<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
</div>
</ng-container>
<ng-container *ngIf="!invalid && warn">
<svg
cdsIcon="warning--alt--filled"
class="cds--radio-button__invalid-icon cds--radio-button__invalid-icon--warning"
size="16">
</svg>
<div class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container>
<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
</div>
</ng-container>
</div>
<div
*ngIf="helperText && !invalid && !warn"
class="cds--form__helper-text"
[ngClass]="{'cds--form__helper-text--disabled': disabled}">
<ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container>
<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: RadioGroup, decorators: [{
type: Component,
args: [{
selector: "cds-radio-group, ibm-radio-group",
template: `
<fieldset
class="cds--radio-button-group"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledby]="ariaLabelledby"
[ngClass]="{
'cds--radio-button-group--vertical': orientation === 'vertical',
'cds--radio-button-group--label-left': labelPlacement === 'left',
'cds--radio-button-group--invalid': invalid,
'cds--radio-button-group--warning': !invalid && warn
}"
[attr.data-invalid]="invalid ? true : null">
<legend *ngIf="legend" class="cds--label">
<ng-template *ngIf="isTemplate(legend); else legendLabel;" [ngTemplateOutlet]="legend"></ng-template>
<ng-template #legendLabel>{{legend}}</ng-template>
</legend>
<ng-content></ng-content>
</fieldset>
<div class="cds--radio-button__validation-msg">
<ng-container *ngIf="invalid">
<svg
cdsIcon="warning--filled"
size="16"
class="cds--radio-button__invalid-icon">
</svg>
<div class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(invalidText)">{{ invalidText }}</ng-container>
<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
</div>
</ng-container>
<ng-container *ngIf="!invalid && warn">
<svg
cdsIcon="warning--alt--filled"
class="cds--radio-button__invalid-icon cds--radio-button__invalid-icon--warning"
size="16">
</svg>
<div class="cds--form-requirement">
<ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container>
<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
</div>
</ng-container>
</div>
<div
*ngIf="helperText && !invalid && !warn"
class="cds--form__helper-text"
[ngClass]="{'cds--form__helper-text--disabled': disabled}">
<ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container>
<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: RadioGroup,
multi: true
}
]
}]
}], propDecorators: { selected: [{
type: Input
}], value: [{
type: Input
}], name: [{
type: Input
}], disabled: [{
type: Input
}], skeleton: [{
type: Input
}], orientation: [{
type: Input
}], labelPlacement: [{
type: Input
}], legend: [{
type: Input
}], ariaLabel: [{
type: Input
}], ariaLabelledby: [{
type: Input
}], helperText: [{
type: Input
}], invalid: [{
type: Input
}], invalidText: [{
type: Input
}], warn: [{
type: Input
}], warnText: [{
type: Input
}], change: [{
type: Output
}], radios: [{
type: ContentChildren,
args: [forwardRef(() => Radio)]
}], radioButtonGroupClass: [{
type: HostBinding,
args: ["class.cds--form-item"]
}], focusOut: [{
type: HostListener,
args: ["focusout"]
}] } });
// modules
class RadioModule {
}
RadioModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: RadioModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
RadioModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: RadioModule, declarations: [Radio,
RadioGroup], imports: [CommonModule,
FormsModule,
IconModule], exports: [Radio,
RadioGroup] });
RadioModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: RadioModule, imports: [CommonModule,
FormsModule,
IconModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: RadioModule, decorators: [{
type: NgModule,
args: [{
declarations: [
Radio,
RadioGroup
],
exports: [
Radio,
RadioGroup
],
imports: [
CommonModule,
FormsModule,
IconModule
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { Radio, RadioChange, RadioGroup, RadioModule };
//# sourceMappingURL=carbon-components-angular-radio.mjs.map