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 {
+
+}
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"],