@alyle/ui
Version:
Minimal Design, a set of components for Angular
376 lines (372 loc) • 18.7 kB
JavaScript
import * as i0 from '@angular/core';
import { forwardRef, EventEmitter, ContentChildren, Input, Output, ChangeDetectionStrategy, Component, ViewChild, Optional, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import * as i1 from '@alyle/ui';
import { st2c, LY_COMMON_STYLES, StyleCollection, mixinDisableRipple, StyleRenderer, LyCommonModule } from '@alyle/ui';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import * as i2 from '@angular/cdk/platform';
const STYLE_PRIORITY = -2;
const DEFAULT_DISABLE_RIPPLE = false;
const DEFAULT_COLOR = 'accent';
const LY_RADIO_CONTROL_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => LyRadioGroup),
multi: true
};
let idx = 0;
class UndefinedValue {
constructor() { }
}
const STYLES = (theme, ref) => {
const radio = ref.selectorsOf(STYLES);
const { after, before } = theme;
return {
$priority: STYLE_PRIORITY,
/** ly-radio-group */
root: () => (_className) => `${_className}{display:inline-block;}${st2c(((theme.radio
&& theme.radio.root
&& (theme.radio.root instanceof StyleCollection
? theme.radio.root.setTransformer(fn => fn(radio))
: theme.radio.root(radio)))), `${_className}`)}`,
radio: () => (_className) => `${_className}{display:inline-block;-webkit-tap-highlight-color:transparent;}${_className}${radio.checked} ${radio.container} div:nth-child(1){transform:scale(1.25);}${_className}${radio.checked} ${radio.container} div:nth-child(2){transform:scale(0.8);}${_className}${radio.onFocusByKeyboard} ${radio.container}::after{box-shadow:0 0 0 12px;background:currentColor;opacity:.13;border-radius:50%;}`,
label: (_className) => `${_className}{user-select:none;cursor:pointer;white-space:nowrap;position:relative;display:flex;align-items:baseline;}`,
labelContent: null,
container: (_className) => `${_className}{position:relative;margin-${before}:.125em;margin-${after}:.5em;margin-top:auto;margin-bottom:auto;width:16px;height:16px;}${_className} div{margin:auto;border-radius:50%;width:1em;height:1em;box-sizing:border-box;}${_className}::after{content:'';}${st2c((LY_COMMON_STYLES.fill), `${_className}::after`)}${_className}::after{width:16px;height:16px;margin:auto;}${_className} div:nth-child(2){background:currentColor;transform:scale(0);}${_className} div:nth-child(1){transform:scale(1);border:solid .08em currentColor;color:${theme.text.disabled};}`,
checked: null,
_animations: () => (_className) => `${_className} ${radio.container} div{transition:transform cubic-bezier(.1,1,0.5,1);transition-duration:250ms;}`,
onFocusByKeyboard: null,
disabled: () => (_className) => `${_className}{color:${theme.disabled.contrast};}${_className} ${radio.container} div{color:${theme.disabled.contrast}!important;}`
};
};
class LyRadioGroup {
/** @docs-private */
static { this.и = 'LyRadioGroup'; }
set value(val) {
if (this._value !== val) {
if (this._radios) {
this._updateCheckFromValue(val);
}
}
}
get value() {
return this._value;
}
/**
* Mark this group as being "touched" (for ngModel). Meant to be called by the contained
* radio buttons upon their blur.
*/
_touch() {
if (this.onTouched) {
this.onTouched();
}
}
/** @docs-private */
writeValue(value) {
if (!!this._radios) {
this.value = value;
this._markForCheck();
}
}
/**
* Registers a callback to be triggered when the model value changes.
* Implemented as part of ControlValueAccessor.
* @param fn Callback to be registered.
* @docs-private
*/
registerOnChange(fn) {
this._controlValueAccessorChangeFn = fn;
}
/**
* Registers a callback to be triggered when the control is touched.
* Implemented as part of ControlValueAccessor.
* @param fn Callback to be registered.
* @docs-private
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
/**
* Sets the disabled state of the control. Implemented as a part of ControlValueAccessor.
* @param _isDisabled Whether the control should be disabled.
* @docs-private
*/
setDisabledState(_isDisabled) {
// this.disabled = isDisabled;
this._markForCheck();
}
constructor(elementRef, renderer, _theme, _cd) {
this._theme = _theme;
this._cd = _cd;
/** @docs-private */
this.classes = this._theme.renderStyleSheet(STYLES);
/** @docs-private */
this.name = `ly-radio-name-${idx++}`;
this.change = new EventEmitter();
this.color = 'accent';
/** The method to be called in order to update ngModel */
this._controlValueAccessorChangeFn = () => { };
/**
* onTouch function registered via registerOnTouch (ControlValueAccessor).
* @docs-private
*/
this.onTouched = () => { };
renderer.addClass(elementRef.nativeElement, this.classes.root);
}
_updateCheckFromValue(val) {
let newChecked;
this._radios.forEach(radioButton => {
if (val === radioButton.value) {
this.updatevalue(val);
newChecked = true;
radioButton.checked = true;
}
else if (radioButton.checked) {
radioButton.checked = false;
}
});
if (!newChecked) {
/** when val not exist in radio button !== */
this._controlValueAccessorChangeFn(null);
if (this._value != null) {
this._value = null;
}
}
}
/** @docs-private */
updatevalue(value) {
this._value = value;
this._controlValueAccessorChangeFn(value);
this.change.emit();
this._markForCheck();
}
_markForCheck() {
this._cd.markForCheck();
}
_radioResetChecked() {
this._radios.forEach(_ => _._setCheckedToFalsy());
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadioGroup, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.LyTheme2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: LyRadioGroup, isStandalone: false, selector: "ly-radio-group", inputs: { value: "value", color: "color" }, outputs: { change: "change" }, providers: [LY_RADIO_CONTROL_VALUE_ACCESSOR], queries: [{ propertyName: "_radios", predicate: i0.forwardRef(() => LyRadio) }], exportAs: ["lyRadioGroup"], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadioGroup, decorators: [{
type: Component,
args: [{
selector: 'ly-radio-group',
template: `<ng-content></ng-content>`,
providers: [LY_RADIO_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush,
preserveWhitespaces: false,
exportAs: 'lyRadioGroup',
standalone: false
}]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.LyTheme2 }, { type: i0.ChangeDetectorRef }], propDecorators: { value: [{
type: Input
}], change: [{
type: Output
}], color: [{
type: Input
}], _radios: [{
type: ContentChildren,
args: [forwardRef(() => LyRadio)]
}] } });
/** @docs-private */
class LyRadioBase {
constructor(_theme, _ngZone, _platform) {
this._theme = _theme;
this._ngZone = _ngZone;
this._platform = _platform;
}
}
/** @docs-private */
const LyRadioMixinBase = mixinDisableRipple(LyRadioBase);
class LyRadio extends LyRadioMixinBase {
/** @docs-private */
static { this.и = 'LyRadio'; }
set value(val) {
if (this._value !== val) {
this._value = val;
}
}
get value() { return this._value; }
set color(val) {
if (this._color !== val) {
this._color = val;
this[0x1] = this._styleRenderer.add(`${LyRadio.и}--color-${val}`, (theme, ref) => {
const { checked, container } = ref.selectorsOf(STYLES);
return (_className) => `${_className}${checked} ${container},${_className}${checked} ${container} div:nth-child(1),${_className} ${container} div:nth-child(2){color:${theme.colorOf(val)};}`;
}, STYLE_PRIORITY, this[0x1]);
}
}
get color() { return this._color; }
set checked(val) {
const newCheckedState = coerceBooleanProperty(val);
const before = this._checked;
if (before !== newCheckedState) {
this._checked = newCheckedState;
if (!before && newCheckedState) {
/** Add class checked */
this._renderer.addClass(this._elementRef.nativeElement, this.classes.checked);
if (this.value !== this.radioGroup.value) {
/** update Value */
this.radioGroup.updatevalue(this.value);
}
}
else {
/** Remove class checked */
this._renderer.removeClass(this._elementRef.nativeElement, this.classes.checked);
}
this._markForCheck();
}
}
get checked() {
return this._checked;
}
/** @docs-private */
get inputId() {
return `${this.id}-input`;
}
get disabled() { return this._disabled; }
set disabled(value) {
const newVal = coerceBooleanProperty(value);
if (newVal) {
this._renderer.addClass(this._elementRef.nativeElement, this.classes.disabled);
this._disabledClass = this.classes.disabled;
}
else if (this._disabledClass) {
this._renderer.removeClass(this._elementRef.nativeElement, this.classes.disabled);
this._disabledClass = undefined;
}
this._disabled = coerceBooleanProperty(value);
this._markForCheck();
}
constructor(
/** @docs-private */
radioGroup, _elementRef, _renderer, theme, changeDetectorRef, ngZone, _coreStyles, _focusState, _styleRenderer, platform) {
super(theme, ngZone, platform);
this.radioGroup = radioGroup;
this._elementRef = _elementRef;
this._renderer = _renderer;
this.changeDetectorRef = changeDetectorRef;
this._coreStyles = _coreStyles;
this._focusState = _focusState;
this._styleRenderer = _styleRenderer;
/** @docs-private */
this.classes = this.radioGroup.classes;
/** @docs-private */
this.id = `ly-radio-id-${idx++}`;
/** @docs-private */
this.name = '';
this._value = null;
this._checked = false;
this.change = new EventEmitter();
this._triggerElement = this._elementRef;
this._rippleConfig = {
centered: true,
radius: 'containerSize',
percentageToIncrease: 150
};
_renderer.addClass(_elementRef.nativeElement, radioGroup.classes.radio);
}
ngOnInit() {
if (this.radioGroup) {
// Copy name from parent radio group
this.name = this.radioGroup.name;
}
if (!this.color) {
this.color = this.radioGroup.color || DEFAULT_COLOR;
}
}
ngAfterViewInit() {
this._rippleContainer = this._radioContainer;
// set default disable ripple
if (this.disableRipple == null) {
this.disableRipple = DEFAULT_DISABLE_RIPPLE;
}
const focusState = this._focusState.listen(this._input, this._elementRef);
if (focusState) {
focusState.subscribe((event) => {
if (event === 'keyboard') {
this._renderer.addClass(this._elementRef.nativeElement, this.classes.onFocusByKeyboard);
}
else if (event == null) {
this._renderer.removeClass(this._elementRef.nativeElement, this.classes.onFocusByKeyboard);
}
});
}
}
_markForCheck() {
this.changeDetectorRef.markForCheck();
}
ngOnDestroy() {
this._focusState.unlisten(this._elementRef);
this._removeRippleEvents();
}
_onInputChange(event) {
event.stopPropagation();
this.radioGroup._updateCheckFromValue(this.value);
this.radioGroup._touch();
this._addAnim();
}
_addAnim() {
if (!this._animClass) {
this._renderer.addClass(this._elementRef.nativeElement, this.classes._animations);
this._animClass = this.classes._animations;
}
}
_onInputClick(event) { event.stopPropagation(); }
_setCheckedToFalsy() {
this.checked = false;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadio, deps: [{ token: LyRadioGroup, optional: true }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.LyTheme2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i1.LyCoreStyles }, { token: i1.LyFocusState }, { token: i1.StyleRenderer }, { token: i2.Platform }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: LyRadio, isStandalone: false, selector: "ly-radio", inputs: { disableRipple: "disableRipple", value: "value", color: "color", checked: "checked", disabled: "disabled" }, outputs: { change: "change" }, providers: [
StyleRenderer
], viewQueries: [{ propertyName: "_input", first: true, predicate: ["_input"], descendants: true }, { propertyName: "_radioContainer", first: true, predicate: ["_radioContainer"], descendants: true }, { propertyName: "_labelContainer", first: true, predicate: ["_labelContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<label #_labelContainer [attr.for]=\"inputId\" [className]=\"classes.label\">\n <input #_input\n [className]=\"_coreStyles.classes.visuallyHidden\"\n [id]=\"inputId\"\n [checked]=\"checked\"\n [name]=\"name\"\n (change)=\"_onInputChange($event)\"\n (click)=\"_onInputClick($event)\"\n [disabled]=\"disabled\"\n type=\"radio\"\n >\n <div #_radioContainer [className]=\"classes.container\">\n <div [className]=\"_coreStyles.classes.fill\"></div>\n <div [className]=\"_coreStyles.classes.fill\"></div>\n </div>\n <div\n [className]=\"classes.labelContent\">\n <ng-content></ng-content>\n </div>\n</label>", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadio, decorators: [{
type: Component,
args: [{ selector: 'ly-radio', changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, inputs: [
'disableRipple'
], providers: [
StyleRenderer
], standalone: false, template: "<label #_labelContainer [attr.for]=\"inputId\" [className]=\"classes.label\">\n <input #_input\n [className]=\"_coreStyles.classes.visuallyHidden\"\n [id]=\"inputId\"\n [checked]=\"checked\"\n [name]=\"name\"\n (change)=\"_onInputChange($event)\"\n (click)=\"_onInputClick($event)\"\n [disabled]=\"disabled\"\n type=\"radio\"\n >\n <div #_radioContainer [className]=\"classes.container\">\n <div [className]=\"_coreStyles.classes.fill\"></div>\n <div [className]=\"_coreStyles.classes.fill\"></div>\n </div>\n <div\n [className]=\"classes.labelContent\">\n <ng-content></ng-content>\n </div>\n</label>" }]
}], ctorParameters: () => [{ type: LyRadioGroup, decorators: [{
type: Optional
}] }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.LyTheme2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i1.LyCoreStyles }, { type: i1.LyFocusState }, { type: i1.StyleRenderer }, { type: i2.Platform }], propDecorators: { _input: [{
type: ViewChild,
args: ['_input']
}], _radioContainer: [{
type: ViewChild,
args: ['_radioContainer']
}], _labelContainer: [{
type: ViewChild,
args: ['_labelContainer']
}], change: [{
type: Output
}], value: [{
type: Input
}], color: [{
type: Input
}], checked: [{
type: Input
}], disabled: [{
type: Input
}] } });
class LyRadioModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadioModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.10", ngImport: i0, type: LyRadioModule, declarations: [LyRadioGroup, LyRadio], imports: [CommonModule, FormsModule, LyCommonModule], exports: [LyRadioGroup, LyRadio] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadioModule, imports: [CommonModule, FormsModule, LyCommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyRadioModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, FormsModule, LyCommonModule],
exports: [LyRadioGroup, LyRadio],
declarations: [LyRadioGroup, LyRadio],
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { LY_RADIO_CONTROL_VALUE_ACCESSOR, LyRadio, LyRadioBase, LyRadioGroup, LyRadioMixinBase, LyRadioModule, STYLES, UndefinedValue };
//# sourceMappingURL=alyle-ui-radio.mjs.map