Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(elements-angular): support new angular standalone mode #1242

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions packages/elements-angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@
"es2015": "./dist/fesm2015/inovex.de-elements-angular.mjs",
"node": "./dist/fesm2015/inovex.de-elements-angular.mjs",
"default": "./dist/fesm2020/inovex.de-elements-angular.mjs"
},
"./shared": {
"types": "./dist/shared/index.d.ts",
"esm2020": "./dist/esm2020/shared/inovex.de-elements-angular-shared.mjs",
"es2020": "./dist/fesm2020/inovex.de-elements-angular-shared.mjs",
"es2015": "./dist/fesm2015/inovex.de-elements-angular-shared.mjs",
"node": "./dist/fesm2015/inovex.de-elements-angular-shared.mjs",
"default": "./dist/fesm2020/inovex.de-elements-angular-shared.mjs"
},
"./standalone": {
"types": "./dist/standalone/index.d.ts",
"esm2020": "./dist/esm2020/standalone/inovex.de-elements-angular-standalone.mjs",
"es2020": "./dist/fesm2020/inovex.de-elements-angular-standalone.mjs",
"es2015": "./dist/fesm2015/inovex.de-elements-angular-standalone.mjs",
"node": "./dist/fesm2015/inovex.de-elements-angular-standalone.mjs",
"default": "./dist/fesm2020/inovex.de-elements-angular-standalone.mjs"
}
}
}
6 changes: 6 additions & 0 deletions packages/elements-angular/shared/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "./../node_modules/ng-packagr/ng-package.schema.json",
"lib": {
"entryFile": "src/index.ts"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { ValueAccessorDirective } from './value-accessor.directive';

export const booleanDirectiveSelector =
'ino-checkbox,ino-control-item[role="checkbox"],ino-switch';

@Directive()
export class BooleanValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('checkedChange', ['$event.detail'])
_handleInoChange(value: boolean) {
this.handleChangeEvent(value);
}

override writeValue(value: boolean): void {
this.el.nativeElement.checked = this.lastValue = value == null ? '' : value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { ValueAccessorDirective } from './value-accessor.directive';

export const fsDirectiveSelector = 'ino-input-file,ino-input[type=file]';

@Directive()
export class FsValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('changeFile', ['$event.detail'])
_handleInputEvent(value: any): void {
if (this.el.nativeElement.multiple) {
this.handleChangeEvent(value.files);
} else {
this.handleChangeEvent(value.files[0]);
}
}

override writeValue(value: any): void {
if (value instanceof FileList) {
this.el.nativeElement.files = value;
} else if (Array.isArray(value) && !value.length) {
this.el.nativeElement.files = null;
} else if (value === null) {
this.el.nativeElement.files = null;
} else {
// Since we cannot manually construct a FileList instance, we have to ignore
// any attempt to push a non-FileList instance into the input.
if (console && console.warn && console.log) {
console.warn(
'Ignoring attempt to assign non-FileList to input[type=file].',
);
console.log('Value:', value);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './boolean-value-accessor.directive';
export * from './fs-value-accessor.directive';
export * from './numeric-value-accessor.directive';
export * from './radio-value-accessor.directive';
export * from './range-value-accessor.directive';
export * from './text-value-accessor.directive';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { HostListener, ElementRef, Directive } from '@angular/core';
import { ValueAccessorDirective } from './value-accessor.directive';

export const numericDirectiveSelector =
'ino-input[type=number],ino-range:not([ranged])';

@Directive()
export class NumericValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('valueChange', ['$event.detail'])
handleInputEvent(value: number): void {
this.handleChangeEvent(value);
}

registerOnChange(fn: (_: number | null) => void): void {
super.registerOnChange((value: string) => {
fn(value === '' ? null : parseFloat(value));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { ValueAccessorDirective } from './value-accessor.directive';

export const radioDirectiveSelector =
'ino-radio,ino-control-item[role="radio"]';

@Directive()
export class RadioValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('checkedChange', ['$event.detail'])
_handleInoChange(value: boolean): void {
this.handleChangeEvent(value);
}

override writeValue(value: boolean): void {
this.el.nativeElement.checked = this.lastValue = value == null ? '' : value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';

type ValueType = 'start' | 'end';

export const rangeDirectiveSelector = 'ino-range[ranged=true]';

@Directive()
export class RangeValueAccessorDirective implements ControlValueAccessor {
private lastValueStart: number | undefined;
private lastValueEnd: number | undefined;
private lastValueWrittenTo: ValueType | undefined;

constructor(private el: ElementRef) {}

writeValue(value: number): void {
if (this.lastValueWrittenTo === 'start')
this.el.nativeElement.valueStart = value;

if (this.lastValueWrittenTo === 'end')
this.el.nativeElement.valueEnd = value;
}

@HostListener('valueStartChange', ['$event.detail'])
handleValueStartChange(value: number): void {
this.handleValueStartEndChange('start', value);
}

@HostListener('valueEndChange', ['$event.detail'])
handleValueEndChange(value: number): void {
this.handleValueStartEndChange('end', value);
}

private handleValueStartEndChange(
type: 'start' | 'end',
value: number,
): void {
if (type === 'start' && value !== this.lastValueStart) {
this.lastValueStart = value;
this.lastValueWrittenTo = 'start';
this.writeValue(value);
}

if (type === 'end' && value !== this.lastValueEnd) {
this.lastValueEnd = value;
this.lastValueWrittenTo = 'end';
this.writeValue(value);
}
}

setDisabledState(isDisabled: boolean): void {
this.el.nativeElement.disabled = isDisabled;
}

registerOnChange(fn: (value: number) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}

private onChange: (value: any) => void = () => {
/**/
};
private onTouched: () => void = () => {
/**/
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { ValueAccessorDirective } from './value-accessor.directive';

export const textDirectiveSelector =
'ino-autocomplete,ino-currency-input,ino-input:not([type=number]):not([type=file]),ino-markdown-editor,ino-textarea,ino-select,ino-datepicker,ino-segment-group';

@Directive()
export class TextValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('valueChange', ['$event.detail'])
_handleInputEvent(value: string): void {
this.handleChangeEvent(value);
}

@HostListener('inoBlur')
_handleInoBlur() {
this.handleBlurEvent();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ElementRef } from '@angular/core';
import { Directive, ElementRef } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';

@Directive()
export class ValueAccessorDirective implements ControlValueAccessor {
protected lastValue: any;
constructor(protected el: ElementRef) {}
Expand Down
2 changes: 2 additions & 0 deletions packages/elements-angular/shared/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './directives/control-value-accesors';
export * from './utils/app-initialize';
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

import { ValueAccessorDirective } from './value-accessor.directive';
import { booleanDirectiveSelector, BooleanValueAccessorDirective as ProxyDirective } from '@inovex.de/elements-angular/shared';

@Directive({
selector: 'ino-checkbox,ino-control-item[role="checkbox"],ino-switch',
selector: booleanDirectiveSelector,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: BooleanValueAccessorDirective,
multi: true,
},
],
standalone: false
})
export class BooleanValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('checkedChange', ['$event.detail'])
_handleInoChange(value: boolean) {
this.handleChangeEvent(value);
}

override writeValue(value: boolean): void {
this.el.nativeElement.checked = this.lastValue = value == null ? '' : value;
}
}
export class BooleanValueAccessorDirective extends ProxyDirective {}
Original file line number Diff line number Diff line change
@@ -1,48 +1,16 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

import { ValueAccessorDirective } from './value-accessor.directive';
import { fsDirectiveSelector, FsValueAccessorDirective as ProxyDirective } from '@inovex.de/elements-angular/shared';

@Directive({
selector: 'ino-input-file,ino-input[type=file]',
selector: fsDirectiveSelector,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: FsValueAccessorDirective,
useExisting: ProxyDirective,
multi: true,
},
],
standalone: false
})
export class FsValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('changeFile', ['$event.detail'])
_handleInputEvent(value: any): void {
if (this.el.nativeElement.multiple) {
this.handleChangeEvent(value.files);
} else {
this.handleChangeEvent(value.files[0]);
}
}

override writeValue(value: any): void {
if (value instanceof FileList) {
this.el.nativeElement.files = value;
} else if (Array.isArray(value) && !value.length) {
this.el.nativeElement.files = null;
} else if (value === null) {
this.el.nativeElement.files = null;
} else {
// Since we cannot manually construct a FileList instance, we have to ignore
// any attempt to push a non-FileList instance into the input.
if (console && console.warn && console.log) {
console.warn(
'Ignoring attempt to assign non-FileList to input[type=file].'
);
console.log('Value:', value);
}
}
}
}
export class FsValueAccessorDirective extends ProxyDirective {}
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
import { Directive, HostListener, ElementRef } from '@angular/core';
import { Directive } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessorDirective } from "./value-accessor.directive";
import { numericDirectiveSelector, NumericValueAccessorDirective as ProxyDirective } from '@inovex.de/elements-angular/shared';

@Directive({
selector: 'ino-input[type=number],ino-range:not([ranged])',
selector: numericDirectiveSelector,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: NumericValueAccessorDirective,
multi: true,
},
],
standalone: false
})
export class NumericValueAccessorDirective extends ValueAccessorDirective {
constructor(el: ElementRef) {
super(el);
}

@HostListener('valueChange', ['$event.detail'])
handleInputEvent(value: number): void {
this.handleChangeEvent(value);
}

registerOnChange(fn: (_: number | null) => void): void {
super.registerOnChange((value: string) => {
fn(value === '' ? null : parseFloat(value));
});
}
}
export class NumericValueAccessorDirective extends ProxyDirective {}
Loading
Loading