@ng-simplicity/forms-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NG-Simplicity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # @ng-simplicity/forms-core
2
+
3
+ The core engine package for **NG-Simplicity Forms**. This package manages form states, dynamic registry injection, component lifecycle bindings, and structural layout directives (Rows, Columns, Sections, Groups, Arrays).
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ Add this package to your Angular application:
10
+
11
+ ```bash
12
+ npm install @ng-simplicity/forms-core
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Architecture Overview
18
+
19
+ `@ng-simplicity/forms-core` is structured around three primary layers:
20
+
21
+ ### 1. The Public Boundary: `NgsFormsService`
22
+ - Injected by the user's component page.
23
+ - Exposes form values and statuses through Signals and observables (e.g. `formValue$`, `dirty`, `isValid`).
24
+ - Provides entry methods like `setFormConfig(config)` and `patchValue(data)`.
25
+ - Implements a retry loading mechanism in case child elements compile asynchronously.
26
+
27
+ ### 2. The Internal Coordinator: `NgsFormsInternalService`
28
+ - Provided at the container level by `<ngs-form>`.
29
+ - Coordinates component states, validators, and submission attempts.
30
+ - Offers `subscribeToState(fieldName)` to merge local field configurations with global properties.
31
+
32
+ ### 3. Component Registry: `NgsFormsComponentRegistryService`
33
+ - Maps string identifiers (like `input-text`, `input-textarea`) to actual Angular component types.
34
+ - Used by the rendering compiler to dynamically construct layout structures.
35
+
36
+ ---
37
+
38
+ ## Custom Component Development Guide
39
+
40
+ One of the main strengths of `forms-core` is the ability to write your own custom inputs and register them. To build a custom component that hooks into the dynamic forms layout:
41
+
42
+ ### 1. Extend `NgsFormsFormItemWithVisibleAndValidatorsBase`
43
+
44
+ Your component must extend the base class and use Angular's Reactive Forms control bindings.
45
+
46
+ ```typescript
47
+ import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
48
+ import { ReactiveFormsModule } from '@angular/forms';
49
+ import {
50
+ NgsFormsFormItemWithVisibleAndValidatorsBase,
51
+ NgsFormsFormItem,
52
+ NgsFormsFormItemConfigBaseTextInput
53
+ } from '@ng-simplicity/forms-core';
54
+ import { CommonModule } from '@angular/common';
55
+ import { v4 } from 'uuid';
56
+
57
+ export interface CustomInputConfig extends NgsFormsFormItemConfigBaseTextInput {
58
+ customColor?: string;
59
+ }
60
+
61
+ @Component({
62
+ selector: 'custom-fancy-input',
63
+ standalone: true,
64
+ imports: [CommonModule, ReactiveFormsModule],
65
+ template: `
66
+ @if (control) {
67
+ <div class="fancy-input-wrapper">
68
+ <label [style.color]="config.customColor">{{ config.label }}</label>
69
+ <input
70
+ [formControl]="control"
71
+ [placeholder]="config.placeholder || ''"
72
+ class="fancy-input-field"
73
+ />
74
+ @if (errorMessage) {
75
+ <div class="error-msg">{{ errorMessage }}</div>
76
+ }
77
+ </div>
78
+ }
79
+ `,
80
+ changeDetection: ChangeDetectionStrategy.OnPush,
81
+ })
82
+ export class CustomFancyInputComponent
83
+ extends NgsFormsFormItemWithVisibleAndValidatorsBase<CustomInputConfig>
84
+ implements OnInit
85
+ {
86
+ static override key = 'fancy-input';
87
+
88
+ // Helper static creator to ensure type-safe schema composition
89
+ static create(config: CustomInputConfig): NgsFormsFormItem<CustomInputConfig> {
90
+ return {
91
+ uuid: v4(),
92
+ type: CustomFancyInputComponent.key,
93
+ config,
94
+ };
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### 2. Register Your Component
100
+
101
+ Register it into the registry service:
102
+
103
+ ```typescript
104
+ import { Component } from '@angular/core';
105
+ import { NgsFormsComponentRegistryService } from '@ng-simplicity/forms-core';
106
+ import { CustomFancyInputComponent } from './custom-fancy-input.component';
107
+
108
+ @Component({
109
+ selector: 'app-root',
110
+ template: '<ngs-form></ngs-form>'
111
+ })
112
+ export class AppComponent {
113
+ constructor(registry: NgsFormsComponentRegistryService) {
114
+ registry.register(CustomFancyInputComponent.key, CustomFancyInputComponent);
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### 3. Add to Schema
120
+
121
+ ```typescript
122
+ const formConfig = {
123
+ inputUpdateDebounce: 100,
124
+ root: NgsFormsFormGroupComponent.create({ name: 'profileForm' }, [
125
+ CustomFancyInputComponent.create({
126
+ name: 'nickname',
127
+ label: 'Nickname',
128
+ placeholder: 'Enter cool nickname...',
129
+ customColor: 'purple'
130
+ })
131
+ ])
132
+ };
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Validation & Error Messages (`errorMessageMap`)
138
+
139
+ Each form control component that extends `NgsFormsFormItemWithVisibleAndValidatorsBase` gets access to validation handling out of the box.
140
+
141
+ 1. **Defining Validation Rules**: When creating your configuration schema, pass validators (such as `Validators.required` or custom functions) under `validators` or as an observable stream under `validators$`.
142
+ 2. **Customizing Error Messages**: Pass an optional `errorMessageMap` object containing key-value pairs matching Angular validator error codes to custom text:
143
+ ```typescript
144
+ errorMessageMap: {
145
+ required: 'This field cannot be left blank.',
146
+ minlength: 'Must be at least 4 characters long.',
147
+ email: 'Please enter a valid email address.'
148
+ }
149
+ ```
150
+ 3. **Displaying Errors**: Within your custom component template, bind your error display element to the `errorMessage` property inherited from the base class. The core engine dynamically updates `errorMessage` based on whether the control is invalid, touched, dirty, or if the form has been submitted.
151
+
152
+ ---
153
+
154
+ ## Extension Reference Guide
155
+
156
+ When writing custom controls, select the appropriate base class and configuration interface to inherit from.
157
+
158
+ ### Available Base Classes
159
+ All base classes are exported from `@ng-simplicity/forms-core`:
160
+
161
+ * **`NgsFormsBaseClassFormComponent<T>`**: The fundamental base class. Automatically fetches and injects the component's static configuration (`config`).
162
+ * **`NgsFormsFormItemWithVisibleAndValidatorsBase<T>`**: Extends the base form component class. Connects the component to the parent `FormGroup` or `FormArray`, listens to visibility state (`visible$`), sets up control validator bindings (`validators`/`validators$`), and manages active `errorMessage` and `submitted` states.
163
+ * **`NgsFormsBaseClassFormInputComponent<T>`**: Extends the validator base class. Exposes a `commonState` signal that listens to merged global state or local state overrides (useful for context properties like theme settings or read-only/interactive display toggles).
164
+ * **`NgsFormsBaseClassFormItemInputWithOptionsComponent<T>`**: Extends the input base class. Specifically designed for controls with choice selection (dropdowns, lists, radio button groups). Exposes a unified `options` signal mapped from either static arrays or dynamic observable streams (`options$`).
165
+ * **`NgsFormsBaseClassItemsContainerBase<T>`**: The base class used for layout containers (like rows, grids, sections, groups) that recursively render a nested set of child form components.
166
+
167
+ ### Available Configuration Interfaces
168
+ Ensure your custom configuration type extends one of these core interfaces for full TypeScript safety:
169
+
170
+ * **`NgsFormsFormItemConfigBase`**: Standard base structure containing only an optional `uuid?: string`.
171
+ * **`NgsFormsFormItemConfigBaseItemWithNameAndValidators`**: Core interface for registerable form controls. Adds `name: string`, `errorMessageMap?: NgsFormsFormErrorKeyValueMap`, `disabled?`/`disabled$?`, and `validators?`/`validators$?`.
172
+ * **`NgsFormsFormItemConfigBaseInput`**: Extends the name/validators base. Adds common interactive input properties: `id?: string`, `label: string`, and `value?: unknown`.
173
+ * **`NgsFormsFormItemConfigBaseTextInput`**: Extends the input base. Adds text-specific options: `placeholder?: string` and `type?: 'text' | 'email' | 'password'`.
174
+ * **`NgsFormsFormItemConfigBaseInputWithOptions`**: Extends the input base. Adds selection fields: `options?: Array<NgsFormsFormInputOption>` and `options$?: Observable<Array<NgsFormsFormInputOption>>`.
175
+ * **`NgsFormsFormItemContainerConfigBase`**: Extends the base interface. Used by layout components, defining an array of children: `items: Array<NgsFormsFormItem<any>>`.
176
+
177
+ ---
178
+
179
+ ## Commands
180
+
181
+ - **Run unit tests**:
182
+ ```bash
183
+ nx test forms-core
184
+ ```
185
+ - **Run test with code coverage**:
186
+ ```bash
187
+ nx test forms-core --codeCoverage
188
+ ```