diff --git a/npm/ng-packs/packages/components/abp-form-field/ng-package.json b/npm/ng-packs/packages/components/abp-form-field/ng-package.json new file mode 100644 index 00000000000..e09fb3fd037 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-entrypoint.schema.json", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-error.component.ts b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-error.component.ts new file mode 100644 index 00000000000..15dfb226962 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-error.component.ts @@ -0,0 +1,13 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'abp-form-field-error', + template: `
+ +
`, + changeDetection: ChangeDetectionStrategy.OnPush +}) + +export class AbpFormFieldErrorComponent { + +} diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-hint.component.ts b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-hint.component.ts new file mode 100644 index 00000000000..222ca6163cd --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-hint.component.ts @@ -0,0 +1,11 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + selector: 'abp-form-field-hint', + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AbpFormFieldHintComponent { +} diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-label.component.ts b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-label.component.ts new file mode 100644 index 00000000000..634263cdc95 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field-label.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +@Component({ + selector: 'abp-form-field-label', + template: ``, + changeDetection: ChangeDetectionStrategy.OnPush +}) + +export class AbpFormFieldLabelComponent { + for= input(''); +} diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field.component.html b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field.component.html new file mode 100644 index 00000000000..da5f06ab6d6 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field.component.html @@ -0,0 +1,8 @@ +
+ + + + +
diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field.component.ts b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field.component.ts new file mode 100644 index 00000000000..6e02ee03ba0 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/abp-form-field.component.ts @@ -0,0 +1,33 @@ +import { + Component, + ChangeDetectionStrategy, + input, + HostBinding, + InjectionToken, + QueryList, + ContentChild, + contentChild, +} from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AbpFormFieldLabelComponent } from './abp-form-field-label.component'; + +export const ABP_FORM_FIELD = new InjectionToken('AbpFormFieldComponent'); + +@Component({ + selector: 'abp-form-field', + templateUrl: './abp-form-field.component.html', + imports: [CommonModule], + exportAs: 'abpFormField', + providers: [{ provide: ABP_FORM_FIELD, useExisting: AbpFormFieldComponent }], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AbpFormFieldComponent { + + containerClass = input('mb-3'); + labelComponent = contentChild(AbpFormFieldLabelComponent); + + @HostBinding('class') + get hostClasses(): string { + return `d-block mb-3 ${this.containerClass()}`; + } +} diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/index.ts b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/index.ts new file mode 100644 index 00000000000..529106c889e --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/abp-form-field/index.ts @@ -0,0 +1,3 @@ +export * from './abp-form-field.component'; +export * from './abp-form-field-hint.component'; +export * from './abp-form-field-label.component'; diff --git a/npm/ng-packs/packages/components/abp-form-field/src/lib/index.ts b/npm/ng-packs/packages/components/abp-form-field/src/lib/index.ts new file mode 100644 index 00000000000..e65c3233d9b --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/lib/index.ts @@ -0,0 +1 @@ +export * from './abp-form-field'; diff --git a/npm/ng-packs/packages/components/abp-form-field/src/public-api.ts b/npm/ng-packs/packages/components/abp-form-field/src/public-api.ts new file mode 100644 index 00000000000..f41a696fd20 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-form-field/src/public-api.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/npm/ng-packs/packages/components/abp-input/ng-package.json b/npm/ng-packs/packages/components/abp-input/ng-package.json new file mode 100644 index 00000000000..e09fb3fd037 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-input/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-entrypoint.schema.json", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/components/abp-input/src/abp-input.component.html b/npm/ng-packs/packages/components/abp-input/src/abp-input.component.html new file mode 100644 index 00000000000..e31818a2ff5 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-input/src/abp-input.component.html @@ -0,0 +1,35 @@ +@if(abpFormField) { +
+ +
+} @else { +
+ @if (label()) { + + } + + @if (hint()) { + {{ hint() | abpLocalization }} + } + @if (errors.length > 0) { +
+ @for (error of errors; track error) { +
{{ error }}
+ } +
+ } +
+
+} diff --git a/npm/ng-packs/packages/components/abp-input/src/abp-input.component.ts b/npm/ng-packs/packages/components/abp-input/src/abp-input.component.ts new file mode 100644 index 00000000000..3a3dbe13328 --- /dev/null +++ b/npm/ng-packs/packages/components/abp-input/src/abp-input.component.ts @@ -0,0 +1,109 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + DestroyRef, + forwardRef, + inject, + OnInit, + input, + Injector +} from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + FormBuilder, + FormControl, + FormControlName, + FormGroup, + FormGroupDirective, + NG_VALUE_ACCESSOR, + NgControl, + ReactiveFormsModule, +} from '@angular/forms'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { LocalizationPipe } from '@abp/ng.core'; +import { ABP_FORM_FIELD } from '@abp/ng.components/abp-form-field'; + +const ABP_INPUT_CONTROL_VALUE_ACCESSOR = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => AbpInputComponent), + multi: true, +}; + +@Component({ + selector: 'abp-input', + templateUrl: './abp-input.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ReactiveFormsModule, LocalizationPipe], + exportAs: 'abpInput', + host: { + class: 'abp-input', + }, + providers: [ABP_INPUT_CONTROL_VALUE_ACCESSOR], +}) +export class AbpInputComponent implements OnInit, ControlValueAccessor { + label = input(); + type = input<'text' | 'number' | 'password'>('text'); + id = input(''); + placeholder = input(''); + hint = input(''); + control: FormControl; + readonly formBuilder = inject(FormBuilder); + readonly changeDetectorRef = inject(ChangeDetectorRef); + readonly destroyRef = inject(DestroyRef); + readonly injector = inject(Injector); + readonly abpFormField = inject(ABP_FORM_FIELD, { optional: true }); + abpInputFormGroup: FormGroup; + + ngOnInit() { + + const ngControl = this.injector.get(NgControl, null); + if (ngControl) { + this.control = this.injector.get(FormGroupDirective).getControl(ngControl as FormControlName); + } + + this.abpInputFormGroup = this.formBuilder.group({ + value: [''], + }); + + this.value.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(val => { + this.onChange(val); + }); + } + + writeValue(value: any): void { + this.value.setValue(value); + this.changeDetectorRef.markForCheck(); + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + if (isDisabled) { + this.value.disable(); + } else { + this.value.enable(); + } + } + + get errors(): string[] { + if (this.control && this.control.errors) { + return [] + } + return [] + } + + get value(): AbstractControl { + return this.abpInputFormGroup.get('value'); + } + + private onChange: (value: any) => void = () => {}; + private onTouched: () => void = () => {}; +} diff --git a/npm/ng-packs/packages/components/abp-input/src/public-api.ts b/npm/ng-packs/packages/components/abp-input/src/public-api.ts new file mode 100644 index 00000000000..319fe5737bf --- /dev/null +++ b/npm/ng-packs/packages/components/abp-input/src/public-api.ts @@ -0,0 +1 @@ +export * from './abp-input.component'; diff --git a/npm/ng-packs/packages/components/tsconfig.lib.json b/npm/ng-packs/packages/components/tsconfig.lib.json index 22d2695db80..478ba03368a 100644 --- a/npm/ng-packs/packages/components/tsconfig.lib.json +++ b/npm/ng-packs/packages/components/tsconfig.lib.json @@ -10,6 +10,6 @@ "lib": ["dom", "es2020"], "useDefineForClassFields": false }, - "exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"], + "exclude": ["test-setup.ts", "**/*.spec.ts", "jest.config.ts"], "include": ["**/*.ts"] } diff --git a/npm/ng-packs/tsconfig.base.json b/npm/ng-packs/tsconfig.base.json index f863f18520d..0b2b7edc0ae 100644 --- a/npm/ng-packs/tsconfig.base.json +++ b/npm/ng-packs/tsconfig.base.json @@ -20,6 +20,8 @@ "@abp/ng.account.core/proxy": ["packages/account-core/proxy/src/public-api.ts"], "@abp/ng.account/config": ["packages/account/config/src/public-api.ts"], "@abp/ng.components": ["packages/components/src/public-api.ts"], + "@abp/ng.components/abp-form-field": ["packages/components/abp-form-field/src/public-api.ts"], + "@abp/ng.components/abp-input": ["packages/components/abp-input/src/public-api.ts"], "@abp/ng.components/chart.js": ["packages/components/chart.js/src/public-api.ts"], "@abp/ng.components/extensible": ["packages/components/extensible/src/public-api.ts"], "@abp/ng.components/page": ["packages/components/page/src/public-api.ts"],