@bolttech/form-engine-core 0.0.1-beta.16 → 0.0.1-beta.17

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
@@ -44,6 +44,12 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
44
44
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
45
45
  };
46
46
 
47
+ const DEFAULT_API_DEBOUNCE_TIME = 1000;
48
+ const DEFAULT_STATE_REFRESH_TIME = 100;
49
+ const TEMPLATE_REGEX_DELIMITATOR = /\${(.*?)}/g;
50
+ const TEMPLATE_REGEX_OPERATOR_SPLITTER = /\s*(\|\||&&|!)\s*/g;
51
+ const TEMPLATE_REGEX_OPERATOR_MATCHER = /^\|\||&&|!$/;
52
+
47
53
  /**
48
54
  * Makes an HTTP request using XMLHttpRequest.
49
55
  *
@@ -96,15 +102,17 @@ function makeRequest(method, url, headers, body) {
96
102
  * ```
97
103
  */
98
104
  function extractFieldKeys(expression) {
99
- const regex = /\${(.*?)}/g;
105
+ const regex = TEMPLATE_REGEX_DELIMITATOR;
100
106
  const extractedValues = [];
101
107
  let match;
102
108
  while ((match = regex.exec(expression)) !== null) {
103
109
  extractedValues.push(match[1]);
104
110
  }
111
+ const operatorRegex = TEMPLATE_REGEX_OPERATOR_SPLITTER;
112
+ const splittedString = extractedValues.map(el => el.split(operatorRegex).filter(item => !operatorRegex.test(item))).flat().filter(el => el.split('.').length > 1);
105
113
  return {
106
- originFieldKeys: Array.from(new Set(extractedValues.map(el => el.split('.')[0]))),
107
- originPropertyKeys: Array.from(new Set(extractedValues.map(el => el.split('.')[1])))
114
+ originFieldKeys: Array.from(new Set(splittedString.map(el => el.split('.')[0]))),
115
+ originPropertyKeys: Array.from(new Set(splittedString.map(el => el.split('.')[1])))
108
116
  };
109
117
  }
110
118
  /**
@@ -2249,9 +2257,6 @@ const validations = {
2249
2257
  validDate
2250
2258
  };
2251
2259
 
2252
- const DEFAULT_API_DEBOUNCE_TIME = 1000;
2253
- const DEFAULT_STATE_REFRESH_TIME = 100;
2254
-
2255
2260
  /**
2256
2261
  * Custom RXJS Subject to gracefully handle errors on unsubscribed Subjects
2257
2262
  * that were unmounted due to adapter external handling such as visibility
@@ -2861,7 +2866,6 @@ class FormCore {
2861
2866
  * @param {string} [entry.action] - The action attribute of the form.
2862
2867
  * @param {string} [entry.method] - The method attribute of the form.
2863
2868
  * @param {IFormSchema.iVars} [entry.iVars] - The internal variables of the form.
2864
- * @param {(data: TFormValues) => void} [entry.onSubmit] - A callback function to handle form submission.
2865
2869
  * @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
2866
2870
  */
2867
2871
  constructor(entry) {
@@ -2873,7 +2877,6 @@ class FormCore {
2873
2877
  this.action = entry.action || ((_b = entry.schema) === null || _b === void 0 ? void 0 : _b.action);
2874
2878
  this.method = entry.method || ((_c = entry.schema) === null || _c === void 0 ? void 0 : _c.method);
2875
2879
  this._iVars = entry.iVars || ((_d = entry.schema) === null || _d === void 0 ? void 0 : _d.iVars) || {};
2876
- this.onSubmit = entry.onSubmit;
2877
2880
  this.config = {
2878
2881
  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,
2879
2882
  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
@@ -2886,7 +2889,6 @@ class FormCore {
2886
2889
  this.submitSubject$ = new Subject();
2887
2890
  this.fieldEventSubject$ = new Subject();
2888
2891
  this.dataSubject$ = new Subject();
2889
- this.dataCallbackSubscription$ = new Subscription();
2890
2892
  this.subscribedTemplates = [];
2891
2893
  this.schema && this.serializeStructure(this.schema.components);
2892
2894
  this.schema && this.subscribeTemplates();
@@ -2895,7 +2897,6 @@ class FormCore {
2895
2897
  key: IVARPROPNAME,
2896
2898
  event: 'ON_IVARS'
2897
2899
  });
2898
- entry.onData && this.subscribeData(entry.onData);
2899
2900
  /*
2900
2901
  mount events needs to occur on form level, only when all the fields are instantiated
2901
2902
  is it possible to apply all the side effects that occur globally, same effect occur
@@ -2970,20 +2971,6 @@ class FormCore {
2970
2971
  traverseObject(template, key).forEach(element => this.subscribedTemplates.push(element));
2971
2972
  });
2972
2973
  }
2973
- /**
2974
- *
2975
- * @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
2976
- */
2977
- subscribeData(callback) {
2978
- this.dataCallbackSubscription$ = this.dataSubject$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS), map(({
2979
- key
2980
- }) => ({
2981
- field: key,
2982
- data: this.getFormValues()
2983
- }))).subscribe({
2984
- next: callback
2985
- });
2986
- }
2987
2974
  /**
2988
2975
  * Gets the value of a property from a field.
2989
2976
  *
@@ -3070,17 +3057,17 @@ class FormCore {
3070
3057
  * @returns {string[]} An array of extracted parameters.
3071
3058
  */
3072
3059
  extractParams(expression) {
3073
- const regex = /\${(.*?)}/g;
3060
+ const regex = TEMPLATE_REGEX_DELIMITATOR;
3074
3061
  const extractedValues = [];
3075
3062
  let match;
3076
3063
  while (!isNil(match = regex.exec(expression))) {
3077
3064
  extractedValues.push(match[1]);
3078
3065
  }
3079
- const operatorRegex = /\s*(\|\||&&|!)\s*/g;
3066
+ const operatorRegex = TEMPLATE_REGEX_OPERATOR_SPLITTER;
3080
3067
  const splittedString = extractedValues.map(el => el.split(operatorRegex));
3081
3068
  const result = splittedString.map(splittedStringVal => {
3082
3069
  return splittedStringVal.filter(Boolean).reduce((acc, curr) => {
3083
- if (curr.match(/^\|\||&&|!$/)) {
3070
+ if (curr.match(TEMPLATE_REGEX_OPERATOR_MATCHER)) {
3084
3071
  return `${acc}${curr}`;
3085
3072
  }
3086
3073
  let value;
@@ -3142,7 +3129,7 @@ class FormCore {
3142
3129
  * @returns {string} The expression string with the replacements made.
3143
3130
  */
3144
3131
  replaceExpression(expression, values) {
3145
- const regex = /\${(.*?)}/g;
3132
+ const regex = TEMPLATE_REGEX_DELIMITATOR;
3146
3133
  return expression.replace(regex, () => String(values.shift()) || '');
3147
3134
  }
3148
3135
  /**
@@ -3443,6 +3430,27 @@ class FormCore {
3443
3430
  });
3444
3431
  return sub;
3445
3432
  }
3433
+ /**
3434
+ *
3435
+ * @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
3436
+ */
3437
+ subscribeData(callback) {
3438
+ const sub = this.dataSubject$.pipe(groupBy(payload => payload.event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS))), map(({
3439
+ key
3440
+ }) => ({
3441
+ field: key,
3442
+ data: this.getFormValues()
3443
+ }))).subscribe({
3444
+ next: callback
3445
+ });
3446
+ return sub;
3447
+ }
3448
+ subscribeOnSubmit(callback) {
3449
+ const sub = this.submitSubject$.pipe(map(() => this.getFormValues())).subscribe({
3450
+ next: callback
3451
+ });
3452
+ return sub;
3453
+ }
3446
3454
  /**
3447
3455
  * Submits the form by triggering form field events and invoking the onSubmit callback.
3448
3456
  */
@@ -3455,7 +3463,6 @@ class FormCore {
3455
3463
  if (!this.isValid) return;
3456
3464
  const values = this.getFormValues();
3457
3465
  this.submitSubject$.next(values);
3458
- this.onSubmit && this.onSubmit(values);
3459
3466
  }
3460
3467
  destroy() {
3461
3468
  this.submitSubject$.unsubscribe();
@@ -3606,22 +3613,49 @@ class FormGroup {
3606
3613
  * @param {string[]} indexes form indexes to be submitted
3607
3614
  * @returns
3608
3615
  */
3609
- submitMultipleFormsByIndex(indexes) {
3616
+ submitMultipleFormsByIndex(indexes, callback) {
3610
3617
  let isValid = true;
3611
3618
  let values = {};
3612
3619
  let erroredFields = [];
3613
3620
  indexes.forEach(index => {
3614
- var _a;
3615
- const res = (_a = this.forms.get(index)) === null || _a === void 0 ? void 0 : _a.getFormValues();
3621
+ var _a, _b;
3622
+ (_a = this.forms.get(index)) === null || _a === void 0 ? void 0 : _a.submit();
3623
+ const res = (_b = this.forms.get(index)) === null || _b === void 0 ? void 0 : _b.getFormValues();
3616
3624
  isValid = isValid && ((res === null || res === void 0 ? void 0 : res.isValid) || false);
3617
3625
  values = Object.assign(Object.assign({}, values), (res === null || res === void 0 ? void 0 : res.values) || {});
3618
3626
  erroredFields = [...erroredFields, ...((res === null || res === void 0 ? void 0 : res.erroredFields) || [])];
3619
3627
  });
3620
- return {
3628
+ isValid && callback && callback({
3621
3629
  erroredFields,
3622
3630
  isValid,
3623
3631
  values
3624
- };
3632
+ });
3633
+ }
3634
+ onDataSubscription({
3635
+ ids,
3636
+ callback
3637
+ }) {
3638
+ const subs = ids.reduce((acc, formId) => {
3639
+ var _a;
3640
+ // @TODO add config on debounceTime on this events
3641
+ const sub = (_a = this.forms.get(formId)) === null || _a === void 0 ? void 0 : _a.dataSubject$.pipe(groupBy(payload => `${formId}.${payload.event}`), mergeMap(group$ => group$.pipe(debounceTime(100))), map(({
3642
+ key
3643
+ }) => {
3644
+ var _a;
3645
+ return {
3646
+ formField: key,
3647
+ values: (_a = this.forms.get(formId)) === null || _a === void 0 ? void 0 : _a.getFormValues()
3648
+ };
3649
+ }));
3650
+ if (sub) {
3651
+ acc[formId] = sub;
3652
+ } else {
3653
+ console.warn(`failed to register form id ${formId}`);
3654
+ }
3655
+ return acc;
3656
+ }, {});
3657
+ const sub = combineLatest(subs).subscribe(callback);
3658
+ return sub;
3625
3659
  }
3626
3660
  }
3627
3661
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bolttech/form-engine-core",
3
- "version": "0.0.1-beta.16",
3
+ "version": "0.0.1-beta.17",
4
4
  "module": "./index.esm.js",
5
5
  "type": "module",
6
6
  "main": "./index.esm.js",
@@ -1,3 +1,6 @@
1
1
  declare const DEFAULT_API_DEBOUNCE_TIME = 1000;
2
2
  declare const DEFAULT_STATE_REFRESH_TIME = 100;
3
- export { DEFAULT_API_DEBOUNCE_TIME, DEFAULT_STATE_REFRESH_TIME };
3
+ declare const TEMPLATE_REGEX_DELIMITATOR: RegExp;
4
+ declare const TEMPLATE_REGEX_OPERATOR_SPLITTER: RegExp;
5
+ declare const TEMPLATE_REGEX_OPERATOR_MATCHER: RegExp;
6
+ export { DEFAULT_API_DEBOUNCE_TIME, DEFAULT_STATE_REFRESH_TIME, TEMPLATE_REGEX_DELIMITATOR, TEMPLATE_REGEX_OPERATOR_SPLITTER, TEMPLATE_REGEX_OPERATOR_MATCHER };
@@ -24,13 +24,11 @@ declare class FormCore {
24
24
  key: string;
25
25
  event: TEvents;
26
26
  }>;
27
- dataCallbackSubscription$: Subscription;
28
27
  subscribedTemplates: TSubscribedTemplates[];
29
28
  action?: string;
30
29
  method?: string;
31
30
  config: Required<TSchemaFormConfig>;
32
31
  mappers: Map<string, TMapper<unknown>>;
33
- onSubmit?: (data: TFormValues<Record<string, unknown>>) => void;
34
32
  /**
35
33
  * Creates an instance of FormCore.
36
34
  *
@@ -40,7 +38,6 @@ declare class FormCore {
40
38
  * @param {string} [entry.action] - The action attribute of the form.
41
39
  * @param {string} [entry.method] - The method attribute of the form.
42
40
  * @param {IFormSchema.iVars} [entry.iVars] - The internal variables of the form.
43
- * @param {(data: TFormValues) => void} [entry.onSubmit] - A callback function to handle form submission.
44
41
  * @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
45
42
  */
46
43
  constructor(entry: TFormEntry & Omit<IFormSchema, 'components'>);
@@ -66,14 +63,6 @@ declare class FormCore {
66
63
  * Subscribes to templates for dynamic updates.
67
64
  */
68
65
  subscribeTemplates(): void;
69
- /**
70
- *
71
- * @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
72
- */
73
- subscribeData(callback: (payload: {
74
- field: string;
75
- data: TFormValues<Record<string, unknown>>;
76
- }) => void): void;
77
66
  /**
78
67
  * Gets the value of a property from a field.
79
68
  *
@@ -220,6 +209,15 @@ declare class FormCore {
220
209
  subscribeFieldEvent({ callback, }: {
221
210
  callback: (payload: TFieldEvent) => void;
222
211
  }): Subscription;
212
+ /**
213
+ *
214
+ * @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
215
+ */
216
+ subscribeData(callback: (payload: {
217
+ field: string;
218
+ data: TFormValues<Record<string, unknown>>;
219
+ }) => void): Subscription;
220
+ subscribeOnSubmit(callback: (payload: TFormValues<Record<string, unknown>>) => void): Subscription;
223
221
  /**
224
222
  * Submits the form by triggering form field events and invoking the onSubmit callback.
225
223
  */
@@ -79,7 +79,15 @@ declare class FormGroup {
79
79
  * @param {string[]} indexes form indexes to be submitted
80
80
  * @returns
81
81
  */
82
- submitMultipleFormsByIndex<T>(indexes: string[]): TFormValues<T>;
82
+ submitMultipleFormsByIndex<T>(indexes: string[], callback?: (payload: TFormValues<T>) => void): void;
83
+ onDataSubscription({ ids, callback, }: {
84
+ ids: string[];
85
+ callback: (payload: Record<string, {
86
+ formId: string;
87
+ formField: string;
88
+ values?: TFormValues<Record<string, unknown>>;
89
+ }>) => void;
90
+ }): import("rxjs").Subscription;
83
91
  }
84
92
  type TFormGroup = FormGroup;
85
93
  export { TFormGroup, FormGroup };
@@ -41,11 +41,6 @@ type TFormValues<T> = {
41
41
  */
42
42
  type TFormEntry = Omit<IFormSchema, 'components'> & {
43
43
  schema?: IFormSchema;
44
- onSubmit?: <T>(data: TFormValues<T>) => void;
45
- onData?: <T>(payload: {
46
- field: string;
47
- data: TFormValues<T>;
48
- }) => void;
49
44
  mappers?: TMapper<unknown>[];
50
45
  };
51
46
  export { TFormValues, TFormEntry };