ngx-vest-forms 2.6.0 → 2.7.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/README.md +115 -1
- package/fesm2022/ngx-vest-forms.mjs +803 -237
- package/fesm2022/ngx-vest-forms.mjs.map +1 -1
- package/package.json +3 -2
- package/types/ngx-vest-forms.d.ts +120 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-vest-forms",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Brecht Billiet, Arjen Althoff",
|
|
6
6
|
"description": "Opinionated template-driven forms library for Angular with Vest.js integration",
|
|
@@ -42,5 +42,6 @@
|
|
|
42
42
|
"types": "./types/ngx-vest-forms.d.ts",
|
|
43
43
|
"default": "./fesm2022/ngx-vest-forms.mjs"
|
|
44
44
|
}
|
|
45
|
-
}
|
|
45
|
+
},
|
|
46
|
+
"type": "module"
|
|
46
47
|
}
|
|
@@ -85,7 +85,8 @@ declare class FormControlStateDirective {
|
|
|
85
85
|
/**
|
|
86
86
|
* Whether this control has been validated at least once.
|
|
87
87
|
* True after the first validation completes, even if the user hasn't touched the field.
|
|
88
|
-
* This
|
|
88
|
+
* This is primarily used for warning display and other derived state that should react
|
|
89
|
+
* to validationConfig-triggered validation even before the user touches the field.
|
|
89
90
|
*/
|
|
90
91
|
readonly hasBeenValidated: _angular_core.Signal<boolean>;
|
|
91
92
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FormControlStateDirective, never>;
|
|
@@ -144,21 +145,26 @@ declare class FormErrorDisplayDirective {
|
|
|
144
145
|
* This keeps programmatic `NgForm.onSubmit()` reactive in zoneless mode and
|
|
145
146
|
* avoids depending on `NgForm.submitted`, whose getter intentionally reads an
|
|
146
147
|
* internal signal with `untracked()`.
|
|
148
|
+
*
|
|
149
|
+
* Note: when this directive is used outside an `NgForm` (no parent form), no
|
|
150
|
+
* subscription is wired up and this signal stays `false` for the lifetime of
|
|
151
|
+
* the directive. Consumers relying on submitted state must host the field
|
|
152
|
+
* inside an `NgForm` (or `ngxVestForm`).
|
|
147
153
|
*/
|
|
148
154
|
readonly formSubmitted: Signal<boolean>;
|
|
149
155
|
constructor();
|
|
150
156
|
/**
|
|
151
157
|
* Determines if errors should be shown based on the specified display mode
|
|
152
|
-
* and the control's state (touched/submitted/
|
|
158
|
+
* and the control's state (touched/submitted/dirty).
|
|
153
159
|
*
|
|
154
160
|
* Note: We check both hasErrors (extracted error messages) AND isInvalid (Angular's validation state)
|
|
155
161
|
* because in some cases (like conditional validations via validationConfig), the control is marked
|
|
156
162
|
* as invalid by Angular before error messages are extracted from Vest. This ensures aria-invalid
|
|
157
163
|
* is set correctly even during the validation propagation delay.
|
|
158
164
|
*
|
|
159
|
-
* For validationConfig-triggered validations
|
|
160
|
-
*
|
|
161
|
-
*
|
|
165
|
+
* For validationConfig-triggered validations, a field may become invalid before it has been
|
|
166
|
+
* touched. Error visibility still respects the field's own `errorDisplayMode`, so untouched
|
|
167
|
+
* dependent fields can remain visually quiet until blur or submit.
|
|
162
168
|
*/
|
|
163
169
|
readonly shouldShowErrors: Signal<boolean>;
|
|
164
170
|
/**
|
|
@@ -993,6 +999,34 @@ type NgxTypedVestSuite<T> = StaticSuite<string, string, NgxTypedSuiteCallback<T>
|
|
|
993
999
|
* This ensures backward compatibility while supporting the new typed API.
|
|
994
1000
|
*/
|
|
995
1001
|
type NgxValidationConfig<T = unknown> = Record<string, string[]> | ValidationConfigMap<T> | null;
|
|
1002
|
+
/**
|
|
1003
|
+
* Payload emitted when a named control inside the form loses focus.
|
|
1004
|
+
*
|
|
1005
|
+
* This is intentionally low-level so app code can build workflows such as
|
|
1006
|
+
* draft auto-save, analytics, or blur-driven side effects without the form
|
|
1007
|
+
* library taking ownership of persistence behavior.
|
|
1008
|
+
*
|
|
1009
|
+
* It is not intended as a blur-time workaround for dependent field validation;
|
|
1010
|
+
* for that pattern, prefer `validationConfig` plus each target field's own
|
|
1011
|
+
* `errorDisplayMode`.
|
|
1012
|
+
*
|
|
1013
|
+
* The emitted `field` is the full dotted control path (e.g.
|
|
1014
|
+
* `passwords.confirm`, `businessHours.values.0.from`) regardless of whether
|
|
1015
|
+
* the surrounding groups use static `ngModelGroup="key"` or dynamic
|
|
1016
|
+
* `[ngModelGroup]="expr"` bindings, because the path is read from the live
|
|
1017
|
+
* `NgModel` directive registered with the form.
|
|
1018
|
+
*
|
|
1019
|
+
* @publicApi
|
|
1020
|
+
*/
|
|
1021
|
+
type NgxFieldBlurEvent<T = unknown> = {
|
|
1022
|
+
field: string;
|
|
1023
|
+
value: unknown;
|
|
1024
|
+
formValue: T | null;
|
|
1025
|
+
dirty: boolean;
|
|
1026
|
+
touched: boolean;
|
|
1027
|
+
valid: boolean;
|
|
1028
|
+
pending: boolean;
|
|
1029
|
+
};
|
|
996
1030
|
/**
|
|
997
1031
|
* Main form directive for ngx-vest-forms that bridges Angular template-driven forms with Vest.js validation.
|
|
998
1032
|
*
|
|
@@ -1142,6 +1176,12 @@ declare class FormDirective<T extends Record<string, unknown>> {
|
|
|
1142
1176
|
* Cleanup is handled automatically by the directive when it's destroyed.
|
|
1143
1177
|
*/
|
|
1144
1178
|
readonly validChange: _angular_core.OutputRef<boolean>;
|
|
1179
|
+
/**
|
|
1180
|
+
* Emits when a named control inside the form loses focus.
|
|
1181
|
+
*
|
|
1182
|
+
* Useful for application-level workflows such as draft auto-save on blur.
|
|
1183
|
+
*/
|
|
1184
|
+
readonly fieldBlur: _angular_core.OutputEmitterRef<NgxFieldBlurEvent<T>>;
|
|
1145
1185
|
/**
|
|
1146
1186
|
* Track validation in progress to prevent circular triggering (Issue #19)
|
|
1147
1187
|
*/
|
|
@@ -1314,7 +1354,7 @@ declare class FormDirective<T extends Record<string, unknown>> {
|
|
|
1314
1354
|
* Host handler: called whenever any descendant field loses focus.
|
|
1315
1355
|
* Used to make touched-path tracking react immediately on blur/tab.
|
|
1316
1356
|
*/
|
|
1317
|
-
onFormFocusOut(): void;
|
|
1357
|
+
onFormFocusOut(event: FocusEvent): void;
|
|
1318
1358
|
/**
|
|
1319
1359
|
* Resets the form to a pristine, untouched state with optional new values.
|
|
1320
1360
|
*
|
|
@@ -1380,7 +1420,7 @@ declare class FormDirective<T extends Record<string, unknown>> {
|
|
|
1380
1420
|
*/
|
|
1381
1421
|
createAsyncValidator(field: string, validationOptions: ValidationOptions): AsyncValidatorFn;
|
|
1382
1422
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FormDirective<any>, never>;
|
|
1383
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FormDirective<any>, "form[scVestForm], form[ngxVestForm]", ["scVestForm", "ngxVestForm"], { "formValue": { "alias": "formValue"; "required": false; "isSignal": true; }; "suite": { "alias": "suite"; "required": false; "isSignal": true; }; "formShape": { "alias": "formShape"; "required": false; "isSignal": true; }; "validationConfig": { "alias": "validationConfig"; "required": false; "isSignal": true; }; }, { "formValueChange": "formValueChange"; "errorsChange": "errorsChange"; "dirtyChange": "dirtyChange"; "validChange": "validChange"; }, never, never, true, never>;
|
|
1423
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<FormDirective<any>, "form[scVestForm], form[ngxVestForm]", ["scVestForm", "ngxVestForm"], { "formValue": { "alias": "formValue"; "required": false; "isSignal": true; }; "suite": { "alias": "suite"; "required": false; "isSignal": true; }; "formShape": { "alias": "formShape"; "required": false; "isSignal": true; }; "validationConfig": { "alias": "validationConfig"; "required": false; "isSignal": true; }; }, { "formValueChange": "formValueChange"; "errorsChange": "errorsChange"; "dirtyChange": "dirtyChange"; "validChange": "validChange"; "fieldBlur": "fieldBlur"; }, never, never, true, never>;
|
|
1384
1424
|
}
|
|
1385
1425
|
|
|
1386
1426
|
/**
|
|
@@ -1473,12 +1513,16 @@ declare class ValidateRootFormDirective<T> implements AsyncValidator, AfterViewI
|
|
|
1473
1513
|
readonly ngxValidateRootForm: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
1474
1514
|
/**
|
|
1475
1515
|
* Validation mode:
|
|
1476
|
-
* - 'submit' (default): Only validates after form submission
|
|
1477
|
-
* - 'live'
|
|
1478
|
-
*
|
|
1516
|
+
* - `'submit'` (effective default): Only validates after form submission.
|
|
1517
|
+
* - `'live'`: Validates on every value change.
|
|
1518
|
+
*
|
|
1519
|
+
* Both inputs default to `undefined` so we can detect whether the consumer
|
|
1520
|
+
* set them explicitly. Precedence is `ngx ?? legacy ?? 'submit'`, which
|
|
1521
|
+
* matches the documented behavior — observable only when both attributes
|
|
1522
|
+
* are set explicitly on the same form.
|
|
1479
1523
|
*/
|
|
1480
|
-
readonly validateRootFormMode: _angular_core.InputSignal<"submit" | "live">;
|
|
1481
|
-
readonly ngxValidateRootFormMode: _angular_core.InputSignal<"submit" | "live">;
|
|
1524
|
+
readonly validateRootFormMode: _angular_core.InputSignal<"submit" | "live" | undefined>;
|
|
1525
|
+
readonly ngxValidateRootFormMode: _angular_core.InputSignal<"submit" | "live" | undefined>;
|
|
1482
1526
|
constructor();
|
|
1483
1527
|
/**
|
|
1484
1528
|
* Subscribe to form submit event using NgForm.ngSubmit EventEmitter
|
|
@@ -2302,15 +2346,6 @@ declare function getFormGroupField(rootForm: FormGroup, control: AbstractControl
|
|
|
2302
2346
|
* @param form
|
|
2303
2347
|
*/
|
|
2304
2348
|
declare function mergeValuesAndRawValues<T>(form: FormGroup): T;
|
|
2305
|
-
/**
|
|
2306
|
-
* Performs a deep-clone of an object
|
|
2307
|
-
* @param obj
|
|
2308
|
-
*
|
|
2309
|
-
* @deprecated Use official ES {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone structuredClone} instead
|
|
2310
|
-
*
|
|
2311
|
-
* Browser Support: structuredClone is available in all modern browsers (Chrome 98+, Firefox 94+, Safari 15.4+, Edge 98+)
|
|
2312
|
-
* and Node.js 17+. A polyfill is provided in test-setup.ts for Jest test environments.
|
|
2313
|
-
*/
|
|
2314
2349
|
declare function cloneDeep<T>(object: T): T;
|
|
2315
2350
|
/**
|
|
2316
2351
|
* Sets a value in an object at the provided field path.
|
|
@@ -2360,6 +2395,12 @@ type DebouncedPendingStateOptions = {
|
|
|
2360
2395
|
*/
|
|
2361
2396
|
minimumDisplay?: number;
|
|
2362
2397
|
};
|
|
2398
|
+
/**
|
|
2399
|
+
* Accepts either a static options object or a reactive `Signal` (e.g. an
|
|
2400
|
+
* `input()` accessor) so consumers can update debounce timings at runtime
|
|
2401
|
+
* without recreating the pending-state machine.
|
|
2402
|
+
*/
|
|
2403
|
+
type DebouncedPendingStateOptionsInput = DebouncedPendingStateOptions | Signal<DebouncedPendingStateOptions>;
|
|
2363
2404
|
/**
|
|
2364
2405
|
* Result of createDebouncedPendingState containing the debounced signal
|
|
2365
2406
|
* and cleanup function.
|
|
@@ -2409,7 +2450,7 @@ type DebouncedPendingStateResult = {
|
|
|
2409
2450
|
* @param options - Configuration options for debouncing behavior
|
|
2410
2451
|
* @returns Object containing the debounced showPendingMessage signal and cleanup function
|
|
2411
2452
|
*/
|
|
2412
|
-
declare function createDebouncedPendingState(isPending: Signal<boolean>, options?:
|
|
2453
|
+
declare function createDebouncedPendingState(isPending: Signal<boolean>, options?: DebouncedPendingStateOptionsInput): DebouncedPendingStateResult;
|
|
2413
2454
|
|
|
2414
2455
|
/**
|
|
2415
2456
|
* Validates a form value against a shape to catch typos in `name` or `ngModelGroup` attributes.
|
|
@@ -2500,11 +2541,13 @@ declare function shallowEqual(obj1: unknown, obj2: unknown): boolean;
|
|
|
2500
2541
|
* - Plain objects (with recursive deep comparison)
|
|
2501
2542
|
* - Date objects (by timestamp comparison)
|
|
2502
2543
|
* - RegExp objects (by source and flags comparison)
|
|
2503
|
-
* - Set objects (
|
|
2504
|
-
* - Map objects (
|
|
2544
|
+
* - Set objects (reference equality only)
|
|
2545
|
+
* - Map objects (reference equality only)
|
|
2546
|
+
* - Functions (reference equality only — distinct function instances are never equal,
|
|
2547
|
+
* even if their source code is identical)
|
|
2505
2548
|
*
|
|
2506
2549
|
* **Safety Features:**
|
|
2507
|
-
* - **Circular reference
|
|
2550
|
+
* - **Circular reference handling**: Tracks visited object pairs with `WeakMap<object, WeakSet<object>>`
|
|
2508
2551
|
* - **Type coercion prevention**: Strict type checking before comparison
|
|
2509
2552
|
* - **Null safety**: Proper handling of null and undefined values
|
|
2510
2553
|
*
|
|
@@ -2516,7 +2559,8 @@ declare function shallowEqual(obj1: unknown, obj2: unknown): boolean;
|
|
|
2516
2559
|
* ///
|
|
2517
2560
|
* /// Memory usage:
|
|
2518
2561
|
* /// JSON.stringify: Creates temporary strings (high GC pressure)
|
|
2519
|
-
* /// fastDeepEqual:
|
|
2562
|
+
* /// fastDeepEqual: One small WeakMap of visited object pairs is allocated lazily on
|
|
2563
|
+
* /// first nested-container descent; primitive-only comparisons allocate nothing.
|
|
2520
2564
|
* ```
|
|
2521
2565
|
*
|
|
2522
2566
|
* **Typical Usage in Forms:**
|
|
@@ -2532,10 +2576,15 @@ declare function shallowEqual(obj1: unknown, obj2: unknown): boolean;
|
|
|
2532
2576
|
*
|
|
2533
2577
|
* @param obj1 - First object to compare
|
|
2534
2578
|
* @param obj2 - Second object to compare
|
|
2535
|
-
*
|
|
2579
|
+
*
|
|
2580
|
+
* Cyclic arrays and plain objects are compared structurally by tracking visited object
|
|
2581
|
+
* pairs. Distinct cyclic graphs with the same structure compare equal. `Date` and
|
|
2582
|
+
* `RegExp` values compare structurally. `Map` and `Set` values compare by reference
|
|
2583
|
+
* only, so distinct instances are considered different even if their contents match.
|
|
2584
|
+
*
|
|
2536
2585
|
* @returns true if objects are deeply equal by value
|
|
2537
2586
|
*/
|
|
2538
|
-
declare function fastDeepEqual(obj1: unknown, obj2: unknown
|
|
2587
|
+
declare function fastDeepEqual(obj1: unknown, obj2: unknown): boolean;
|
|
2539
2588
|
|
|
2540
2589
|
/**
|
|
2541
2590
|
* @deprecated Use NGX_ERROR_DISPLAY_MODE_TOKEN instead
|
|
@@ -2607,5 +2656,46 @@ declare const NGX_WARNING_DISPLAY_MODE_TOKEN: InjectionToken<NgxWarningDisplayMo
|
|
|
2607
2656
|
*/
|
|
2608
2657
|
declare const NGX_VALIDATION_CONFIG_DEBOUNCE_TOKEN: InjectionToken<number>;
|
|
2609
2658
|
|
|
2610
|
-
|
|
2611
|
-
|
|
2659
|
+
/**
|
|
2660
|
+
* Signature of a deep-equality comparator. Must return `true` iff `a` and `b`
|
|
2661
|
+
* are considered equal for the purpose of change detection.
|
|
2662
|
+
*/
|
|
2663
|
+
type NgxEqualityFn = (a: unknown, b: unknown) => boolean;
|
|
2664
|
+
/**
|
|
2665
|
+
* Injection token for the deep-equality function used internally by
|
|
2666
|
+
* {@link FormDirective} for change detection — `formValueChange`
|
|
2667
|
+
* `distinctUntilChanged`, the form↔model two-way sync effect, and the
|
|
2668
|
+
* `formState` signal's structural comparator.
|
|
2669
|
+
*
|
|
2670
|
+
* The default factory returns {@link fastDeepEqual}. Override this token to
|
|
2671
|
+
* plug in a smaller or differently-tuned comparator (e.g. `dequal/lite`,
|
|
2672
|
+
* `lodash.isEqual`) without forking the directive.
|
|
2673
|
+
*
|
|
2674
|
+
* @example Bring-your-own equality at the application level
|
|
2675
|
+
* ```ts
|
|
2676
|
+
* import { dequal } from 'dequal/lite';
|
|
2677
|
+
* import { NGX_EQUALITY_FN } from 'ngx-vest-forms';
|
|
2678
|
+
*
|
|
2679
|
+
* export const appConfig: ApplicationConfig = {
|
|
2680
|
+
* providers: [
|
|
2681
|
+
* { provide: NGX_EQUALITY_FN, useValue: dequal },
|
|
2682
|
+
* ],
|
|
2683
|
+
* };
|
|
2684
|
+
* ```
|
|
2685
|
+
*
|
|
2686
|
+
* @example Per-component override (e.g. for tests)
|
|
2687
|
+
* ```ts
|
|
2688
|
+
* @Component({
|
|
2689
|
+
* providers: [
|
|
2690
|
+
* { provide: NGX_EQUALITY_FN, useValue: (a, b) => a === b },
|
|
2691
|
+
* ],
|
|
2692
|
+
* })
|
|
2693
|
+
* export class TestFormComponent {}
|
|
2694
|
+
* ```
|
|
2695
|
+
*
|
|
2696
|
+
* @default {@link fastDeepEqual}
|
|
2697
|
+
*/
|
|
2698
|
+
declare const NGX_EQUALITY_FN: InjectionToken<NgxEqualityFn>;
|
|
2699
|
+
|
|
2700
|
+
export { ControlWrapperComponent, DEFAULT_FOCUS_SELECTOR, DEFAULT_INVALID_SELECTOR, FormControlStateDirective, FormDirective, FormErrorControlDirective, FormErrorDisplayDirective, FormGroupWrapperComponent, FormModelDirective, FormModelGroupDirective, NGX_EQUALITY_FN, NGX_ERROR_DISPLAY_MODE_TOKEN, NGX_VALIDATION_CONFIG_DEBOUNCE_TOKEN, NGX_WARNING_DISPLAY_MODE_TOKEN, NgxVestForms, ROOT_FORM, ROOT_FORM as ROOT_FORM_CONSTANT, SC_ERROR_DISPLAY_MODE_TOKEN, ValidateRootFormDirective, ValidationConfigBuilder, arrayToObject, clearFields, clearFieldsWhen, cloneDeep, createDebouncedPendingState, createEmptyFormState, createValidationConfig, deepArrayToObject, fastDeepEqual, getAllFormErrors, getFormControlField, getFormGroupField, keepFieldsWhen, mergeAriaDescribedBy, mergeValuesAndRawValues, objectToArray, parseAriaIdTokens, parseFieldPath, resolveAssociationTargets, set, setValueAtPath, shallowEqual, stringifyFieldPath, validateShape, vestForms, vestFormsViewProviders };
|
|
2701
|
+
export type { AriaAssociationMode, DebouncedPendingStateOptions, DebouncedPendingStateOptionsInput, DebouncedPendingStateResult, DeepPartial, DeepRequired, FieldPath, FieldPathValue, FormCompatibleDeepRequired, FormFieldName, LeafFieldPath, NgxDeepPartial, NgxDeepRequired, NgxEqualityFn, NgxFieldBlurEvent, NgxFieldKey, NgxFirstInvalidOptions, NgxFormCompatibleDeepRequired, NgxFormState, NgxTypedVestSuite, NgxValidationConfig, NgxVestSuite, NgxWarningDisplayMode, ScErrorDisplayMode, ValidateFieldPath, ValidationConfigMap, ValidationOptions };
|