@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 CHANGED
@@ -1,4 +1,4 @@
1
- import { Subscription, Subject, combineLatest, startWith, filter, 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';
@@ -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) : 1000,
2293
- defaultStateRefreshTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) : 100
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
- apiResponse: this.apiSubject$.pipe(startWith(this._api)),
2368
- props: this.propsSubject$.pipe(startWith(this._props))
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(this.debounceDistinct(({
2377
+ !this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(groupBy(({
2371
2378
  event
2372
- }) => event, (_a = this.config) === null || _a === void 0 ? void 0 : _a.defaultAPIdebounceTimeMS), filter(() => this.apiSubject$ && !this.apiSubject$.closed)).subscribe(payload => {
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 = this.maskValue(this.formatValue(val['_value']));
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 = this.maskValue(this.formatValue(val));
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._errorsString = Object.values(this.errors).join(', ');
2534
- this.errorSubject$.next(Object.values(this.errors));
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 = entry.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
- component,
2948
- props,
2949
- name,
2950
- validations,
2951
- visibilityConditions,
2952
- resetValues,
2953
- errorMessages,
2954
- apiSchema,
2955
- metadata
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
- var _a, _b;
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
- if (!this.fields.has(key)) return console.warn(`failed to get value from ${key}`);
3006
- return path.length > 0 ? get(this.fields.get(key)[property], path) : this.fields.get(key)[property];
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(fieldSchema, mapper) {
3295
- var _a;
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 mapperConfig = mapper || this.mappers.find(mapEl => mapEl.componentName === fieldSchema.component);
3300
- if (!mapperConfig) throw new Error(`mapper not found for ${fieldSchema.component}, add it to the mappers configuration`);
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: mapperConfig,
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: (_a = this.initialValues) === null || _a === void 0 ? void 0 : _a[fieldSchema.name],
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: (_a = this.initialValues) === null || _a === void 0 ? void 0 : _a[structElement.name],
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 = ((_b = structElement === null || structElement === void 0 ? void 0 : structElement.children) === null || _b === void 0 ? void 0 : _b.map(el => el.name)) || (currField === null || currField === void 0 ? void 0 : 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(filter(payload => payload.event === event)).subscribe({
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@bolttech/form-engine-core",
3
- "version": "0.0.1-beta.6",
3
+ "version": "0.0.1-beta.8",
4
4
  "module": "./index.esm.js",
5
5
  "type": "module",
6
6
  "main": "./index.esm.js",
@@ -0,0 +1,3 @@
1
+ declare const DEFAULT_API_DEBOUNCE_TIME = 1000;
2
+ declare const DEFAULT_STATE_REFRESH_TIME = 100;
3
+ export { DEFAULT_API_DEBOUNCE_TIME, DEFAULT_STATE_REFRESH_TIME };
@@ -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 };
@@ -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
  /**
@@ -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?: TSchemaFormConfig;
32
- mappers: TMapper<unknown>[];
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: IComponentSchema, mapper?: TMapper<unknown>): void;
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({ event, callback, }: {
224
- event: TEvents;
219
+ getFormValues(): TFormValues<Record<string, unknown>>;
220
+ subscribeFieldEvent({ callback, }: {
225
221
  callback: (payload: TFieldEvent) => void;
226
222
  }): Subscription;
227
223
  /**
@@ -18,7 +18,7 @@ declare class FormGroup {
18
18
  */
19
19
  createFormWithIndex({ index, mappers, }: {
20
20
  index: string;
21
- mappers: TMapper<unknown>[];
21
+ mappers?: TMapper<unknown>[];
22
22
  }): void;
23
23
  /**
24
24
  * Adds a form instance to the form group.
@@ -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 {Record<string, unknown>} values - The current values of the form fields.
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: Record<string, unknown>;
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: TMapper<unknown>[];
49
+ mappers?: TMapper<unknown>[];
50
50
  };
51
51
  export { TFormValues, TFormEntry };