@bolttech/form-engine-core 0.0.1-beta.6 → 0.0.1-beta.8
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/index.esm.js +90 -119
- package/package.json +1 -1
- package/src/constants/constants.d.ts +3 -0
- package/src/interfaces/state.d.ts +1 -6
- package/src/managers/field.d.ts +9 -35
- package/src/managers/form.d.ts +14 -18
- package/src/managers/formGroup.d.ts +1 -1
- package/src/types/form.d.ts +9 -9
package/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Subscription, Subject, combineLatest, startWith,
|
|
1
|
+
import { Subscription, Subject, combineLatest, startWith, groupBy, mergeMap, debounceTime, filter, map } from 'rxjs';
|
|
2
2
|
import creditCardType from 'credit-card-type';
|
|
3
3
|
import { isNumber as isNumber$1, isNil, isEqual, get, set } from 'lodash';
|
|
4
4
|
import { getCurrencySymbol } from '@gaignoux/currency';
|
|
@@ -2256,6 +2256,9 @@ const validations = {
|
|
|
2256
2256
|
validDate
|
|
2257
2257
|
};
|
|
2258
2258
|
|
|
2259
|
+
const DEFAULT_API_DEBOUNCE_TIME = 1000;
|
|
2260
|
+
const DEFAULT_STATE_REFRESH_TIME = 100;
|
|
2261
|
+
|
|
2259
2262
|
/**
|
|
2260
2263
|
* Represents a form field with observables for managing form state, validations, and API requests.
|
|
2261
2264
|
*/
|
|
@@ -2288,9 +2291,10 @@ class FormField {
|
|
|
2288
2291
|
}) {
|
|
2289
2292
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
2290
2293
|
this.fieldStateSubscription$ = new Subscription();
|
|
2294
|
+
this.originalSchema = schemaComponent;
|
|
2291
2295
|
this.config = {
|
|
2292
|
-
defaultAPIdebounceTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultAPIdebounceTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultAPIdebounceTimeMS) :
|
|
2293
|
-
defaultStateRefreshTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) :
|
|
2296
|
+
defaultAPIdebounceTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultAPIdebounceTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultAPIdebounceTimeMS) : DEFAULT_API_DEBOUNCE_TIME,
|
|
2297
|
+
defaultStateRefreshTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) : DEFAULT_STATE_REFRESH_TIME
|
|
2294
2298
|
};
|
|
2295
2299
|
this.name = schemaComponent.name;
|
|
2296
2300
|
this.component = schemaComponent.component;
|
|
@@ -2305,7 +2309,6 @@ class FormField {
|
|
|
2305
2309
|
this.masks = schemaComponent.masks;
|
|
2306
2310
|
if (mapper.valueChangeEvent) this.valueChangeEvent = mapper.valueChangeEvent;
|
|
2307
2311
|
if ((_a = mapper.events) === null || _a === void 0 ? void 0 : _a.setValue) this.valuePropName = mapper.events.setValue;
|
|
2308
|
-
if ((_b = mapper.events) === null || _b === void 0 ? void 0 : _b.setErrorMessage) this.errorMessagePropName = mapper.events.setErrorMessage;
|
|
2309
2312
|
this.mapper = mapper;
|
|
2310
2313
|
this.validateVisibility = validateVisibility;
|
|
2311
2314
|
this.resetValue = resetValue;
|
|
@@ -2314,8 +2317,12 @@ class FormField {
|
|
|
2314
2317
|
this.dataSubject$ = dataSubject$;
|
|
2315
2318
|
this._props = schemaComponent.props || {};
|
|
2316
2319
|
this._value = '';
|
|
2317
|
-
this._stateValue =
|
|
2320
|
+
this._stateValue = ((_b = this.mapper.events) === null || _b === void 0 ? void 0 : _b.setValue) ? {
|
|
2321
|
+
[this.mapper.events.setValue]: ''
|
|
2322
|
+
} : {};
|
|
2318
2323
|
this._metadata = '';
|
|
2324
|
+
this.errorsString = '';
|
|
2325
|
+
this.errorsList = [];
|
|
2319
2326
|
this.initialValue = initialValue;
|
|
2320
2327
|
this._visibility = true;
|
|
2321
2328
|
this._api = {
|
|
@@ -2331,7 +2338,6 @@ class FormField {
|
|
|
2331
2338
|
}, {})
|
|
2332
2339
|
};
|
|
2333
2340
|
this._errors = {};
|
|
2334
|
-
this._errorsString = '';
|
|
2335
2341
|
this._valid = false;
|
|
2336
2342
|
this.initializeObservers();
|
|
2337
2343
|
}
|
|
@@ -2362,33 +2368,21 @@ class FormField {
|
|
|
2362
2368
|
this.apiEventQueueSubject$ = new Subject();
|
|
2363
2369
|
}
|
|
2364
2370
|
this.fieldState$ = combineLatest({
|
|
2365
|
-
errors: this.errorSubject$.pipe(startWith([])),
|
|
2366
2371
|
visibility: this.visibilitySubject$.pipe(startWith(this._visibility)),
|
|
2367
|
-
|
|
2368
|
-
|
|
2372
|
+
props: this.propsSubject$.pipe(startWith(this._props)),
|
|
2373
|
+
errors: this.errorSubject$.pipe(startWith(Object.assign({}, ((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setErrorMessage) && {
|
|
2374
|
+
[this.mapper.events.setErrorMessage]: this.errorsString
|
|
2375
|
+
})))
|
|
2369
2376
|
});
|
|
2370
|
-
!this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(
|
|
2377
|
+
!this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(groupBy(({
|
|
2371
2378
|
event
|
|
2372
|
-
}) => event, (
|
|
2379
|
+
}) => event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultAPIdebounceTimeMS))), filter(() => this.apiSubject$ && !this.apiSubject$.closed)).subscribe(payload => {
|
|
2373
2380
|
this.apiRequest(payload);
|
|
2374
2381
|
});
|
|
2375
2382
|
if (!isNil(this.initialValue)) {
|
|
2376
2383
|
this.value = this.initialValue;
|
|
2377
2384
|
}
|
|
2378
2385
|
}
|
|
2379
|
-
/**
|
|
2380
|
-
* Observable function to emit api events debounced and distinct for each event type,
|
|
2381
|
-
* avoiding previous events being cancelled by new events if they occur inside the debounce time interval
|
|
2382
|
-
*
|
|
2383
|
-
* @param {(event: { event: TEvents }) => TEvents} keyExtractor function that will pass the event key to the groupBy operator
|
|
2384
|
-
* @param {number} debounceTimeMs time to wait for each individual event emmited
|
|
2385
|
-
* @returns
|
|
2386
|
-
*/
|
|
2387
|
-
debounceDistinct(keyExtractor, debounceTimeMs) {
|
|
2388
|
-
return source$ => source$.pipe(groupBy(keyExtractor), mergeMap(group$ => group$.pipe(debounceTime(debounceTimeMs), map(() => ({
|
|
2389
|
-
event: group$.key
|
|
2390
|
-
})))));
|
|
2391
|
-
}
|
|
2392
2386
|
/**
|
|
2393
2387
|
* Retrieves the properties associated with the form field.
|
|
2394
2388
|
*
|
|
@@ -2414,7 +2408,7 @@ class FormField {
|
|
|
2414
2408
|
/**
|
|
2415
2409
|
* Retrieves the current state value of the form field.
|
|
2416
2410
|
*
|
|
2417
|
-
* @returns {unknown} - The current state value of the form field.
|
|
2411
|
+
* @returns {Record<string,unknown>} - The current state value of the form field.
|
|
2418
2412
|
*/
|
|
2419
2413
|
get stateValue() {
|
|
2420
2414
|
return this._stateValue;
|
|
@@ -2422,14 +2416,6 @@ class FormField {
|
|
|
2422
2416
|
get metadata() {
|
|
2423
2417
|
return this._metadata;
|
|
2424
2418
|
}
|
|
2425
|
-
/**
|
|
2426
|
-
* Retrieves the concatenated string of errors associated with the form field.
|
|
2427
|
-
*
|
|
2428
|
-
* @returns {string} - The concatenated string of errors.
|
|
2429
|
-
*/
|
|
2430
|
-
get errorsString() {
|
|
2431
|
-
return this._errorsString;
|
|
2432
|
-
}
|
|
2433
2419
|
/**
|
|
2434
2420
|
* Retrieves the current value of the form field.
|
|
2435
2421
|
*
|
|
@@ -2444,6 +2430,7 @@ class FormField {
|
|
|
2444
2430
|
* @param {unknown} value - The new value to be set.
|
|
2445
2431
|
*/
|
|
2446
2432
|
set value(value) {
|
|
2433
|
+
var _a, _b, _c;
|
|
2447
2434
|
/*
|
|
2448
2435
|
too much unstable, if the valueChangeEvent parses the template event
|
|
2449
2436
|
value, might occur unexpected results
|
|
@@ -2463,22 +2450,19 @@ class FormField {
|
|
|
2463
2450
|
if (typeof val === 'undefined' || val === null) return;
|
|
2464
2451
|
if (typeof val === 'object' && '_value' in val && '_metadata' in val) {
|
|
2465
2452
|
this._value = this.formatValue(val['_value']);
|
|
2466
|
-
this._stateValue =
|
|
2453
|
+
this._stateValue = ((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setValue) ? {
|
|
2454
|
+
[this.mapper.events.setValue]: this.maskValue(this.formatValue(val['_value']))
|
|
2455
|
+
} : {};
|
|
2467
2456
|
this._metadata = val._metadata;
|
|
2468
2457
|
} else {
|
|
2469
2458
|
this._value = this.formatValue(val);
|
|
2470
|
-
this._stateValue =
|
|
2459
|
+
this._stateValue = ((_b = this.mapper.events) === null || _b === void 0 ? void 0 : _b.setValue) ? {
|
|
2460
|
+
[(_c = this.mapper.events) === null || _c === void 0 ? void 0 : _c.setValue]: this.maskValue(this.formatValue(val))
|
|
2461
|
+
} : {};
|
|
2462
|
+
this.maskValue(this.formatValue(val));
|
|
2471
2463
|
this._metadata = val;
|
|
2472
2464
|
}
|
|
2473
|
-
|
|
2474
|
-
update prop value attribute to sync with templating
|
|
2475
|
-
currently doesn't need prop Subject emission since it's synced with value
|
|
2476
|
-
to avoid excessive prop subject emissions on each keystroke
|
|
2477
|
-
*/
|
|
2478
|
-
if (this.valuePropName) this._props = Object.assign(Object.assign({}, this.props), {
|
|
2479
|
-
[this.valuePropName]: this.value
|
|
2480
|
-
});
|
|
2481
|
-
this.valueSubject$.next(this._stateValue);
|
|
2465
|
+
this.stateValue && this.valueSubject$.next(this.stateValue);
|
|
2482
2466
|
this.templateSubject$.next({
|
|
2483
2467
|
key: this.name,
|
|
2484
2468
|
event: 'ON_VALUE'
|
|
@@ -2528,10 +2512,17 @@ class FormField {
|
|
|
2528
2512
|
* @param {TErrorMessages} errors - The new error messages to be set.
|
|
2529
2513
|
*/
|
|
2530
2514
|
set errors(errors) {
|
|
2515
|
+
var _a;
|
|
2531
2516
|
if (typeof errors === 'undefined' || isEqual(errors, this.errors)) return;
|
|
2532
2517
|
this._errors = errors;
|
|
2533
|
-
this.
|
|
2534
|
-
this.
|
|
2518
|
+
this.errorsList = Object.values(this.errors);
|
|
2519
|
+
this.errorsString = this.errorsList.join(', ');
|
|
2520
|
+
/**
|
|
2521
|
+
* if any error receieves a list of errors, set a prop for it, currently only supporting a single string
|
|
2522
|
+
*/
|
|
2523
|
+
((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setErrorMessage) && this.errorSubject$.next({
|
|
2524
|
+
[this.mapper.events.setErrorMessage]: this.errorsString
|
|
2525
|
+
});
|
|
2535
2526
|
this.templateSubject$.next({
|
|
2536
2527
|
key: this.name,
|
|
2537
2528
|
event: 'ON_PROPS'
|
|
@@ -2567,11 +2558,8 @@ class FormField {
|
|
|
2567
2558
|
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
2568
2559
|
*
|
|
2569
2560
|
* @param {object} mountOpts - Adapter mount options.
|
|
2570
|
-
* @param {string} prop.valuePropName - Adapter value property name.
|
|
2571
|
-
* @param {(event: unknown) => unknown} prop.valueChangeEvent - Adapter change event handler function
|
|
2572
2561
|
* @param {(value: unknown) => unknown} prop.valueSubscription - Adapter value change function
|
|
2573
2562
|
* @param {(payload: Partial<IState>) => unknown} prop.propsSubscription - Adapter prop change function
|
|
2574
|
-
* @param {string} prop.errorMessagePropName - error message property name to set errors onto component
|
|
2575
2563
|
* @returns {void}
|
|
2576
2564
|
*/
|
|
2577
2565
|
mountField({
|
|
@@ -2667,10 +2655,6 @@ class FormField {
|
|
|
2667
2655
|
});
|
|
2668
2656
|
this._valid = valid;
|
|
2669
2657
|
this.errors = errors;
|
|
2670
|
-
// remove later
|
|
2671
|
-
if (this.errorMessagePropName) this.props = Object.assign(Object.assign({}, this.props), {
|
|
2672
|
-
[this.errorMessagePropName]: this.errorsString
|
|
2673
|
-
});
|
|
2674
2658
|
}
|
|
2675
2659
|
/**
|
|
2676
2660
|
* WIP expensive function to get updated field validity on each event
|
|
@@ -2863,7 +2847,7 @@ class FormCore {
|
|
|
2863
2847
|
* @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
|
|
2864
2848
|
*/
|
|
2865
2849
|
constructor(entry) {
|
|
2866
|
-
var _a, _b, _c, _d;
|
|
2850
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2867
2851
|
this.schema = entry.schema;
|
|
2868
2852
|
this.fields = new Map();
|
|
2869
2853
|
this.initialValues = entry.initialValues || ((_a = entry.schema) === null || _a === void 0 ? void 0 : _a.initialValues);
|
|
@@ -2871,7 +2855,10 @@ class FormCore {
|
|
|
2871
2855
|
this.method = entry.method || ((_c = entry.schema) === null || _c === void 0 ? void 0 : _c.method);
|
|
2872
2856
|
this._iVars = entry.iVars || ((_d = entry.schema) === null || _d === void 0 ? void 0 : _d.iVars) || {};
|
|
2873
2857
|
this.onSubmit = entry.onSubmit;
|
|
2874
|
-
this.config =
|
|
2858
|
+
this.config = {
|
|
2859
|
+
defaultAPIdebounceTimeMS: Number((_e = entry.config) === null || _e === void 0 ? void 0 : _e.defaultAPIdebounceTimeMS) ? Number((_f = entry.config) === null || _f === void 0 ? void 0 : _f.defaultAPIdebounceTimeMS) : DEFAULT_API_DEBOUNCE_TIME,
|
|
2860
|
+
defaultStateRefreshTimeMS: Number((_g = entry.config) === null || _g === void 0 ? void 0 : _g.defaultStateRefreshTimeMS) ? Number((_h = entry.config) === null || _h === void 0 ? void 0 : _h.defaultStateRefreshTimeMS) : DEFAULT_STATE_REFRESH_TIME
|
|
2861
|
+
};
|
|
2875
2862
|
this.mappers = entry.mappers;
|
|
2876
2863
|
this.schema && FormCore.checkIndexes(this.schema.components);
|
|
2877
2864
|
this.templateSubject$ = new Subject();
|
|
@@ -2887,7 +2874,6 @@ class FormCore {
|
|
|
2887
2874
|
key: IVARPROPNAME,
|
|
2888
2875
|
event: 'ON_IVARS'
|
|
2889
2876
|
});
|
|
2890
|
-
// this.fieldEventsSubject$.subscribe(this.refreshApi.bind(this));
|
|
2891
2877
|
entry.onData && this.subscribeData(entry.onData);
|
|
2892
2878
|
/*
|
|
2893
2879
|
mount events needs to occur on form level, only when all the fields are instantiated
|
|
@@ -2939,20 +2925,18 @@ class FormCore {
|
|
|
2939
2925
|
* Subscribes to templates for dynamic updates.
|
|
2940
2926
|
*/
|
|
2941
2927
|
subscribeTemplates() {
|
|
2942
|
-
|
|
2943
|
-
@TODO fix removal of templates of removed fields, they are kept
|
|
2944
|
-
tried: this.subscribedTemplates = [] and only stores the last one..
|
|
2945
|
-
*/
|
|
2928
|
+
this.subscribedTemplates = [];
|
|
2946
2929
|
this.fields.forEach(({
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2930
|
+
originalSchema: {
|
|
2931
|
+
component,
|
|
2932
|
+
props,
|
|
2933
|
+
name,
|
|
2934
|
+
validations,
|
|
2935
|
+
visibilityConditions,
|
|
2936
|
+
resetValues,
|
|
2937
|
+
errorMessages,
|
|
2938
|
+
api
|
|
2939
|
+
}
|
|
2956
2940
|
}, key) => {
|
|
2957
2941
|
const template = {
|
|
2958
2942
|
component,
|
|
@@ -2962,20 +2946,17 @@ class FormCore {
|
|
|
2962
2946
|
visibilityConditions,
|
|
2963
2947
|
resetValues,
|
|
2964
2948
|
errorMessages,
|
|
2965
|
-
apiSchema
|
|
2966
|
-
metadata
|
|
2949
|
+
apiSchema: api
|
|
2967
2950
|
};
|
|
2968
2951
|
traverseObject(template, key).forEach(element => this.subscribedTemplates.push(element));
|
|
2969
2952
|
});
|
|
2970
|
-
// console.log(subscribedProps);
|
|
2971
2953
|
}
|
|
2972
2954
|
/**
|
|
2973
2955
|
*
|
|
2974
2956
|
* @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
|
|
2975
2957
|
*/
|
|
2976
2958
|
subscribeData(callback) {
|
|
2977
|
-
|
|
2978
|
-
this.dataCallbackSubscription$ = this.dataSubject$.pipe(debounceTime(Number((_a = this.config) === null || _a === void 0 ? void 0 : _a.defaultStateRefreshTimeMS) ? Number((_b = this.config) === null || _b === void 0 ? void 0 : _b.defaultStateRefreshTimeMS) : 100), map(({
|
|
2959
|
+
this.dataCallbackSubscription$ = this.dataSubject$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS), map(({
|
|
2979
2960
|
key
|
|
2980
2961
|
}) => ({
|
|
2981
2962
|
field: key,
|
|
@@ -3002,8 +2983,12 @@ class FormCore {
|
|
|
3002
2983
|
const value = get(this.iVars, [property, ...path]);
|
|
3003
2984
|
return value;
|
|
3004
2985
|
}
|
|
3005
|
-
|
|
3006
|
-
return
|
|
2986
|
+
const field = this.fields.get(key);
|
|
2987
|
+
if (!field) return console.warn(`failed to get value from ${key}`);
|
|
2988
|
+
if (property === 'props' && path[0] === field.valuePropName) {
|
|
2989
|
+
return field.stateValue;
|
|
2990
|
+
}
|
|
2991
|
+
return path.length > 0 ? get(field[property], path) : field[property];
|
|
3007
2992
|
}
|
|
3008
2993
|
/**
|
|
3009
2994
|
* Sets the value of a property in a field.
|
|
@@ -3036,7 +3021,6 @@ class FormCore {
|
|
|
3036
3021
|
now using key !== originKey, check if any recursion error occurs
|
|
3037
3022
|
**/
|
|
3038
3023
|
if (property === 'props' && path[0] === field.valuePropName && key !== originKey) {
|
|
3039
|
-
// field.value = value;
|
|
3040
3024
|
field.emitValue({
|
|
3041
3025
|
event: 'ON_FIELD_CHANGE',
|
|
3042
3026
|
value
|
|
@@ -3076,7 +3060,6 @@ class FormCore {
|
|
|
3076
3060
|
const operatorRegex = /\s*(\|\||&&|!)\s*/g;
|
|
3077
3061
|
const splittedString = extractedValues.map(el => el.split(operatorRegex));
|
|
3078
3062
|
const result = splittedString.map(splittedStringVal => {
|
|
3079
|
-
// console.log(splittedStringVal)
|
|
3080
3063
|
return splittedStringVal.filter(Boolean).reduce((acc, curr) => {
|
|
3081
3064
|
if (curr.match(/^\|\||&&|!$/)) {
|
|
3082
3065
|
return `${acc}${curr}`;
|
|
@@ -3120,7 +3103,6 @@ class FormCore {
|
|
|
3120
3103
|
});
|
|
3121
3104
|
return result.map(el => {
|
|
3122
3105
|
try {
|
|
3123
|
-
// console.log(el);
|
|
3124
3106
|
return new Function(`return ${el}`)();
|
|
3125
3107
|
} catch (e) {
|
|
3126
3108
|
console.log(e);
|
|
@@ -3193,34 +3175,6 @@ class FormCore {
|
|
|
3193
3175
|
}
|
|
3194
3176
|
});
|
|
3195
3177
|
}
|
|
3196
|
-
/**
|
|
3197
|
-
* Refreshes api observed fields.
|
|
3198
|
-
*
|
|
3199
|
-
* @param {object} options - Options for refreshing api.
|
|
3200
|
-
* @param {string} options.key - The key of the field triggering the update.
|
|
3201
|
-
*/
|
|
3202
|
-
refreshApi({
|
|
3203
|
-
key
|
|
3204
|
-
}) {
|
|
3205
|
-
/*
|
|
3206
|
-
global api notifications needs to have field dependency array
|
|
3207
|
-
in order to be reliable, disabled for now
|
|
3208
|
-
*/
|
|
3209
|
-
return key;
|
|
3210
|
-
// const emmittedFields: string[] = [];
|
|
3211
|
-
// this.subscribedTemplates.forEach((template) => {
|
|
3212
|
-
// if (
|
|
3213
|
-
// template.originFieldKeys.includes(key) &&
|
|
3214
|
-
// template.originPropertyKeys.includes('api') &&
|
|
3215
|
-
// !emmittedFields.includes(template.destinationKey)
|
|
3216
|
-
// ) {
|
|
3217
|
-
// emmittedFields.push(template.destinationKey);
|
|
3218
|
-
// this.fields
|
|
3219
|
-
// .get(template.destinationKey)
|
|
3220
|
-
// ?.emitEvents({ event: 'ON_API_RESPONSE' });
|
|
3221
|
-
// }
|
|
3222
|
-
// });
|
|
3223
|
-
}
|
|
3224
3178
|
/**
|
|
3225
3179
|
* Validates visibility conditions for a given event and updates field visibility accordingly.
|
|
3226
3180
|
*
|
|
@@ -3291,20 +3245,23 @@ class FormCore {
|
|
|
3291
3245
|
*
|
|
3292
3246
|
* @param fieldSchema
|
|
3293
3247
|
*/
|
|
3294
|
-
addField(
|
|
3295
|
-
|
|
3248
|
+
addField({
|
|
3249
|
+
fieldSchema,
|
|
3250
|
+
mapperElement
|
|
3251
|
+
}) {
|
|
3252
|
+
var _a, _b, _c;
|
|
3296
3253
|
if (this.fields.has(fieldSchema.name)) {
|
|
3297
3254
|
throw new Error(`field name ${fieldSchema.name} already defined`);
|
|
3298
3255
|
}
|
|
3299
|
-
const
|
|
3300
|
-
if (!
|
|
3256
|
+
const mapper = mapperElement || ((_a = this.mappers) === null || _a === void 0 ? void 0 : _a.find(mapEl => mapEl.componentName === fieldSchema.component));
|
|
3257
|
+
if (!mapper) throw new Error(`mapper not found for ${fieldSchema.component}, add it to the mappers configuration`);
|
|
3301
3258
|
this.fields.set(fieldSchema.name, new FormField({
|
|
3302
3259
|
schemaComponent: fieldSchema,
|
|
3303
|
-
mapper
|
|
3260
|
+
mapper,
|
|
3304
3261
|
children: fieldSchema.children ? fieldSchema.children.map(el => el.name) : [],
|
|
3305
3262
|
validateVisibility: this.validateVisibility.bind(this),
|
|
3306
3263
|
resetValue: this.resetValue.bind(this),
|
|
3307
|
-
initialValue: (
|
|
3264
|
+
initialValue: (_b = this.initialValues) === null || _b === void 0 ? void 0 : _b[fieldSchema.name],
|
|
3308
3265
|
templateSubject$: this.templateSubject$,
|
|
3309
3266
|
fieldEventSubject$: this.fieldEventSubject$,
|
|
3310
3267
|
dataSubject$: this.dataSubject$,
|
|
@@ -3315,6 +3272,21 @@ class FormCore {
|
|
|
3315
3272
|
event: 'ON_FIELDS',
|
|
3316
3273
|
key: fieldSchema.name
|
|
3317
3274
|
});
|
|
3275
|
+
(_c = this.fields.get(fieldSchema.name)) === null || _c === void 0 ? void 0 : _c.emitEvents({
|
|
3276
|
+
event: 'ON_FIELD_MOUNT'
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
3279
|
+
removeField({
|
|
3280
|
+
key
|
|
3281
|
+
}) {
|
|
3282
|
+
var _a;
|
|
3283
|
+
(_a = this.fields.get(key)) === null || _a === void 0 ? void 0 : _a.destroyField();
|
|
3284
|
+
this.fields.delete(key);
|
|
3285
|
+
this.subscribeTemplates();
|
|
3286
|
+
this.templateSubject$.next({
|
|
3287
|
+
key,
|
|
3288
|
+
event: 'ON_FIELDS'
|
|
3289
|
+
});
|
|
3318
3290
|
}
|
|
3319
3291
|
/**
|
|
3320
3292
|
* Serializes the schema structure to create form fields.
|
|
@@ -3325,10 +3297,10 @@ class FormCore {
|
|
|
3325
3297
|
serializeStructure(struct, path) {
|
|
3326
3298
|
if (!struct) return;
|
|
3327
3299
|
struct.forEach(structElement => {
|
|
3328
|
-
var _a, _b;
|
|
3300
|
+
var _a, _b, _c;
|
|
3329
3301
|
const currField = this.fields.get(structElement.name);
|
|
3330
3302
|
if (!currField) {
|
|
3331
|
-
const mapper = this.mappers.find(mapEl => mapEl.componentName === structElement.component);
|
|
3303
|
+
const mapper = (_a = this.mappers) === null || _a === void 0 ? void 0 : _a.find(mapEl => mapEl.componentName === structElement.component);
|
|
3332
3304
|
if (!mapper) throw new Error(`mapper not found for ${structElement.component}, add it to the mappers configuration`);
|
|
3333
3305
|
this.fields.set(structElement.name, new FormField({
|
|
3334
3306
|
schemaComponent: structElement,
|
|
@@ -3337,14 +3309,14 @@ class FormCore {
|
|
|
3337
3309
|
children: structElement.children ? structElement.children.map(el => el.name) : [],
|
|
3338
3310
|
validateVisibility: this.validateVisibility.bind(this),
|
|
3339
3311
|
resetValue: this.resetValue.bind(this),
|
|
3340
|
-
initialValue: (
|
|
3312
|
+
initialValue: (_b = this.initialValues) === null || _b === void 0 ? void 0 : _b[structElement.name],
|
|
3341
3313
|
templateSubject$: this.templateSubject$,
|
|
3342
3314
|
fieldEventSubject$: this.fieldEventSubject$,
|
|
3343
3315
|
dataSubject$: this.dataSubject$,
|
|
3344
3316
|
config: this.config
|
|
3345
3317
|
}));
|
|
3346
3318
|
} else {
|
|
3347
|
-
currField.children = ((
|
|
3319
|
+
currField.children = ((_c = structElement === null || structElement === void 0 ? void 0 : structElement.children) === null || _c === void 0 ? void 0 : _c.map(el => el.name)) || (currField === null || currField === void 0 ? void 0 : currField.children) || [];
|
|
3348
3320
|
currField.path = path;
|
|
3349
3321
|
currField.templateSubject$ = this.templateSubject$;
|
|
3350
3322
|
}
|
|
@@ -3434,10 +3406,9 @@ class FormCore {
|
|
|
3434
3406
|
};
|
|
3435
3407
|
}
|
|
3436
3408
|
subscribeFieldEvent({
|
|
3437
|
-
event,
|
|
3438
3409
|
callback
|
|
3439
3410
|
}) {
|
|
3440
|
-
const sub = this.fieldEventSubject$.pipe(
|
|
3411
|
+
const sub = this.fieldEventSubject$.pipe(groupBy(payload => payload.event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS)))).subscribe({
|
|
3441
3412
|
next: callback
|
|
3442
3413
|
});
|
|
3443
3414
|
return sub;
|
package/package.json
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
|
-
import { TApiResponse } from '../types/schema';
|
|
2
1
|
/**
|
|
3
2
|
* @interface IState
|
|
4
3
|
* Represents the state of a form component.
|
|
5
4
|
*
|
|
6
5
|
* @property {string[]} errors - The list of error messages.
|
|
7
6
|
* @property {boolean} visibility - The visibility state of the component.
|
|
8
|
-
* @property {TApiResponse} apiResponse - The API response data.
|
|
9
7
|
* @property {Record<string, unknown>} props - The properties of the component.
|
|
10
8
|
*
|
|
11
9
|
* @example
|
|
12
10
|
* ```typescript
|
|
13
11
|
* const state: IState = {
|
|
14
|
-
* errors: ['This field is required.'],
|
|
15
12
|
* visibility: true,
|
|
16
|
-
* apiResponse: { default: { response: null } },
|
|
17
13
|
* props: { type: 'text', value: 'John' }
|
|
18
14
|
* };
|
|
19
15
|
* ```
|
|
20
16
|
*/
|
|
21
17
|
interface IState {
|
|
22
|
-
errors: string[];
|
|
23
18
|
visibility: boolean;
|
|
24
|
-
apiResponse: TApiResponse;
|
|
25
19
|
props: Record<string, unknown>;
|
|
20
|
+
errors: Record<string, unknown>;
|
|
26
21
|
}
|
|
27
22
|
export { IState };
|
package/src/managers/field.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ declare class FormField {
|
|
|
12
12
|
component: string;
|
|
13
13
|
path?: string;
|
|
14
14
|
children?: string[];
|
|
15
|
+
originalSchema: IComponentSchema;
|
|
15
16
|
validations?: TEvent<TValidationMethods>;
|
|
16
17
|
visibilityConditions?: TVisibility[];
|
|
17
18
|
resetValues?: TResetValueMethods[];
|
|
@@ -20,22 +21,22 @@ declare class FormField {
|
|
|
20
21
|
formatters?: TFormatters;
|
|
21
22
|
masks?: TMasks;
|
|
22
23
|
valuePropName?: string;
|
|
23
|
-
errorMessagePropName?: string;
|
|
24
24
|
initialValue?: unknown;
|
|
25
25
|
config: Required<TSchemaFormConfig>;
|
|
26
26
|
mapper: TMapper<unknown>;
|
|
27
|
+
errorsString: string;
|
|
28
|
+
errorsList: string[];
|
|
27
29
|
private _props;
|
|
28
30
|
private _value;
|
|
29
31
|
private _stateValue;
|
|
30
32
|
private _metadata;
|
|
31
33
|
private _visibility;
|
|
32
34
|
private _errors;
|
|
33
|
-
private _errorsString;
|
|
34
35
|
private _api;
|
|
35
36
|
private _valid;
|
|
36
37
|
propsSubject$: Subject<Record<string, unknown>>;
|
|
37
|
-
errorSubject$: Subject<string
|
|
38
|
-
valueSubject$: Subject<unknown
|
|
38
|
+
errorSubject$: Subject<Record<string, unknown>>;
|
|
39
|
+
valueSubject$: Subject<Record<string, unknown>>;
|
|
39
40
|
visibilitySubject$: Subject<boolean>;
|
|
40
41
|
apiSubject$: Subject<TApiResponse>;
|
|
41
42
|
fieldEventSubject$: Subject<TFieldEvent>;
|
|
@@ -103,21 +104,6 @@ declare class FormField {
|
|
|
103
104
|
* method to initialize all recycled Subjects and initialize Observers on field instance creation or rerender
|
|
104
105
|
*/
|
|
105
106
|
initializeObservers(): void;
|
|
106
|
-
/**
|
|
107
|
-
* Observable function to emit api events debounced and distinct for each event type,
|
|
108
|
-
* avoiding previous events being cancelled by new events if they occur inside the debounce time interval
|
|
109
|
-
*
|
|
110
|
-
* @param {(event: { event: TEvents }) => TEvents} keyExtractor function that will pass the event key to the groupBy operator
|
|
111
|
-
* @param {number} debounceTimeMs time to wait for each individual event emmited
|
|
112
|
-
* @returns
|
|
113
|
-
*/
|
|
114
|
-
debounceDistinct(keyExtractor: (event: {
|
|
115
|
-
event: TEvents;
|
|
116
|
-
}) => TEvents, debounceTimeMs: number): (source$: Observable<{
|
|
117
|
-
event: TEvents;
|
|
118
|
-
}>) => Observable<{
|
|
119
|
-
event: TEvents;
|
|
120
|
-
}>;
|
|
121
107
|
/**
|
|
122
108
|
* Retrieves the properties associated with the form field.
|
|
123
109
|
*
|
|
@@ -133,16 +119,10 @@ declare class FormField {
|
|
|
133
119
|
/**
|
|
134
120
|
* Retrieves the current state value of the form field.
|
|
135
121
|
*
|
|
136
|
-
* @returns {unknown} - The current state value of the form field.
|
|
122
|
+
* @returns {Record<string,unknown>} - The current state value of the form field.
|
|
137
123
|
*/
|
|
138
|
-
get stateValue(): unknown
|
|
124
|
+
get stateValue(): Record<string, unknown>;
|
|
139
125
|
get metadata(): unknown;
|
|
140
|
-
/**
|
|
141
|
-
* Retrieves the concatenated string of errors associated with the form field.
|
|
142
|
-
*
|
|
143
|
-
* @returns {string} - The concatenated string of errors.
|
|
144
|
-
*/
|
|
145
|
-
get errorsString(): string;
|
|
146
126
|
/**
|
|
147
127
|
* Retrieves the current value of the form field.
|
|
148
128
|
*
|
|
@@ -201,15 +181,12 @@ declare class FormField {
|
|
|
201
181
|
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
202
182
|
*
|
|
203
183
|
* @param {object} mountOpts - Adapter mount options.
|
|
204
|
-
* @param {string} prop.valuePropName - Adapter value property name.
|
|
205
|
-
* @param {(event: unknown) => unknown} prop.valueChangeEvent - Adapter change event handler function
|
|
206
184
|
* @param {(value: unknown) => unknown} prop.valueSubscription - Adapter value change function
|
|
207
185
|
* @param {(payload: Partial<IState>) => unknown} prop.propsSubscription - Adapter prop change function
|
|
208
|
-
* @param {string} prop.errorMessagePropName - error message property name to set errors onto component
|
|
209
186
|
* @returns {void}
|
|
210
187
|
*/
|
|
211
188
|
mountField({ valueSubscription, propsSubscription, }: {
|
|
212
|
-
valueSubscription: (value: unknown) => void;
|
|
189
|
+
valueSubscription: (value: Record<string, unknown>) => void;
|
|
213
190
|
propsSubscription: (payload: Partial<IState>) => void;
|
|
214
191
|
}): void;
|
|
215
192
|
/**
|
|
@@ -220,10 +197,7 @@ declare class FormField {
|
|
|
220
197
|
* @returns {void}
|
|
221
198
|
*/
|
|
222
199
|
emitValue(prop: {
|
|
223
|
-
value: unknown
|
|
224
|
-
_value: unknown;
|
|
225
|
-
_stateValue: unknown;
|
|
226
|
-
};
|
|
200
|
+
value: unknown;
|
|
227
201
|
event: TEvents;
|
|
228
202
|
}): void;
|
|
229
203
|
/**
|
package/src/managers/form.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ declare class FormCore {
|
|
|
18
18
|
key: string;
|
|
19
19
|
event: TMutationEvents;
|
|
20
20
|
}>;
|
|
21
|
-
submitSubject$: Subject<TFormValues
|
|
21
|
+
submitSubject$: Subject<TFormValues<Record<string, unknown>>>;
|
|
22
22
|
fieldEventSubject$: Subject<TFieldEvent>;
|
|
23
23
|
dataSubject$: Subject<{
|
|
24
24
|
key: string;
|
|
@@ -28,9 +28,9 @@ declare class FormCore {
|
|
|
28
28
|
subscribedTemplates: TSubscribedTemplates[];
|
|
29
29
|
action?: string;
|
|
30
30
|
method?: string;
|
|
31
|
-
config
|
|
32
|
-
mappers
|
|
33
|
-
onSubmit?: (data: TFormValues) => void;
|
|
31
|
+
config: Required<TSchemaFormConfig>;
|
|
32
|
+
mappers?: TMapper<unknown>[];
|
|
33
|
+
onSubmit?: (data: TFormValues<Record<string, unknown>>) => void;
|
|
34
34
|
/**
|
|
35
35
|
* Creates an instance of FormCore.
|
|
36
36
|
*
|
|
@@ -72,7 +72,7 @@ declare class FormCore {
|
|
|
72
72
|
*/
|
|
73
73
|
subscribeData(callback: (payload: {
|
|
74
74
|
field: string;
|
|
75
|
-
data: TFormValues
|
|
75
|
+
data: TFormValues<Record<string, unknown>>;
|
|
76
76
|
}) => void): void;
|
|
77
77
|
/**
|
|
78
78
|
* Gets the value of a property from a field.
|
|
@@ -140,15 +140,6 @@ declare class FormCore {
|
|
|
140
140
|
key: string;
|
|
141
141
|
event: TMutationEvents;
|
|
142
142
|
}): void;
|
|
143
|
-
/**
|
|
144
|
-
* Refreshes api observed fields.
|
|
145
|
-
*
|
|
146
|
-
* @param {object} options - Options for refreshing api.
|
|
147
|
-
* @param {string} options.key - The key of the field triggering the update.
|
|
148
|
-
*/
|
|
149
|
-
refreshApi({ key }: {
|
|
150
|
-
key: string;
|
|
151
|
-
}): string;
|
|
152
143
|
/**
|
|
153
144
|
* Validates and collects the names of form fields in the provided schema structure.
|
|
154
145
|
*
|
|
@@ -186,7 +177,13 @@ declare class FormCore {
|
|
|
186
177
|
*
|
|
187
178
|
* @param fieldSchema
|
|
188
179
|
*/
|
|
189
|
-
addField(fieldSchema
|
|
180
|
+
addField({ fieldSchema, mapperElement, }: {
|
|
181
|
+
fieldSchema: IComponentSchema;
|
|
182
|
+
mapperElement?: TMapper<unknown>;
|
|
183
|
+
}): void;
|
|
184
|
+
removeField({ key }: {
|
|
185
|
+
key: string;
|
|
186
|
+
}): void;
|
|
190
187
|
/**
|
|
191
188
|
* Serializes the schema structure to create form fields.
|
|
192
189
|
*
|
|
@@ -219,9 +216,8 @@ declare class FormCore {
|
|
|
219
216
|
*
|
|
220
217
|
* @returns {TFormValues} The current form values.
|
|
221
218
|
*/
|
|
222
|
-
getFormValues(): TFormValues
|
|
223
|
-
subscribeFieldEvent({
|
|
224
|
-
event: TEvents;
|
|
219
|
+
getFormValues(): TFormValues<Record<string, unknown>>;
|
|
220
|
+
subscribeFieldEvent({ callback, }: {
|
|
225
221
|
callback: (payload: TFieldEvent) => void;
|
|
226
222
|
}): Subscription;
|
|
227
223
|
/**
|
package/src/types/form.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { IFormSchema } from '../interfaces/schema';
|
|
2
2
|
import { TMapper } from './mapper';
|
|
3
3
|
/**
|
|
4
|
-
* @type TFormValues
|
|
5
|
-
* Represents the values and state of a form.
|
|
4
|
+
* @type TFormValues<T>
|
|
5
|
+
* Represents the values and state of a form. It has a generic type that allows the importer to determine which type values key will return.
|
|
6
6
|
*
|
|
7
|
-
* @property {
|
|
7
|
+
* @property {Generic Type} values - The current values of the form fields.
|
|
8
8
|
* @property {string[]} erroredFields - A list of field names that have errors.
|
|
9
9
|
* @property {boolean} isValid - Indicates whether the form is valid.
|
|
10
10
|
*
|
|
@@ -17,8 +17,8 @@ import { TMapper } from './mapper';
|
|
|
17
17
|
* };
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
-
type TFormValues = {
|
|
21
|
-
values:
|
|
20
|
+
type TFormValues<T> = {
|
|
21
|
+
values: T;
|
|
22
22
|
erroredFields: string[];
|
|
23
23
|
isValid: boolean;
|
|
24
24
|
};
|
|
@@ -41,11 +41,11 @@ type TFormValues = {
|
|
|
41
41
|
*/
|
|
42
42
|
type TFormEntry = Omit<IFormSchema, 'components'> & {
|
|
43
43
|
schema?: IFormSchema;
|
|
44
|
-
onSubmit?: (data: TFormValues) => void;
|
|
45
|
-
onData?: (payload: {
|
|
44
|
+
onSubmit?: <T>(data: TFormValues<T>) => void;
|
|
45
|
+
onData?: <T>(payload: {
|
|
46
46
|
field: string;
|
|
47
|
-
data: TFormValues
|
|
47
|
+
data: TFormValues<T>;
|
|
48
48
|
}) => void;
|
|
49
|
-
mappers
|
|
49
|
+
mappers?: TMapper<unknown>[];
|
|
50
50
|
};
|
|
51
51
|
export { TFormValues, TFormEntry };
|