@bolttech/form-engine-core 0.0.1-beta.1 → 0.0.1-beta.10
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 +1616 -0
- package/index.esm.js +197 -126
- package/package.json +1 -1
- package/src/constants/constants.d.ts +3 -0
- package/src/interfaces/schema.d.ts +5 -1
- package/src/interfaces/state.d.ts +1 -6
- package/src/managers/field.d.ts +24 -46
- package/src/managers/form.d.ts +24 -18
- package/src/managers/formGroup.d.ts +23 -2
- package/src/managers/index.d.ts +3 -0
- package/src/types/event.d.ts +7 -1
- package/src/types/form.d.ts +9 -9
- package/src/types/schema.d.ts +13 -2
package/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Subscription, Subject, combineLatest, startWith, groupBy, mergeMap, debounceTime, map } from 'rxjs';
|
|
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';
|
|
@@ -681,16 +681,9 @@ const currency = (value, masks) => {
|
|
|
681
681
|
if (integerPart === '') {
|
|
682
682
|
integerPart = '0';
|
|
683
683
|
}
|
|
684
|
-
console.log('Before', {
|
|
685
|
-
convertedValue
|
|
686
|
-
});
|
|
687
684
|
if (align === 'right' && String(value).endsWith(' ')) {
|
|
688
685
|
convertedValue = convertedValue.slice(0, -1);
|
|
689
686
|
}
|
|
690
|
-
console.log('After', {
|
|
691
|
-
value,
|
|
692
|
-
convertedValue
|
|
693
|
-
});
|
|
694
687
|
let newRawValue = integerPart;
|
|
695
688
|
let decimalPart = convertedValue.slice(convertedValue.length - precision);
|
|
696
689
|
if (precision > 0) {
|
|
@@ -2256,6 +2249,9 @@ const validations = {
|
|
|
2256
2249
|
validDate
|
|
2257
2250
|
};
|
|
2258
2251
|
|
|
2252
|
+
const DEFAULT_API_DEBOUNCE_TIME = 1000;
|
|
2253
|
+
const DEFAULT_STATE_REFRESH_TIME = 100;
|
|
2254
|
+
|
|
2259
2255
|
/**
|
|
2260
2256
|
* Represents a form field with observables for managing form state, validations, and API requests.
|
|
2261
2257
|
*/
|
|
@@ -2265,6 +2261,7 @@ class FormField {
|
|
|
2265
2261
|
*
|
|
2266
2262
|
* @param {object} options - Configuration options for the form field.
|
|
2267
2263
|
* @param {IComponentSchema} options.schemaComponent - The schema definition for the form field.
|
|
2264
|
+
* @param {TSchemaFormConfig} options.config - The schema default configuration for debounced actions.
|
|
2268
2265
|
* @param {string} [options.path] - The path within the form field (used internally during recursion).
|
|
2269
2266
|
* @param {string[]} options.children - An array of children fields names.
|
|
2270
2267
|
* @param {Function} options.validateVisibility - A function to validate the visibility of the field.
|
|
@@ -2274,19 +2271,26 @@ class FormField {
|
|
|
2274
2271
|
*/
|
|
2275
2272
|
constructor({
|
|
2276
2273
|
schemaComponent,
|
|
2274
|
+
config,
|
|
2277
2275
|
path,
|
|
2278
2276
|
children,
|
|
2279
2277
|
validateVisibility,
|
|
2280
2278
|
resetValue,
|
|
2281
2279
|
initialValue,
|
|
2282
2280
|
templateSubject$,
|
|
2283
|
-
|
|
2281
|
+
fieldEventSubject$,
|
|
2284
2282
|
dataSubject$,
|
|
2285
2283
|
mapper
|
|
2286
2284
|
}) {
|
|
2287
2285
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
2288
2286
|
this.fieldStateSubscription$ = new Subscription();
|
|
2287
|
+
this.originalSchema = schemaComponent;
|
|
2288
|
+
this.config = {
|
|
2289
|
+
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,
|
|
2290
|
+
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
|
|
2291
|
+
};
|
|
2289
2292
|
this.name = schemaComponent.name;
|
|
2293
|
+
this.nameToSubmit = schemaComponent.nameToSubmit;
|
|
2290
2294
|
this.component = schemaComponent.component;
|
|
2291
2295
|
this.path = path;
|
|
2292
2296
|
this.children = children;
|
|
@@ -2299,17 +2303,20 @@ class FormField {
|
|
|
2299
2303
|
this.masks = schemaComponent.masks;
|
|
2300
2304
|
if (mapper.valueChangeEvent) this.valueChangeEvent = mapper.valueChangeEvent;
|
|
2301
2305
|
if ((_a = mapper.events) === null || _a === void 0 ? void 0 : _a.setValue) this.valuePropName = mapper.events.setValue;
|
|
2302
|
-
if ((_b = mapper.events) === null || _b === void 0 ? void 0 : _b.setErrorMessage) this.errorMessagePropName = mapper.events.setErrorMessage;
|
|
2303
2306
|
this.mapper = mapper;
|
|
2304
2307
|
this.validateVisibility = validateVisibility;
|
|
2305
2308
|
this.resetValue = resetValue;
|
|
2306
2309
|
this.templateSubject$ = templateSubject$;
|
|
2307
|
-
this.
|
|
2310
|
+
this.fieldEventSubject$ = fieldEventSubject$;
|
|
2308
2311
|
this.dataSubject$ = dataSubject$;
|
|
2309
2312
|
this._props = schemaComponent.props || {};
|
|
2310
2313
|
this._value = '';
|
|
2311
|
-
this._stateValue =
|
|
2314
|
+
this._stateValue = ((_b = this.mapper.events) === null || _b === void 0 ? void 0 : _b.setValue) ? {
|
|
2315
|
+
[this.mapper.events.setValue]: ''
|
|
2316
|
+
} : {};
|
|
2312
2317
|
this._metadata = '';
|
|
2318
|
+
this.errorsString = '';
|
|
2319
|
+
this.errorsList = [];
|
|
2313
2320
|
this.initialValue = initialValue;
|
|
2314
2321
|
this._visibility = true;
|
|
2315
2322
|
this._api = {
|
|
@@ -2324,7 +2331,7 @@ class FormField {
|
|
|
2324
2331
|
return acc;
|
|
2325
2332
|
}, {})
|
|
2326
2333
|
};
|
|
2327
|
-
this.
|
|
2334
|
+
this._errors = {};
|
|
2328
2335
|
this._valid = false;
|
|
2329
2336
|
this.initializeObservers();
|
|
2330
2337
|
}
|
|
@@ -2332,6 +2339,7 @@ class FormField {
|
|
|
2332
2339
|
* method to initialize all recycled Subjects and initialize Observers on field instance creation or rerender
|
|
2333
2340
|
*/
|
|
2334
2341
|
initializeObservers() {
|
|
2342
|
+
var _a;
|
|
2335
2343
|
if (!this.valueSubject$ || this.valueSubject$.closed) {
|
|
2336
2344
|
this.valueSubject$ = new Subject();
|
|
2337
2345
|
}
|
|
@@ -2354,33 +2362,21 @@ class FormField {
|
|
|
2354
2362
|
this.apiEventQueueSubject$ = new Subject();
|
|
2355
2363
|
}
|
|
2356
2364
|
this.fieldState$ = combineLatest({
|
|
2357
|
-
errors: this.errorSubject$.pipe(startWith([])),
|
|
2358
2365
|
visibility: this.visibilitySubject$.pipe(startWith(this._visibility)),
|
|
2359
|
-
|
|
2360
|
-
|
|
2366
|
+
props: this.propsSubject$.pipe(startWith(this._props)),
|
|
2367
|
+
errors: this.errorSubject$.pipe(startWith(Object.assign({}, ((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setErrorMessage) && {
|
|
2368
|
+
[this.mapper.events.setErrorMessage]: this.errorsString
|
|
2369
|
+
})))
|
|
2361
2370
|
});
|
|
2362
|
-
!this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(
|
|
2371
|
+
!this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(groupBy(({
|
|
2363
2372
|
event
|
|
2364
|
-
}) => event,
|
|
2373
|
+
}) => event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultAPIdebounceTimeMS))), filter(() => this.apiSubject$ && !this.apiSubject$.closed)).subscribe(payload => {
|
|
2365
2374
|
this.apiRequest(payload);
|
|
2366
2375
|
});
|
|
2367
2376
|
if (!isNil(this.initialValue)) {
|
|
2368
2377
|
this.value = this.initialValue;
|
|
2369
2378
|
}
|
|
2370
2379
|
}
|
|
2371
|
-
/**
|
|
2372
|
-
* Observable function to emit api events debounced and distinct for each event type,
|
|
2373
|
-
* avoiding previous events being cancelled by new events if they occur inside the debounce time interval
|
|
2374
|
-
*
|
|
2375
|
-
* @param {(event: { event: TEvents }) => TEvents} keyExtractor function that will pass the event key to the groupBy operator
|
|
2376
|
-
* @param {number} debounceTimeMs time to wait for each individual event emmited
|
|
2377
|
-
* @returns
|
|
2378
|
-
*/
|
|
2379
|
-
debounceDistinct(keyExtractor, debounceTimeMs) {
|
|
2380
|
-
return source$ => source$.pipe(groupBy(keyExtractor), mergeMap(group$ => group$.pipe(debounceTime(debounceTimeMs), map(() => ({
|
|
2381
|
-
event: group$.key
|
|
2382
|
-
})))));
|
|
2383
|
-
}
|
|
2384
2380
|
/**
|
|
2385
2381
|
* Retrieves the properties associated with the form field.
|
|
2386
2382
|
*
|
|
@@ -2406,7 +2402,7 @@ class FormField {
|
|
|
2406
2402
|
/**
|
|
2407
2403
|
* Retrieves the current state value of the form field.
|
|
2408
2404
|
*
|
|
2409
|
-
* @returns {unknown} - The current state value of the form field.
|
|
2405
|
+
* @returns {Record<string,unknown>} - The current state value of the form field.
|
|
2410
2406
|
*/
|
|
2411
2407
|
get stateValue() {
|
|
2412
2408
|
return this._stateValue;
|
|
@@ -2414,14 +2410,6 @@ class FormField {
|
|
|
2414
2410
|
get metadata() {
|
|
2415
2411
|
return this._metadata;
|
|
2416
2412
|
}
|
|
2417
|
-
/**
|
|
2418
|
-
* Retrieves the concatenated string of errors associated with the form field.
|
|
2419
|
-
*
|
|
2420
|
-
* @returns {string} - The concatenated string of errors.
|
|
2421
|
-
*/
|
|
2422
|
-
get errorsString() {
|
|
2423
|
-
return this._errorsString;
|
|
2424
|
-
}
|
|
2425
2413
|
/**
|
|
2426
2414
|
* Retrieves the current value of the form field.
|
|
2427
2415
|
*
|
|
@@ -2436,6 +2424,7 @@ class FormField {
|
|
|
2436
2424
|
* @param {unknown} value - The new value to be set.
|
|
2437
2425
|
*/
|
|
2438
2426
|
set value(value) {
|
|
2427
|
+
var _a, _b, _c;
|
|
2439
2428
|
/*
|
|
2440
2429
|
too much unstable, if the valueChangeEvent parses the template event
|
|
2441
2430
|
value, might occur unexpected results
|
|
@@ -2455,22 +2444,19 @@ class FormField {
|
|
|
2455
2444
|
if (typeof val === 'undefined' || val === null) return;
|
|
2456
2445
|
if (typeof val === 'object' && '_value' in val && '_metadata' in val) {
|
|
2457
2446
|
this._value = this.formatValue(val['_value']);
|
|
2458
|
-
this._stateValue =
|
|
2447
|
+
this._stateValue = ((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setValue) ? {
|
|
2448
|
+
[this.mapper.events.setValue]: this.maskValue(this.formatValue(val['_value']))
|
|
2449
|
+
} : {};
|
|
2459
2450
|
this._metadata = val._metadata;
|
|
2460
2451
|
} else {
|
|
2461
2452
|
this._value = this.formatValue(val);
|
|
2462
|
-
this._stateValue =
|
|
2453
|
+
this._stateValue = ((_b = this.mapper.events) === null || _b === void 0 ? void 0 : _b.setValue) ? {
|
|
2454
|
+
[(_c = this.mapper.events) === null || _c === void 0 ? void 0 : _c.setValue]: this.maskValue(this.formatValue(val))
|
|
2455
|
+
} : {};
|
|
2456
|
+
this.maskValue(this.formatValue(val));
|
|
2463
2457
|
this._metadata = val;
|
|
2464
2458
|
}
|
|
2465
|
-
|
|
2466
|
-
update prop value attribute to sync with templating
|
|
2467
|
-
currently doesn't need prop Subject emission since it's synced with value
|
|
2468
|
-
to avoid excessive prop subject emissions on each keystroke
|
|
2469
|
-
*/
|
|
2470
|
-
if (this.valuePropName) this._props = Object.assign(Object.assign({}, this.props), {
|
|
2471
|
-
[this.valuePropName]: this.value
|
|
2472
|
-
});
|
|
2473
|
-
this.valueSubject$.next(this._stateValue);
|
|
2459
|
+
this.stateValue && this.valueSubject$.next(this.stateValue);
|
|
2474
2460
|
this.templateSubject$.next({
|
|
2475
2461
|
key: this.name,
|
|
2476
2462
|
event: 'ON_VALUE'
|
|
@@ -2520,10 +2506,17 @@ class FormField {
|
|
|
2520
2506
|
* @param {TErrorMessages} errors - The new error messages to be set.
|
|
2521
2507
|
*/
|
|
2522
2508
|
set errors(errors) {
|
|
2509
|
+
var _a;
|
|
2523
2510
|
if (typeof errors === 'undefined' || isEqual(errors, this.errors)) return;
|
|
2524
2511
|
this._errors = errors;
|
|
2525
|
-
this.
|
|
2526
|
-
this.
|
|
2512
|
+
this.errorsList = Object.values(this.errors);
|
|
2513
|
+
this.errorsString = this.errorsList.join(', ');
|
|
2514
|
+
/**
|
|
2515
|
+
* if any error receieves a list of errors, set a prop for it, currently only supporting a single string
|
|
2516
|
+
*/
|
|
2517
|
+
((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setErrorMessage) && this.errorSubject$.next({
|
|
2518
|
+
[this.mapper.events.setErrorMessage]: this.errorsString
|
|
2519
|
+
});
|
|
2527
2520
|
this.templateSubject$.next({
|
|
2528
2521
|
key: this.name,
|
|
2529
2522
|
event: 'ON_PROPS'
|
|
@@ -2559,11 +2552,8 @@ class FormField {
|
|
|
2559
2552
|
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
2560
2553
|
*
|
|
2561
2554
|
* @param {object} mountOpts - Adapter mount options.
|
|
2562
|
-
* @param {string} prop.valuePropName - Adapter value property name.
|
|
2563
|
-
* @param {(event: unknown) => unknown} prop.valueChangeEvent - Adapter change event handler function
|
|
2564
2555
|
* @param {(value: unknown) => unknown} prop.valueSubscription - Adapter value change function
|
|
2565
2556
|
* @param {(payload: Partial<IState>) => unknown} prop.propsSubscription - Adapter prop change function
|
|
2566
|
-
* @param {string} prop.errorMessagePropName - error message property name to set errors onto component
|
|
2567
2557
|
* @returns {void}
|
|
2568
2558
|
*/
|
|
2569
2559
|
mountField({
|
|
@@ -2614,6 +2604,11 @@ class FormField {
|
|
|
2614
2604
|
this.apiEventQueueSubject$.next({
|
|
2615
2605
|
event
|
|
2616
2606
|
});
|
|
2607
|
+
this.fieldEventSubject$.next({
|
|
2608
|
+
event,
|
|
2609
|
+
fieldName: this.name,
|
|
2610
|
+
fieldInstance: this
|
|
2611
|
+
});
|
|
2617
2612
|
}
|
|
2618
2613
|
/**
|
|
2619
2614
|
* Sets the validity state of the field based on the provided validation rules and triggers error message updates.
|
|
@@ -2639,14 +2634,19 @@ class FormField {
|
|
|
2639
2634
|
const errors = Object.assign({}, this.errors);
|
|
2640
2635
|
const schemaValidations = (_a = this.validations) === null || _a === void 0 ? void 0 : _a.config;
|
|
2641
2636
|
schemaValidations && Object.keys(schemaValidations).forEach(validationKey => {
|
|
2642
|
-
var _a
|
|
2637
|
+
var _a;
|
|
2643
2638
|
const error = validations[validationKey](this.value, schemaValidations);
|
|
2644
2639
|
// setting valid flag
|
|
2645
2640
|
valid = !error && valid;
|
|
2646
2641
|
// setting error messages
|
|
2647
2642
|
if (((_a = this.validations) === null || _a === void 0 ? void 0 : _a.events.includes(event)) || event === 'ON_FORM_SUBMIT') {
|
|
2648
|
-
if (error &&
|
|
2649
|
-
|
|
2643
|
+
if (error && this.errorMessages) {
|
|
2644
|
+
if (validationKey in this.errorMessages) {
|
|
2645
|
+
const messages = this.errorMessages;
|
|
2646
|
+
errors[validationKey] = messages[validationKey];
|
|
2647
|
+
} else if ('default' in this.errorMessages) {
|
|
2648
|
+
errors[validationKey] = this.errorMessages.default;
|
|
2649
|
+
}
|
|
2650
2650
|
} else {
|
|
2651
2651
|
delete errors[validationKey];
|
|
2652
2652
|
}
|
|
@@ -2654,10 +2654,19 @@ class FormField {
|
|
|
2654
2654
|
});
|
|
2655
2655
|
this._valid = valid;
|
|
2656
2656
|
this.errors = errors;
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* WIP expensive function to get updated field validity on each event
|
|
2660
|
+
*/
|
|
2661
|
+
updateValidityFlag() {
|
|
2662
|
+
var _a;
|
|
2663
|
+
let valid = true;
|
|
2664
|
+
const schemaValidations = (_a = this.validations) === null || _a === void 0 ? void 0 : _a.config;
|
|
2665
|
+
schemaValidations && Object.keys(schemaValidations).forEach(validationKey => {
|
|
2666
|
+
const error = validations[validationKey](this.value, schemaValidations);
|
|
2667
|
+
valid = !error && valid;
|
|
2660
2668
|
});
|
|
2669
|
+
this._valid = valid;
|
|
2661
2670
|
}
|
|
2662
2671
|
/**
|
|
2663
2672
|
* Formats the field value using the specified formatters, if available.
|
|
@@ -2802,7 +2811,7 @@ class FormField {
|
|
|
2802
2811
|
* @returns {void}
|
|
2803
2812
|
*/
|
|
2804
2813
|
subscribeState(callback) {
|
|
2805
|
-
this.fieldStateSubscription$ = this.fieldState$.pipe(debounceTime(
|
|
2814
|
+
this.fieldStateSubscription$ = this.fieldState$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS)).subscribe({
|
|
2806
2815
|
next: callback
|
|
2807
2816
|
});
|
|
2808
2817
|
}
|
|
@@ -2837,7 +2846,7 @@ class FormCore {
|
|
|
2837
2846
|
* @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
|
|
2838
2847
|
*/
|
|
2839
2848
|
constructor(entry) {
|
|
2840
|
-
var _a, _b, _c, _d;
|
|
2849
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2841
2850
|
this.schema = entry.schema;
|
|
2842
2851
|
this.fields = new Map();
|
|
2843
2852
|
this.initialValues = entry.initialValues || ((_a = entry.schema) === null || _a === void 0 ? void 0 : _a.initialValues);
|
|
@@ -2845,11 +2854,15 @@ class FormCore {
|
|
|
2845
2854
|
this.method = entry.method || ((_c = entry.schema) === null || _c === void 0 ? void 0 : _c.method);
|
|
2846
2855
|
this._iVars = entry.iVars || ((_d = entry.schema) === null || _d === void 0 ? void 0 : _d.iVars) || {};
|
|
2847
2856
|
this.onSubmit = entry.onSubmit;
|
|
2857
|
+
this.config = {
|
|
2858
|
+
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,
|
|
2859
|
+
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
|
|
2860
|
+
};
|
|
2848
2861
|
this.mappers = entry.mappers;
|
|
2849
2862
|
this.schema && FormCore.checkIndexes(this.schema.components);
|
|
2850
2863
|
this.templateSubject$ = new Subject();
|
|
2851
2864
|
this.submitSubject$ = new Subject();
|
|
2852
|
-
this.
|
|
2865
|
+
this.fieldEventSubject$ = new Subject();
|
|
2853
2866
|
this.dataSubject$ = new Subject();
|
|
2854
2867
|
this.dataCallbackSubscription$ = new Subscription();
|
|
2855
2868
|
this.subscribedTemplates = [];
|
|
@@ -2860,7 +2873,6 @@ class FormCore {
|
|
|
2860
2873
|
key: IVARPROPNAME,
|
|
2861
2874
|
event: 'ON_IVARS'
|
|
2862
2875
|
});
|
|
2863
|
-
this.apiResponseSubject$.subscribe(this.refreshApi.bind(this));
|
|
2864
2876
|
entry.onData && this.subscribeData(entry.onData);
|
|
2865
2877
|
/*
|
|
2866
2878
|
mount events needs to occur on form level, only when all the fields are instantiated
|
|
@@ -2912,20 +2924,18 @@ class FormCore {
|
|
|
2912
2924
|
* Subscribes to templates for dynamic updates.
|
|
2913
2925
|
*/
|
|
2914
2926
|
subscribeTemplates() {
|
|
2915
|
-
|
|
2916
|
-
@TODO fix removal of templates of removed fields, they are kept
|
|
2917
|
-
tried: this.subscribedTemplates = [] and only stores the last one..
|
|
2918
|
-
*/
|
|
2927
|
+
this.subscribedTemplates = [];
|
|
2919
2928
|
this.fields.forEach(({
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
+
originalSchema: {
|
|
2930
|
+
component,
|
|
2931
|
+
props,
|
|
2932
|
+
name,
|
|
2933
|
+
validations,
|
|
2934
|
+
visibilityConditions,
|
|
2935
|
+
resetValues,
|
|
2936
|
+
errorMessages,
|
|
2937
|
+
api
|
|
2938
|
+
}
|
|
2929
2939
|
}, key) => {
|
|
2930
2940
|
const template = {
|
|
2931
2941
|
component,
|
|
@@ -2935,19 +2945,17 @@ class FormCore {
|
|
|
2935
2945
|
visibilityConditions,
|
|
2936
2946
|
resetValues,
|
|
2937
2947
|
errorMessages,
|
|
2938
|
-
apiSchema
|
|
2939
|
-
metadata
|
|
2948
|
+
apiSchema: api
|
|
2940
2949
|
};
|
|
2941
2950
|
traverseObject(template, key).forEach(element => this.subscribedTemplates.push(element));
|
|
2942
2951
|
});
|
|
2943
|
-
// console.log(subscribedProps);
|
|
2944
2952
|
}
|
|
2945
2953
|
/**
|
|
2946
2954
|
*
|
|
2947
2955
|
* @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
|
|
2948
2956
|
*/
|
|
2949
2957
|
subscribeData(callback) {
|
|
2950
|
-
this.dataCallbackSubscription$ = this.dataSubject$.pipe(debounceTime(
|
|
2958
|
+
this.dataCallbackSubscription$ = this.dataSubject$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS), map(({
|
|
2951
2959
|
key
|
|
2952
2960
|
}) => ({
|
|
2953
2961
|
field: key,
|
|
@@ -2974,8 +2982,12 @@ class FormCore {
|
|
|
2974
2982
|
const value = get(this.iVars, [property, ...path]);
|
|
2975
2983
|
return value;
|
|
2976
2984
|
}
|
|
2977
|
-
|
|
2978
|
-
return
|
|
2985
|
+
const field = this.fields.get(key);
|
|
2986
|
+
if (!field) return console.warn(`failed to get value from ${key}`);
|
|
2987
|
+
if (property === 'props' && path[0] === field.valuePropName) {
|
|
2988
|
+
return field.stateValue;
|
|
2989
|
+
}
|
|
2990
|
+
return path.length > 0 ? get(field[property], path) : field[property];
|
|
2979
2991
|
}
|
|
2980
2992
|
/**
|
|
2981
2993
|
* Sets the value of a property in a field.
|
|
@@ -3008,7 +3020,6 @@ class FormCore {
|
|
|
3008
3020
|
now using key !== originKey, check if any recursion error occurs
|
|
3009
3021
|
**/
|
|
3010
3022
|
if (property === 'props' && path[0] === field.valuePropName && key !== originKey) {
|
|
3011
|
-
// field.value = value;
|
|
3012
3023
|
field.emitValue({
|
|
3013
3024
|
event: 'ON_FIELD_CHANGE',
|
|
3014
3025
|
value
|
|
@@ -3048,7 +3059,6 @@ class FormCore {
|
|
|
3048
3059
|
const operatorRegex = /\s*(\|\||&&|!)\s*/g;
|
|
3049
3060
|
const splittedString = extractedValues.map(el => el.split(operatorRegex));
|
|
3050
3061
|
const result = splittedString.map(splittedStringVal => {
|
|
3051
|
-
// console.log(splittedStringVal)
|
|
3052
3062
|
return splittedStringVal.filter(Boolean).reduce((acc, curr) => {
|
|
3053
3063
|
if (curr.match(/^\|\||&&|!$/)) {
|
|
3054
3064
|
return `${acc}${curr}`;
|
|
@@ -3092,7 +3102,6 @@ class FormCore {
|
|
|
3092
3102
|
});
|
|
3093
3103
|
return result.map(el => {
|
|
3094
3104
|
try {
|
|
3095
|
-
// console.log(el);
|
|
3096
3105
|
return new Function(`return ${el}`)();
|
|
3097
3106
|
} catch (e) {
|
|
3098
3107
|
console.log(e);
|
|
@@ -3165,34 +3174,6 @@ class FormCore {
|
|
|
3165
3174
|
}
|
|
3166
3175
|
});
|
|
3167
3176
|
}
|
|
3168
|
-
/**
|
|
3169
|
-
* Refreshes api observed fields.
|
|
3170
|
-
*
|
|
3171
|
-
* @param {object} options - Options for refreshing api.
|
|
3172
|
-
* @param {string} options.key - The key of the field triggering the update.
|
|
3173
|
-
*/
|
|
3174
|
-
refreshApi({
|
|
3175
|
-
key
|
|
3176
|
-
}) {
|
|
3177
|
-
/*
|
|
3178
|
-
global api notifications needs to have field dependency array
|
|
3179
|
-
in order to be reliable, disabled for now
|
|
3180
|
-
*/
|
|
3181
|
-
return key;
|
|
3182
|
-
// const emmittedFields: string[] = [];
|
|
3183
|
-
// this.subscribedTemplates.forEach((template) => {
|
|
3184
|
-
// if (
|
|
3185
|
-
// template.originFieldKeys.includes(key) &&
|
|
3186
|
-
// template.originPropertyKeys.includes('api') &&
|
|
3187
|
-
// !emmittedFields.includes(template.destinationKey)
|
|
3188
|
-
// ) {
|
|
3189
|
-
// emmittedFields.push(template.destinationKey);
|
|
3190
|
-
// this.fields
|
|
3191
|
-
// .get(template.destinationKey)
|
|
3192
|
-
// ?.emitEvents({ event: 'ON_API_RESPONSE' });
|
|
3193
|
-
// }
|
|
3194
|
-
// });
|
|
3195
|
-
}
|
|
3196
3177
|
/**
|
|
3197
3178
|
* Validates visibility conditions for a given event and updates field visibility accordingly.
|
|
3198
3179
|
*
|
|
@@ -3258,6 +3239,54 @@ class FormCore {
|
|
|
3258
3239
|
});
|
|
3259
3240
|
});
|
|
3260
3241
|
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Adds a field onto the form instance regardless there is a schema or not
|
|
3244
|
+
*
|
|
3245
|
+
* @param fieldSchema
|
|
3246
|
+
*/
|
|
3247
|
+
addField({
|
|
3248
|
+
fieldSchema,
|
|
3249
|
+
mapperElement
|
|
3250
|
+
}) {
|
|
3251
|
+
var _a, _b, _c;
|
|
3252
|
+
if (this.fields.has(fieldSchema.name)) {
|
|
3253
|
+
throw new Error(`field name ${fieldSchema.name} already defined`);
|
|
3254
|
+
}
|
|
3255
|
+
const mapper = mapperElement || ((_a = this.mappers) === null || _a === void 0 ? void 0 : _a.find(mapEl => mapEl.componentName === fieldSchema.component));
|
|
3256
|
+
if (!mapper) throw new Error(`mapper not found for ${fieldSchema.component}, add it to the mappers configuration`);
|
|
3257
|
+
this.fields.set(fieldSchema.name, new FormField({
|
|
3258
|
+
schemaComponent: fieldSchema,
|
|
3259
|
+
mapper,
|
|
3260
|
+
children: fieldSchema.children ? fieldSchema.children.map(el => el.name) : [],
|
|
3261
|
+
validateVisibility: this.validateVisibility.bind(this),
|
|
3262
|
+
resetValue: this.resetValue.bind(this),
|
|
3263
|
+
initialValue: (_b = this.initialValues) === null || _b === void 0 ? void 0 : _b[fieldSchema.name],
|
|
3264
|
+
templateSubject$: this.templateSubject$,
|
|
3265
|
+
fieldEventSubject$: this.fieldEventSubject$,
|
|
3266
|
+
dataSubject$: this.dataSubject$,
|
|
3267
|
+
config: this.config
|
|
3268
|
+
}));
|
|
3269
|
+
this.subscribeTemplates();
|
|
3270
|
+
this.refreshTemplates({
|
|
3271
|
+
event: 'ON_FIELDS',
|
|
3272
|
+
key: fieldSchema.name
|
|
3273
|
+
});
|
|
3274
|
+
(_c = this.fields.get(fieldSchema.name)) === null || _c === void 0 ? void 0 : _c.emitEvents({
|
|
3275
|
+
event: 'ON_FIELD_MOUNT'
|
|
3276
|
+
});
|
|
3277
|
+
}
|
|
3278
|
+
removeField({
|
|
3279
|
+
key
|
|
3280
|
+
}) {
|
|
3281
|
+
var _a;
|
|
3282
|
+
(_a = this.fields.get(key)) === null || _a === void 0 ? void 0 : _a.destroyField();
|
|
3283
|
+
this.fields.delete(key);
|
|
3284
|
+
this.subscribeTemplates();
|
|
3285
|
+
this.templateSubject$.next({
|
|
3286
|
+
key,
|
|
3287
|
+
event: 'ON_FIELDS'
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
3261
3290
|
/**
|
|
3262
3291
|
* Serializes the schema structure to create form fields.
|
|
3263
3292
|
*
|
|
@@ -3267,10 +3296,10 @@ class FormCore {
|
|
|
3267
3296
|
serializeStructure(struct, path) {
|
|
3268
3297
|
if (!struct) return;
|
|
3269
3298
|
struct.forEach(structElement => {
|
|
3270
|
-
var _a, _b;
|
|
3299
|
+
var _a, _b, _c;
|
|
3271
3300
|
const currField = this.fields.get(structElement.name);
|
|
3272
3301
|
if (!currField) {
|
|
3273
|
-
const mapper = this.mappers.find(mapEl => mapEl.componentName === structElement.component);
|
|
3302
|
+
const mapper = (_a = this.mappers) === null || _a === void 0 ? void 0 : _a.find(mapEl => mapEl.componentName === structElement.component);
|
|
3274
3303
|
if (!mapper) throw new Error(`mapper not found for ${structElement.component}, add it to the mappers configuration`);
|
|
3275
3304
|
this.fields.set(structElement.name, new FormField({
|
|
3276
3305
|
schemaComponent: structElement,
|
|
@@ -3279,13 +3308,14 @@ class FormCore {
|
|
|
3279
3308
|
children: structElement.children ? structElement.children.map(el => el.name) : [],
|
|
3280
3309
|
validateVisibility: this.validateVisibility.bind(this),
|
|
3281
3310
|
resetValue: this.resetValue.bind(this),
|
|
3282
|
-
initialValue: (
|
|
3311
|
+
initialValue: (_b = this.initialValues) === null || _b === void 0 ? void 0 : _b[structElement.name],
|
|
3283
3312
|
templateSubject$: this.templateSubject$,
|
|
3284
|
-
|
|
3285
|
-
dataSubject$: this.dataSubject
|
|
3313
|
+
fieldEventSubject$: this.fieldEventSubject$,
|
|
3314
|
+
dataSubject$: this.dataSubject$,
|
|
3315
|
+
config: this.config
|
|
3286
3316
|
}));
|
|
3287
3317
|
} else {
|
|
3288
|
-
currField.children = ((
|
|
3318
|
+
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) || [];
|
|
3289
3319
|
currField.path = path;
|
|
3290
3320
|
currField.templateSubject$ = this.templateSubject$;
|
|
3291
3321
|
}
|
|
@@ -3347,10 +3377,9 @@ class FormCore {
|
|
|
3347
3377
|
const values = {};
|
|
3348
3378
|
this.fields.forEach((val, key) => {
|
|
3349
3379
|
if (val.value) {
|
|
3350
|
-
values
|
|
3380
|
+
set(values, val.nameToSubmit || key, val.value);
|
|
3351
3381
|
}
|
|
3352
3382
|
});
|
|
3353
|
-
console.log(values);
|
|
3354
3383
|
}
|
|
3355
3384
|
/**
|
|
3356
3385
|
* Gets the current values of all form fields.
|
|
@@ -3362,7 +3391,7 @@ class FormCore {
|
|
|
3362
3391
|
const erroredFields = [];
|
|
3363
3392
|
this.fields.forEach((val, key) => {
|
|
3364
3393
|
if (val.value) {
|
|
3365
|
-
values
|
|
3394
|
+
set(values, val.nameToSubmit || key, val.value);
|
|
3366
3395
|
}
|
|
3367
3396
|
if (!val.valid) {
|
|
3368
3397
|
erroredFields.push(key);
|
|
@@ -3374,6 +3403,14 @@ class FormCore {
|
|
|
3374
3403
|
isValid: this.isValid
|
|
3375
3404
|
};
|
|
3376
3405
|
}
|
|
3406
|
+
subscribeFieldEvent({
|
|
3407
|
+
callback
|
|
3408
|
+
}) {
|
|
3409
|
+
const sub = this.fieldEventSubject$.pipe(groupBy(payload => payload.event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS)))).subscribe({
|
|
3410
|
+
next: callback
|
|
3411
|
+
});
|
|
3412
|
+
return sub;
|
|
3413
|
+
}
|
|
3377
3414
|
/**
|
|
3378
3415
|
* Submits the form by triggering form field events and invoking the onSubmit callback.
|
|
3379
3416
|
*/
|
|
@@ -3391,8 +3428,9 @@ class FormCore {
|
|
|
3391
3428
|
destroy() {
|
|
3392
3429
|
this.submitSubject$.unsubscribe();
|
|
3393
3430
|
this.templateSubject$.unsubscribe();
|
|
3394
|
-
this.
|
|
3431
|
+
this.fieldEventSubject$.unsubscribe();
|
|
3395
3432
|
this.dataSubject$.unsubscribe();
|
|
3433
|
+
this.fields.forEach(field => field.destroyField());
|
|
3396
3434
|
}
|
|
3397
3435
|
}
|
|
3398
3436
|
/**
|
|
@@ -3429,6 +3467,25 @@ class FormGroup {
|
|
|
3429
3467
|
constructor() {
|
|
3430
3468
|
this.forms = new Map();
|
|
3431
3469
|
}
|
|
3470
|
+
/**
|
|
3471
|
+
* Creates an empty form with given index
|
|
3472
|
+
*
|
|
3473
|
+
* @param {string} options.index
|
|
3474
|
+
* @param {TMapper<unknown>} options.mappers
|
|
3475
|
+
*/
|
|
3476
|
+
createFormWithIndex({
|
|
3477
|
+
index,
|
|
3478
|
+
mappers
|
|
3479
|
+
}) {
|
|
3480
|
+
const formInstance = new FormCore({
|
|
3481
|
+
index,
|
|
3482
|
+
mappers
|
|
3483
|
+
});
|
|
3484
|
+
this.addForm({
|
|
3485
|
+
key: index,
|
|
3486
|
+
formInstance
|
|
3487
|
+
});
|
|
3488
|
+
}
|
|
3432
3489
|
/**
|
|
3433
3490
|
* Adds a form instance to the form group.
|
|
3434
3491
|
*
|
|
@@ -3471,6 +3528,20 @@ class FormGroup {
|
|
|
3471
3528
|
(_a = this.forms.get(key)) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
3472
3529
|
this.forms.delete(key);
|
|
3473
3530
|
}
|
|
3531
|
+
/**
|
|
3532
|
+
* removes a field given a form and field index
|
|
3533
|
+
*
|
|
3534
|
+
* @param {string} options.formIndex
|
|
3535
|
+
* @param {string} options.fieldIndex
|
|
3536
|
+
*/
|
|
3537
|
+
removeField({
|
|
3538
|
+
formIndex,
|
|
3539
|
+
fieldIndex
|
|
3540
|
+
}) {
|
|
3541
|
+
var _a, _b, _c;
|
|
3542
|
+
(_b = (_a = this.forms.get(formIndex)) === null || _a === void 0 ? void 0 : _a.fields.get(fieldIndex)) === null || _b === void 0 ? void 0 : _b.destroyField();
|
|
3543
|
+
(_c = this.forms.get(formIndex)) === null || _c === void 0 ? void 0 : _c.fields.delete(fieldIndex);
|
|
3544
|
+
}
|
|
3474
3545
|
/**
|
|
3475
3546
|
* Checks if the specified key already exists in the form group.
|
|
3476
3547
|
*
|
package/package.json
CHANGED