@maif/react-forms 1.1.0 → 1.1.3

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 CHANGED
@@ -100,6 +100,26 @@ export const Example = () => {
100
100
  ```javascript
101
101
  ({rawValues, value, setValue}) => if (value.length) { setValue('entry', false) }
102
102
  ```
103
+ - **onAfterChange**: a callback function to the value change.
104
+ ```javascript
105
+ ({entry, value, rawValues, previousValue, getValue, setValue, onChange, informations}) => {
106
+ const otherEntryVal = getValue('otherEntry')
107
+ console.debug({entry, value, rawValues, otherEntryVal})
108
+ setValue('anotherEntry', v + 1)
109
+ const {path, parent, index} = informations
110
+ console.debug({path, parent, index})
111
+ }
112
+ ```
113
+ where :
114
+ - entry [string] is the updated entry of schema
115
+ - value [any] is the actual value of your entry
116
+ - previousValue [any] is the previous value of your entry
117
+ - rawValues [any] is the actual value of antire form
118
+ - getValue [function] is a function to get value of a form entry
119
+ - setValue [function] is a function to set value of a form entry
120
+ - onSave [function] is a function to update actual entry
121
+ - informations [Information] is an object to get information about the actual entry (path, index and parent informations)
122
+
103
123
  - **render**: a function to completely custom the rendering of form field
104
124
  ```javascript
105
125
  ({rawValues, value, onChange, error, setValue, parent}) => <input type="text" className="is-invalid" value={value} onChange={e => onChange(e.target.value)} />
package/lib/esm/index.js CHANGED
@@ -1,14 +1,15 @@
1
1
  import * as yup from 'yup';
2
2
  import * as React from 'react';
3
- import React__default, { useState, useRef, useEffect, useImperativeHandle } from 'react';
3
+ import React__default, { useState, useRef, useEffect, useCallback, useImperativeHandle } from 'react';
4
4
  import { yupResolver } from '@hookform/resolvers/yup';
5
5
  import classNames from 'classnames';
6
6
  import deepEqual from 'fast-deep-equal';
7
7
  import { Eye, EyeOff, PlusCircle, MinusCircle, Trash2, ChevronDown, ChevronUp, HelpCircle, Loader, Upload } from 'react-feather';
8
- import { useFormContext, useController, useForm, FormProvider, Controller, useFieldArray, useWatch } from 'react-hook-form';
8
+ import { useFormContext, useController, useWatch, useForm, FormProvider, Controller, useFieldArray } from 'react-hook-form';
9
9
  import { DatePicker } from 'react-rainbow-components';
10
10
  import ReactToolTip from 'react-tooltip';
11
11
  import { v4 } from 'uuid';
12
+ import debounce from 'lodash.debounce';
12
13
  import CreatableSelect from 'react-select/creatable';
13
14
  import Select from 'react-select';
14
15
  import hash$1 from 'object-hash';
@@ -278,7 +279,7 @@ const useHashEffect = (func, deps) => {
278
279
  const depsHash = cleanHash(deps);
279
280
  const prevDepsHash = cleanHash(prevDeps.current);
280
281
  if (depsHash !== prevDepsHash) {
281
- prevDeps.current = deps;
282
+ prevDeps.current = Object.assign({}, deps);
282
283
  func();
283
284
  }
284
285
  }, deps); /* FIXME deps or [deps] ? */
@@ -27921,7 +27922,7 @@ const ControlledInput = (inputProps) => {
27921
27922
  return prop;
27922
27923
  }
27923
27924
  };
27924
- const props = Object.assign(Object.assign(Object.assign({}, field), step.props), { id: entry, readOnly: functionalProperty(entry, step.disabled) ? 'readOnly' : null, placeholder: step.placeholder, onChange: (e) => {
27925
+ const props = Object.assign(Object.assign({ name: field.name }, step.props), { id: entry, readOnly: functionalProperty(entry, step.disabled) ? 'readOnly' : null, placeholder: step.placeholder, onChange: (e) => {
27925
27926
  const value = (() => {
27926
27927
  if (!e) {
27927
27928
  if (step.type === type.bool ||
@@ -27958,27 +27959,45 @@ const usePrevious = (value) => {
27958
27959
  // Return previous value (happens before update in useEffect above)
27959
27960
  return ref.current;
27960
27961
  };
27961
- const BasicWrapper = ({ entry, className, help, children, render, functionalProperty, label }) => {
27962
+ const BasicWrapper = ({ entry, children, render, functionalProperty, step }) => {
27963
+ const { formState, watch } = useFormContext();
27962
27964
  if (typeof entry === 'object') {
27963
27965
  return children;
27964
27966
  }
27965
- const computedLabel = functionalProperty(entry, label === null ? null : label || entry);
27967
+ const visibleStep = option(step)
27968
+ .map(s => s.visible)
27969
+ .map(visible => {
27970
+ let value;
27971
+ switch (typeof visible) {
27972
+ case 'object':
27973
+ value = watch(visible.ref);
27974
+ return option(visible.test).map(test => test(value)).getOrElse(value);
27975
+ case 'boolean':
27976
+ return visible;
27977
+ default:
27978
+ return true;
27979
+ }
27980
+ })
27981
+ .getOrElse(true);
27982
+ if (!visibleStep) {
27983
+ return null;
27984
+ }
27985
+ const computedLabel = functionalProperty(entry, (step === null || step === void 0 ? void 0 : step.label) === null ? null : (step === null || step === void 0 ? void 0 : step.label) || entry);
27966
27986
  const id = v4();
27967
- const { formState } = useFormContext();
27968
27987
  // FIXME not sure it works as intended with more two or more parts
27969
27988
  const error = entry.split('.').reduce((acc, curr) => acc && acc[curr], formState.errors);
27970
27989
  const isDirty = entry.split('.').reduce((acc, curr) => acc && acc[curr], formState.dirtyFields);
27971
27990
  const isTouched = entry.split('.').reduce((acc, curr) => acc && acc[curr], formState.touchedFields);
27972
27991
  const errorDisplayed = formState.isSubmitted || isDirty || isTouched;
27973
27992
  if (render) {
27974
- return render({ entry, label: computedLabel, error, help, children });
27993
+ return render({ entry, label: computedLabel, error, help: step === null || step === void 0 ? void 0 : step.help, children });
27975
27994
  }
27976
27995
  return (React__default.createElement("div", { className: 'mrf-mt_10', style: { position: 'relative' } },
27977
27996
  computedLabel && React__default.createElement("label", { className: 'mrf-flex mrf-ai_center mrf-mb_5', htmlFor: entry },
27978
27997
  React__default.createElement("span", null, computedLabel),
27979
- help && React__default.createElement(React__default.Fragment, null,
27998
+ (step === null || step === void 0 ? void 0 : step.help) && React__default.createElement(React__default.Fragment, null,
27980
27999
  React__default.createElement(ReactToolTip, { html: true, place: 'bottom', id: id }),
27981
- React__default.createElement("span", { className: 'mrf-flex mrf-ai_center', "data-html": true, "data-tip": help, "data-for": id },
28000
+ React__default.createElement("span", { className: 'mrf-flex mrf-ai_center', "data-html": true, "data-tip": step === null || step === void 0 ? void 0 : step.help, "data-for": id },
27982
28001
  React__default.createElement(HelpCircle, { style: { color: 'gray', width: 17, marginLeft: '.5rem', cursor: 'help' } })))),
27983
28002
  children,
27984
28003
  error && React__default.createElement("div", { className: classNames('mrf-feedback', { ['mrf-txt_red']: !!errorDisplayed }) }, error.message)));
@@ -28089,16 +28108,18 @@ const validate = (flow, schema, value) => {
28089
28108
  abortEarly: false
28090
28109
  });
28091
28110
  };
28092
- const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28111
+ const Watcher = React__default.memo(({ options, control, schema, onSubmit, handleSubmit }) => {
28093
28112
  const data = useWatch({ control });
28113
+ const realSubmit = (d) => handleSubmit(() => {
28114
+ onSubmit(d);
28115
+ })();
28116
+ const debouncedSubmit = useCallback(debounce(realSubmit, 250, { leading: true }), []);
28094
28117
  useHashEffect(() => {
28095
- if (options.autosubmit) {
28096
- handleSubmit(() => {
28097
- onSubmit(cleanOutputArray(data, schema));
28098
- })();
28118
+ if (options === null || options === void 0 ? void 0 : options.autosubmit) {
28119
+ debouncedSubmit(data);
28099
28120
  }
28100
28121
  }, [data]);
28101
- if (options.watch) {
28122
+ if (options === null || options === void 0 ? void 0 : options.watch) {
28102
28123
  if (typeof options.watch === 'function') {
28103
28124
  options.watch(cleanOutputArray(data, schema));
28104
28125
  }
@@ -28109,7 +28130,9 @@ const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28109
28130
  }
28110
28131
  }
28111
28132
  return null;
28112
- };
28133
+ }, () => {
28134
+ return true;
28135
+ });
28113
28136
  const Form = React__default.forwardRef(function Form({ schema, flow, value, inputWrapper, onSubmit, onError = () => { }, footer, style = {}, className, options = {}, nostyle }, ref) {
28114
28137
  const formFlow = flow || Object.keys(schema);
28115
28138
  const maybeCustomHttpClient = (url, method) => {
@@ -28179,25 +28202,7 @@ const Form = React__default.forwardRef(function Form({ schema, flow, value, inpu
28179
28202
  console.error(`no step found for the entry "${entry}" in the given schema. Your form might not work properly. Please fix it`);
28180
28203
  return null;
28181
28204
  }
28182
- const visibleStep = option(step)
28183
- .map((s) => s.visible)
28184
- .map((visible) => {
28185
- let value;
28186
- switch (typeof visible) {
28187
- case 'object':
28188
- value = getValues(visible.ref);
28189
- return option(visible.test).map(test => test(value, idx)).getOrElse(value);
28190
- case 'boolean':
28191
- return visible;
28192
- default:
28193
- return true;
28194
- }
28195
- })
28196
- .getOrElse(true);
28197
- if (!visibleStep) {
28198
- return null;
28199
- }
28200
- return (React__default.createElement(BasicWrapper, { key: `${entry}-${idx}`, entry: entry, functionalProperty: functionalProperty, label: step === null || step === void 0 ? void 0 : step.label, help: step === null || step === void 0 ? void 0 : step.help, render: inputWrapper },
28205
+ return (React__default.createElement(BasicWrapper, { key: `${entry}-${idx}`, entry: entry, functionalProperty: functionalProperty, render: inputWrapper, step: step },
28201
28206
  React__default.createElement(Step, { key: idx, entry: entry, step: step, schema: schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, functionalProperty: functionalProperty })));
28202
28207
  }),
28203
28208
  React__default.createElement(Footer, { render: footer, reset: () => reset(defaultValues), valid: handleSubmit(data => onSubmit(cleanOutputArray(data, schema)), onError), actions: options.actions }))));
@@ -28214,8 +28219,8 @@ const Footer = (props) => {
28214
28219
  isSubmitDisplayed && React__default.createElement("button", { className: 'mrf-btn mrf-btn_green mrf-ml_10', type: "submit" }, ((_p = (_o = props.actions) === null || _o === void 0 ? void 0 : _o.submit) === null || _p === void 0 ? void 0 : _p.label) || 'Save')));
28215
28220
  };
28216
28221
  const Step = (props) => {
28217
- let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, onAfterChange } = props;
28218
- const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, trigger, getValues, setValue, watch, register } = useFormContext();
28222
+ let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, parentInformations } = props;
28223
+ const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, getValues, setValue, watch } = useFormContext();
28219
28224
  if (entry && typeof entry === 'object') {
28220
28225
  const errored = extractFlowString(entry).some(step => !!errors[step] && (dirtyFields[step] || touchedFields[step]));
28221
28226
  return (React__default.createElement(Collapse, Object.assign({}, entry, { errored: errored }), entry.flow.map((en, entryIdx) => {
@@ -28224,32 +28229,15 @@ const Step = (props) => {
28224
28229
  console.error(`no step found for the entry "${en}" in the given schema. Your form might not work properly. Please fix it`);
28225
28230
  return null;
28226
28231
  }
28227
- const visibleStep = option(stp)
28228
- .map(s => s.visible)
28229
- .map(visible => {
28230
- let value;
28231
- switch (typeof visible) {
28232
- case 'object':
28233
- value = getValues(visible.ref);
28234
- return option(visible.test).map(test => test(value, index)).getOrElse(value);
28235
- case 'boolean':
28236
- return visible;
28237
- default:
28238
- return true;
28239
- }
28240
- })
28241
- .getOrElse(true);
28242
- if (!visibleStep) {
28243
- return null;
28244
- }
28245
- return (React__default.createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, label: stp === null || stp === void 0 ? void 0 : stp.label, help: stp === null || stp === void 0 ? void 0 : stp.help, render: inputWrapper },
28246
- React__default.createElement(Step, { entry: en, step: stp, schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: stp === null || stp === void 0 ? void 0 : stp.defaultValue, functionalProperty: functionalProperty })));
28232
+ return (React__default.createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, step: stp, render: inputWrapper },
28233
+ React__default.createElement(Step, { entry: en, step: stp, schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: stp === null || stp === void 0 ? void 0 : stp.defaultValue, functionalProperty: functionalProperty, parentInformations: parentInformations })));
28247
28234
  })));
28248
28235
  }
28249
28236
  const error = entry.split('.').reduce((acc, curr) => acc && acc[curr], errors);
28250
28237
  const isDirty = entry.split('.').reduce((acc, curr) => acc && acc[curr], dirtyFields);
28251
28238
  const isTouched = entry.split('.').reduce((acc, curr) => acc && acc[curr], touchedFields);
28252
28239
  const errorDisplayed = (!!error && (isSubmitted || isDirty || isTouched));
28240
+ const informations = { path: entry, parent: parentInformations, index };
28253
28241
  step = step;
28254
28242
  if (step.onAfterChange) {
28255
28243
  const data = watch();
@@ -28263,11 +28251,12 @@ const Step = (props) => {
28263
28251
  step.onAfterChange({
28264
28252
  entry,
28265
28253
  value: getValues(entry),
28266
- rawValues: newData,
28254
+ rawValues: getValues(),
28267
28255
  previousValue: currentData,
28268
28256
  getValue: (e) => getValues(e),
28269
28257
  setValue,
28270
- onChange: (v) => setValue(entry, v)
28258
+ onChange: (v) => setValue(entry, v),
28259
+ informations
28271
28260
  });
28272
28261
  }
28273
28262
  if (step.array) {
@@ -28276,7 +28265,7 @@ const Step = (props) => {
28276
28265
  }, error: !!error },
28277
28266
  React__default.createElement(ArrayStep, { entry: entry, step: step, disabled: functionalProperty(entry, step.disabled || false), component: ((props, idx) => {
28278
28267
  var _a;
28279
- return (React__default.createElement(Step, { entry: `${entry}.${idx}.value`, step: Object.assign(Object.assign({}, (schema[realEntry || entry])), { render: step.itemRender, onChange: undefined, array: false, onAfterChange: step.onAfterChange }), schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: (_a = props.defaultValue) === null || _a === void 0 ? void 0 : _a.value, index: idx, functionalProperty: functionalProperty }));
28268
+ return (React__default.createElement(Step, { entry: `${entry}.${idx}.value`, step: Object.assign(Object.assign({}, (schema[realEntry || entry])), { render: step.itemRender, onChange: undefined, array: false, onAfterChange: step.onAfterChange }), schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: (_a = props.defaultValue) === null || _a === void 0 ? void 0 : _a.value, index: idx, functionalProperty: functionalProperty, parentInformations: informations }));
28280
28269
  }) })));
28281
28270
  }
28282
28271
  switch (step.type) {
@@ -28296,7 +28285,7 @@ const Step = (props) => {
28296
28285
  case format.buttonsSelect:
28297
28286
  case format.select: {
28298
28287
  return (React__default.createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
28299
- React__default.createElement(SelectInput, Object.assign({ className: classNames('mrf-flex_grow_1', step.className, { 'mrf-input__invalid': !!errorDisplayed }), disabled: functionalProperty(entry, step.disabled || false) }, step.props, { possibleValues: step.options, httpClient: httpClient, isMulti: step.isMulti, createOption: step.createOption, transformer: step.transformer, buttons: step.format === format.buttonsSelect, optionsFrom: step.optionsFrom }))));
28288
+ React__default.createElement(SelectInput, Object.assign({ className: classNames('mrf-flex_grow_1', step.className, { 'mrf-input__invalid': !!errorDisplayed }), disabled: functionalProperty(entry, step.disabled || false) }, step.props, { possibleValues: step.options, httpClient: httpClient, isMulti: step.isMulti, createOption: step.createOption, onCreateOption: step.onCreateOption, transformer: step.transformer, buttons: step.format === format.buttonsSelect, optionsFrom: step.optionsFrom }))));
28300
28289
  }
28301
28290
  default:
28302
28291
  return (React__default.createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
@@ -28324,7 +28313,7 @@ const Step = (props) => {
28324
28313
  case format.form: //todo: disabled ?
28325
28314
  const flow = option(step.flow).getOrElse(option(step.schema).map(s => Object.keys(s)).getOrElse([]));
28326
28315
  return (React__default.createElement(CustomizableInput, { render: step.render, field: { parent, setValue: (key, value) => setValue(key, value), rawValues: getValues(), value: getValues(entry), onChange: (v) => setValue(entry, v, { shouldValidate: true }) } },
28327
- React__default.createElement(NestedForm, { schema: step.schema, flow: flow, step: step, parent: entry, inputWrapper: inputWrapper, maybeCustomHttpClient: httpClient, value: getValues(entry) || defaultValue, index: index, functionalProperty: functionalProperty, errorDisplayed: errorDisplayed })));
28316
+ React__default.createElement(NestedForm, { schema: step.schema, flow: flow, step: step, parent: entry, inputWrapper: inputWrapper, maybeCustomHttpClient: httpClient, value: getValues(entry) || defaultValue, functionalProperty: functionalProperty, errorDisplayed: errorDisplayed, informations: informations })));
28328
28317
  case format.code:
28329
28318
  return (React__default.createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed, component: (field, props) => (React__default.createElement(CodeInput, Object.assign({}, props, {
28330
28319
  /* TODO className={classNames(step.className, { 'mrf-input__invalid': !!error })}*/
@@ -28415,9 +28404,9 @@ const ArrayStep = ({ entry, step, component, disabled }) => {
28415
28404
  }, disabled: disabled }, "Add"),
28416
28405
  error && React__default.createElement("div", { className: "mrf-invalid-feedback" }, error.message))));
28417
28406
  };
28418
- const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, index }) => {
28407
+ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, informations }) => {
28419
28408
  var _a;
28420
- const { getValues, setValue, watch, control, formState: { errors, dirtyFields, touchedFields } } = useFormContext();
28409
+ const { getValues, setValue, control, formState: { errors, dirtyFields, touchedFields } } = useFormContext();
28421
28410
  const [collapsed, setCollapsed] = useState(!!step.collapsed);
28422
28411
  useWatch({ name: ((_a = step === null || step === void 0 ? void 0 : step.conditionalSchema) === null || _a === void 0 ? void 0 : _a.ref) || "", control });
28423
28412
  const schemaAndFlow = option(step.conditionalSchema)
@@ -28444,29 +28433,15 @@ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient,
28444
28433
  }, [schemaAndFlow.schema]);
28445
28434
  const computedSandF = schemaAndFlow.flow.reduce((acc, entry) => {
28446
28435
  const step = (typeof entry === "string") ? schemaAndFlow.schema[entry] : schemaAndFlow.schema[entry.label];
28447
- const visibleStep = option(step)
28448
- .map(s => s.visible)
28449
- .map(visible => {
28450
- switch (typeof visible) {
28451
- case 'object':
28452
- const value = watch(visible.ref);
28453
- return option(visible.test).map(test => test(value, index)).getOrElse(value);
28454
- case 'boolean':
28455
- return visible;
28456
- default:
28457
- return true;
28458
- }
28459
- })
28460
- .getOrElse(true);
28461
- return [...acc, { step, visibleStep, entry }];
28436
+ return [...acc, { step, entry }];
28462
28437
  }, []);
28463
- const bordered = computedSandF.filter(x => x.visibleStep).length >= 1 && step.label !== null;
28438
+ const bordered = computedSandF.length >= 1 && step.label !== null;
28464
28439
  return (React__default.createElement("div", { className: classNames({ ['mrf-nestedform__border']: bordered, ['mrf-border__error']: !!errorDisplayed }), style: { position: 'relative' } },
28465
28440
  !!step.collapsable && schemaAndFlow.flow.length > 1 && collapsed &&
28466
28441
  React__default.createElement(ChevronDown, { size: 30, className: 'mrf-cursor_pointer', style: { position: 'absolute', top: -35, right: 0, zIndex: 100 }, strokeWidth: "2", onClick: () => setCollapsed(!collapsed) }),
28467
28442
  !!step.collapsable && schemaAndFlow.flow.length > 1 && !collapsed &&
28468
28443
  React__default.createElement(ChevronUp, { size: 30, className: 'mrf-cursor_pointer', style: { position: 'absolute', top: -35, right: 0, zIndex: 100 }, strokeWidth: "2", onClick: () => setCollapsed(!collapsed) }),
28469
- computedSandF.map(({ step, visibleStep, entry }, idx) => {
28444
+ computedSandF.map(({ step, entry }, idx) => {
28470
28445
  if (!step && typeof entry === 'string') {
28471
28446
  console.error(`no step found for the entry "${entry}" in the given schema. Your form might not work properly. Please fix it`);
28472
28447
  return null;
@@ -28479,31 +28454,13 @@ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient,
28479
28454
  console.error(`no step found for the entry "${en}" in the given schema. Your form might not work properly. Please fix it`);
28480
28455
  return null;
28481
28456
  }
28482
- const visibleStep = option(stp)
28483
- .map(s => s.visible)
28484
- .map(visible => {
28485
- let value;
28486
- switch (typeof visible) {
28487
- case 'object':
28488
- value = getValues(visible.ref);
28489
- return option(visible.test).map(test => test(value, index)).getOrElse(value);
28490
- case 'boolean':
28491
- return visible;
28492
- default:
28493
- return true;
28494
- }
28495
- })
28496
- .getOrElse(true);
28497
- if (!visibleStep) {
28498
- return null;
28499
- }
28500
- return (React__default.createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, label: (step === null || step === void 0 ? void 0 : step.label) === null ? null : (step === null || step === void 0 ? void 0 : step.label) || entry, help: stp === null || stp === void 0 ? void 0 : stp.help, render: inputWrapper },
28457
+ return (React__default.createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, step: stp, render: inputWrapper },
28501
28458
  React__default.createElement(Step, { entry: en, step: stp, schema: schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, defaultValue: stp === null || stp === void 0 ? void 0 : stp.defaultValue, functionalProperty: functionalProperty })));
28502
28459
  }));
28503
28460
  // TODO return collapse, then entry will always be a string in below return
28504
28461
  }
28505
- return (React__default.createElement(BasicWrapper, { key: `${entry}.${idx}`, className: classNames({ ['mrf-display__none']: (collapsed && !step.visibleOnCollapse) || !visibleStep }), entry: `${parent}.${entry}`, functionalProperty: functionalProperty, label: (step === null || step === void 0 ? void 0 : step.label) === null ? null : (step === null || step === void 0 ? void 0 : step.label) || entry, help: step.help, render: inputWrapper },
28506
- React__default.createElement(Step, { key: `step.${entry}.${idx}`, entry: `${parent}.${entry}`, realEntry: entry, step: schemaAndFlow.schema[entry], parent: parent, schema: schemaAndFlow.schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, defaultValue: value && value[entry], functionalProperty: functionalProperty })));
28462
+ return (React__default.createElement(BasicWrapper, { key: `${entry}.${idx}`, className: classNames({ ['mrf-display__none']: (collapsed && !step.visibleOnCollapse) }), entry: `${parent}.${entry}`, functionalProperty: functionalProperty, step: step, render: inputWrapper },
28463
+ React__default.createElement(Step, { key: `step.${entry}.${idx}`, entry: `${parent}.${entry}`, realEntry: entry, step: schemaAndFlow.schema[entry], parent: parent, schema: schemaAndFlow.schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, defaultValue: value && value[entry], functionalProperty: functionalProperty, parentInformations: informations })));
28507
28464
  })));
28508
28465
  };
28509
28466
  function extractFlowString(entry) {
package/lib/index.d.ts ADDED
@@ -0,0 +1,367 @@
1
+ /// <reference types="react" />
2
+ import * as yup_lib_types from 'yup/lib/types';
3
+ import * as yup from 'yup';
4
+ import { AnySchema, StringSchema, NumberSchema, ArraySchema, TestFunction } from 'yup';
5
+ import Reference from 'yup/lib/Reference';
6
+ import * as yup_lib_object from 'yup/lib/object';
7
+ import React from 'react';
8
+
9
+ declare const type: {
10
+ readonly string: "string";
11
+ readonly number: "number";
12
+ readonly bool: "bool";
13
+ readonly date: "date";
14
+ readonly object: "object";
15
+ readonly file: "file";
16
+ readonly json: "json";
17
+ };
18
+ declare let typeValues: ("string" | "number" | "object" | "json" | "bool" | "date" | "file")[];
19
+ declare type Type = typeof typeValues[number];
20
+
21
+ declare const format: {
22
+ readonly array: "array";
23
+ readonly select: "select";
24
+ readonly code: "code";
25
+ readonly markdown: "markdown";
26
+ readonly text: "textarea";
27
+ readonly textarea: "textarea";
28
+ readonly email: "email";
29
+ readonly password: "password";
30
+ readonly hidden: "hidden";
31
+ readonly form: "form";
32
+ readonly buttonsSelect: "buttons";
33
+ readonly singleLineCode: "singleLineCode";
34
+ };
35
+ declare let formatValues: ("markdown" | "email" | "array" | "select" | "code" | "textarea" | "password" | "hidden" | "form" | "buttons" | "singleLineCode")[];
36
+ declare type Format = typeof formatValues[number];
37
+
38
+ declare type Constraint = (resolver: any, key: string, dependencies: any[]) => AnySchema;
39
+ declare type NumberRef = Reference<number> | number;
40
+ declare const required: (message?: string) => (r: AnySchema) => any;
41
+ declare const url: (message?: string) => (r: StringSchema) => yup.StringSchema<string | undefined, yup_lib_types.AnyObject, string | undefined>;
42
+ declare const email: (message?: string) => (r: StringSchema) => yup.StringSchema<string | undefined, yup_lib_types.AnyObject, string | undefined>;
43
+ declare const uuid: (message?: string) => (r: StringSchema) => yup.StringSchema<string | undefined, yup_lib_types.AnyObject, string | undefined>;
44
+ declare const matches: (regexp?: RegExp, message?: string) => (r: StringSchema) => yup.StringSchema<string | undefined, yup_lib_types.AnyObject, string | undefined>;
45
+ declare const min: (ref: NumberRef, message?: string) => (r: StringSchema | NumberSchema) => yup.StringSchema<string | undefined, yup_lib_types.AnyObject, string | undefined> | yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
46
+ declare const max: (ref: NumberRef, message?: string) => (r: StringSchema | NumberSchema) => yup.StringSchema<string | undefined, yup_lib_types.AnyObject, string | undefined> | yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
47
+ declare const positive: (message?: string) => (r: NumberSchema) => yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
48
+ declare const negative: (message?: string) => (r: NumberSchema) => yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
49
+ declare const integer: (message?: string) => (r: NumberSchema) => yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
50
+ declare const lessThan: (ref: NumberRef, message?: string) => (r: NumberSchema, key: any, dependencies: Array<[any, Reference]>) => yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
51
+ declare const moreThan: (ref: NumberRef, message?: string) => (r: NumberSchema, key: any, dependencies: Array<[any, Reference]>) => yup.NumberSchema<number | undefined, yup_lib_types.AnyObject, number | undefined>;
52
+ declare const length: (ref: NumberRef, message?: string) => (r: ArraySchema<any>) => yup.ArraySchema<any, yup_lib_types.AnyObject, any[] | undefined, any[] | undefined>;
53
+ declare const supportedFormat: (arrayOfValues: string[], message?: string) => (r: AnySchema) => yup.AnySchema<any, any, any>;
54
+ declare const unsupportedFormat: (arrayOfValues: string[], message?: string) => (r: AnySchema) => yup.AnySchema<any, any, any>;
55
+ declare const maxSize: (ref: Reference, message?: string) => (r: AnySchema) => yup.AnySchema<any, any, any>;
56
+ declare const test: (name: string, message: string | undefined, test: TestFunction<any, object>) => (r: AnySchema) => yup.AnySchema<any, any, any>;
57
+ declare const when: (ref: string, test: TestFunction<any, object>, then?: Constraint[], otherwise?: Constraint[]) => (r: AnySchema, key: string, dependencies: any[]) => yup.AnySchema<any, any, any>;
58
+ declare const oneOf: (arrayOfValues: any[], message?: string) => (r: AnySchema) => yup.AnySchema<any, any, any>;
59
+ declare const blacklist: (arrayOfValues: any[], message?: string) => (r: AnySchema) => yup.AnySchema<any, any, any>;
60
+ declare const ref: (ref: string) => Reference<unknown>;
61
+ declare const jsonConstraints: Record<string, any>;
62
+ declare type TConstraintType = keyof typeof jsonConstraints;
63
+
64
+ type constraints_d_Constraint = Constraint;
65
+ declare const constraints_d_required: typeof required;
66
+ declare const constraints_d_url: typeof url;
67
+ declare const constraints_d_email: typeof email;
68
+ declare const constraints_d_uuid: typeof uuid;
69
+ declare const constraints_d_matches: typeof matches;
70
+ declare const constraints_d_min: typeof min;
71
+ declare const constraints_d_max: typeof max;
72
+ declare const constraints_d_positive: typeof positive;
73
+ declare const constraints_d_negative: typeof negative;
74
+ declare const constraints_d_integer: typeof integer;
75
+ declare const constraints_d_lessThan: typeof lessThan;
76
+ declare const constraints_d_moreThan: typeof moreThan;
77
+ declare const constraints_d_length: typeof length;
78
+ declare const constraints_d_supportedFormat: typeof supportedFormat;
79
+ declare const constraints_d_unsupportedFormat: typeof unsupportedFormat;
80
+ declare const constraints_d_maxSize: typeof maxSize;
81
+ declare const constraints_d_test: typeof test;
82
+ declare const constraints_d_when: typeof when;
83
+ declare const constraints_d_oneOf: typeof oneOf;
84
+ declare const constraints_d_blacklist: typeof blacklist;
85
+ declare const constraints_d_ref: typeof ref;
86
+ declare const constraints_d_jsonConstraints: typeof jsonConstraints;
87
+ type constraints_d_TConstraintType = TConstraintType;
88
+ declare namespace constraints_d {
89
+ export {
90
+ constraints_d_Constraint as Constraint,
91
+ constraints_d_required as required,
92
+ constraints_d_url as url,
93
+ constraints_d_email as email,
94
+ constraints_d_uuid as uuid,
95
+ constraints_d_matches as matches,
96
+ constraints_d_min as min,
97
+ constraints_d_max as max,
98
+ constraints_d_positive as positive,
99
+ constraints_d_negative as negative,
100
+ constraints_d_integer as integer,
101
+ constraints_d_lessThan as lessThan,
102
+ constraints_d_moreThan as moreThan,
103
+ constraints_d_length as length,
104
+ constraints_d_supportedFormat as supportedFormat,
105
+ constraints_d_unsupportedFormat as unsupportedFormat,
106
+ constraints_d_maxSize as maxSize,
107
+ constraints_d_test as test,
108
+ constraints_d_when as when,
109
+ constraints_d_oneOf as oneOf,
110
+ constraints_d_blacklist as blacklist,
111
+ constraints_d_ref as ref,
112
+ constraints_d_jsonConstraints as jsonConstraints,
113
+ constraints_d_TConstraintType as TConstraintType,
114
+ };
115
+ }
116
+
117
+ interface PropType {
118
+ onChange?: (v: boolean) => void;
119
+ value?: boolean;
120
+ readOnly?: boolean;
121
+ }
122
+ declare const BooleanInput: React.ForwardRefExoticComponent<PropType & React.RefAttributes<HTMLInputElement>>;
123
+
124
+ declare const Collapse: (props: {
125
+ initCollapsed?: boolean;
126
+ collapsed?: boolean;
127
+ errored: boolean;
128
+ label?: React.ReactNode;
129
+ inline?: any;
130
+ children: React.ReactNode;
131
+ lineEnd?: boolean;
132
+ }) => JSX.Element;
133
+
134
+ declare type SelectOption = {
135
+ label: string;
136
+ value: any;
137
+ };
138
+ declare const SelectInput: <T extends {
139
+ [x: string]: any;
140
+ }>(props: {
141
+ possibleValues?: T[] | undefined;
142
+ transformer?: {
143
+ label: string;
144
+ value: string;
145
+ } | ((v: T) => SelectOption) | undefined;
146
+ value?: any;
147
+ defaultValue?: any;
148
+ isMulti?: boolean | undefined;
149
+ optionsFrom?: string | Promise<T[]> | ((param: {
150
+ rawValues: object;
151
+ value: any;
152
+ }) => string | Promise<T[]>) | undefined;
153
+ fetchCondition?: (() => boolean) | undefined;
154
+ id?: string | undefined;
155
+ httpClient?: ((url: string, method: string) => Promise<Response>) | undefined;
156
+ onChange?: ((options: any[] | any) => void) | undefined;
157
+ onCreateOption?: ((option: string) => T) | undefined;
158
+ buttons: boolean;
159
+ disabled?: boolean | undefined;
160
+ createOption?: boolean | undefined;
161
+ label?: string | undefined;
162
+ placeholder?: React.ReactNode;
163
+ className: string;
164
+ }) => JSX.Element;
165
+
166
+ declare type InternalState = {
167
+ [x: string]: {
168
+ key: string;
169
+ value: any;
170
+ };
171
+ };
172
+ declare const ObjectInput: (props: {
173
+ value?: object | undefined;
174
+ onChange?: ((value: InternalState) => void) | undefined;
175
+ defaultKeyValue?: {
176
+ key: string;
177
+ value: string;
178
+ } | undefined;
179
+ className: string;
180
+ disabled?: boolean | undefined;
181
+ placeholderKey?: string | undefined;
182
+ placeholderValue?: string | undefined;
183
+ }) => JSX.Element;
184
+
185
+ declare type LanguageMode = "javascript" | "css" | "json" | "html" | "markdown";
186
+
187
+ declare function CodeInput({ onChange, value, mode, tabSize, readOnly, showLinesNumber, highlightLine, themeStyle, setRef }: {
188
+ onChange?: (v: string) => void;
189
+ value?: string;
190
+ mode?: LanguageMode;
191
+ tabSize?: number;
192
+ readOnly?: boolean;
193
+ showLinesNumber?: boolean;
194
+ highlightLine?: boolean;
195
+ themeStyle?: {
196
+ height: string;
197
+ minHeight: string;
198
+ maxHeight: string;
199
+ width: string;
200
+ minWidth: string;
201
+ maxWidth: string;
202
+ };
203
+ setRef?: (editor: any) => void;
204
+ }): JSX.Element;
205
+
206
+ declare const MarkdownInput: (props: {
207
+ value?: string | undefined;
208
+ preview?: boolean | undefined;
209
+ className: string;
210
+ readOnly?: boolean | undefined;
211
+ onChange?: ((value: string) => void) | undefined;
212
+ }) => JSX.Element;
213
+
214
+ declare function SingleLineCode({ onChange, value, mode, tabSize, readOnly, showLinesNumber, highlightLine, themeStyle }: {
215
+ onChange?: (newValue: string) => void;
216
+ value?: string;
217
+ mode?: LanguageMode;
218
+ tabSize?: number;
219
+ readOnly?: boolean;
220
+ showLinesNumber?: boolean;
221
+ highlightLine?: boolean;
222
+ themeStyle?: {
223
+ height: string;
224
+ minHeight: string;
225
+ maxHeight: string;
226
+ width: string;
227
+ minWidth: string;
228
+ maxWidth: string;
229
+ };
230
+ }): JSX.Element;
231
+
232
+ interface OptionActionItem {
233
+ display?: boolean;
234
+ label?: string;
235
+ }
236
+ interface OptionActions {
237
+ reset?: OptionActionItem;
238
+ submit?: OptionActionItem;
239
+ }
240
+ declare type HttpClient = (url: string, method: string) => Promise<Response>;
241
+ interface Option {
242
+ httpClient?: HttpClient;
243
+ watch?: boolean | ((param: any) => void);
244
+ autosubmit?: boolean;
245
+ actions?: OptionActions;
246
+ showErrorsOnStart?: boolean;
247
+ }
248
+ interface Schema {
249
+ [key: string]: SchemaEntry;
250
+ }
251
+ declare type SchemaRenderType = ({ rawValues, value, onChange, error, setValue, parent }: {
252
+ rawValues?: any;
253
+ value?: any;
254
+ onChange?: (param: object) => void;
255
+ error?: boolean;
256
+ parent?: string;
257
+ setValue?: (data: any) => void;
258
+ }) => JSX.Element;
259
+ interface ConditionnalSchemaElement {
260
+ default?: boolean;
261
+ condition?: ({ rawValues, ref }: {
262
+ rawValues: {
263
+ [x: string]: any;
264
+ };
265
+ ref: any;
266
+ }) => boolean | any;
267
+ schema: Schema;
268
+ flow: Array<FlowObject | string>;
269
+ }
270
+ interface ConditionnalSchema {
271
+ ref: string;
272
+ switch: ConditionnalSchemaElement[];
273
+ }
274
+ interface SchemaEntry {
275
+ schema?: Schema;
276
+ type: Type;
277
+ format?: Format;
278
+ array?: boolean;
279
+ createOption?: boolean;
280
+ onCreateOption?: (option: string) => any;
281
+ isMulti?: boolean;
282
+ defaultKeyValue?: object;
283
+ visible?: boolean | {
284
+ ref: string;
285
+ test: (b: any, idx?: number) => boolean;
286
+ };
287
+ disabled?: boolean | ((prop: {
288
+ rawValues: {
289
+ [x: string]: any;
290
+ };
291
+ value: any;
292
+ }) => boolean);
293
+ label?: React.ReactNode | ((prop: {
294
+ rawValues: {
295
+ [x: string]: any;
296
+ };
297
+ value: any;
298
+ }) => React.ReactNode);
299
+ placeholder?: string;
300
+ defaultValue?: any;
301
+ help?: string;
302
+ className?: string;
303
+ style?: object;
304
+ onChange?: (param: object) => void;
305
+ render?: SchemaRenderType;
306
+ itemRender?: SchemaRenderType;
307
+ props?: object;
308
+ options?: Array<any | {
309
+ label: string;
310
+ value: any;
311
+ }>;
312
+ optionsFrom?: string;
313
+ transformer?: ((v: any) => SelectOption) | {
314
+ label: string;
315
+ value: string;
316
+ };
317
+ conditionalSchema?: ConditionnalSchema;
318
+ constraints?: Array<Constraint | {
319
+ type: TConstraintType;
320
+ message?: string;
321
+ }>;
322
+ flow?: Array<string | FlowObject>;
323
+ onAfterChange?: (obj: {
324
+ entry: string;
325
+ value: object;
326
+ rawValues: object;
327
+ previousValue?: object;
328
+ getValue: (entry: string) => any;
329
+ setValue: (entry: string, value: any) => void;
330
+ onChange: (v: any) => void;
331
+ informations?: Informations;
332
+ }) => void;
333
+ visibleOnCollapse?: boolean;
334
+ addableDefaultValue?: any;
335
+ collapsed?: boolean;
336
+ collapsable?: boolean;
337
+ }
338
+ interface FlowObject {
339
+ label: string;
340
+ flow: Flow;
341
+ collapse: boolean;
342
+ }
343
+ declare type Flow = Array<string | FlowObject>;
344
+ interface Informations {
345
+ path: string;
346
+ parent?: Informations;
347
+ index?: number;
348
+ }
349
+ declare const validate: (flow: string[], schema: Schema, value: object) => Promise<yup_lib_object.AssertsShape<yup_lib_object.Assign<yup_lib_object.ObjectShape, yup_lib_object.ObjectShape>>>;
350
+ declare const Form: React.ForwardRefExoticComponent<{
351
+ schema: Schema;
352
+ flow: Array<string | FlowObject>;
353
+ value?: object | undefined;
354
+ inputWrapper?: ((props: object) => JSX.Element) | undefined;
355
+ onSubmit: (obj: object) => void;
356
+ onError?: (() => void) | undefined;
357
+ footer?: ((props: {
358
+ reset: () => void;
359
+ valid: () => void;
360
+ }) => JSX.Element) | undefined;
361
+ style?: object | undefined;
362
+ className?: string | undefined;
363
+ options?: Option | undefined;
364
+ nostyle: boolean;
365
+ } & React.RefAttributes<unknown>>;
366
+
367
+ export { BooleanInput, CodeInput, Collapse, ConditionnalSchema, Flow, Form, Format, MarkdownInput, ObjectInput, Schema, SchemaEntry, SelectInput, SelectOption, SingleLineCode, Type, constraints_d as constraints, format, type, validate };
package/lib/index.js CHANGED
@@ -12,6 +12,7 @@ var reactHookForm = require('react-hook-form');
12
12
  var reactRainbowComponents = require('react-rainbow-components');
13
13
  var ReactToolTip = require('react-tooltip');
14
14
  var uuid$1 = require('uuid');
15
+ var debounce = require('lodash.debounce');
15
16
  var CreatableSelect = require('react-select/creatable');
16
17
  var Select = require('react-select');
17
18
  var hash$1 = require('object-hash');
@@ -46,6 +47,7 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
46
47
  var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
47
48
  var deepEqual__default = /*#__PURE__*/_interopDefaultLegacy(deepEqual);
48
49
  var ReactToolTip__default = /*#__PURE__*/_interopDefaultLegacy(ReactToolTip);
50
+ var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
49
51
  var CreatableSelect__default = /*#__PURE__*/_interopDefaultLegacy(CreatableSelect);
50
52
  var Select__default = /*#__PURE__*/_interopDefaultLegacy(Select);
51
53
  var hash__default = /*#__PURE__*/_interopDefaultLegacy(hash$1);
@@ -313,7 +315,7 @@ const useHashEffect = (func, deps) => {
313
315
  const depsHash = cleanHash(deps);
314
316
  const prevDepsHash = cleanHash(prevDeps.current);
315
317
  if (depsHash !== prevDepsHash) {
316
- prevDeps.current = deps;
318
+ prevDeps.current = Object.assign({}, deps);
317
319
  func();
318
320
  }
319
321
  }, deps); /* FIXME deps or [deps] ? */
@@ -27956,7 +27958,7 @@ const ControlledInput = (inputProps) => {
27956
27958
  return prop;
27957
27959
  }
27958
27960
  };
27959
- const props = Object.assign(Object.assign(Object.assign({}, field), step.props), { id: entry, readOnly: functionalProperty(entry, step.disabled) ? 'readOnly' : null, placeholder: step.placeholder, onChange: (e) => {
27961
+ const props = Object.assign(Object.assign({ name: field.name }, step.props), { id: entry, readOnly: functionalProperty(entry, step.disabled) ? 'readOnly' : null, placeholder: step.placeholder, onChange: (e) => {
27960
27962
  const value = (() => {
27961
27963
  if (!e) {
27962
27964
  if (step.type === type.bool ||
@@ -27993,27 +27995,45 @@ const usePrevious = (value) => {
27993
27995
  // Return previous value (happens before update in useEffect above)
27994
27996
  return ref.current;
27995
27997
  };
27996
- const BasicWrapper = ({ entry, className, help, children, render, functionalProperty, label }) => {
27998
+ const BasicWrapper = ({ entry, children, render, functionalProperty, step }) => {
27999
+ const { formState, watch } = reactHookForm.useFormContext();
27997
28000
  if (typeof entry === 'object') {
27998
28001
  return children;
27999
28002
  }
28000
- const computedLabel = functionalProperty(entry, label === null ? null : label || entry);
28003
+ const visibleStep = option(step)
28004
+ .map(s => s.visible)
28005
+ .map(visible => {
28006
+ let value;
28007
+ switch (typeof visible) {
28008
+ case 'object':
28009
+ value = watch(visible.ref);
28010
+ return option(visible.test).map(test => test(value)).getOrElse(value);
28011
+ case 'boolean':
28012
+ return visible;
28013
+ default:
28014
+ return true;
28015
+ }
28016
+ })
28017
+ .getOrElse(true);
28018
+ if (!visibleStep) {
28019
+ return null;
28020
+ }
28021
+ const computedLabel = functionalProperty(entry, (step === null || step === void 0 ? void 0 : step.label) === null ? null : (step === null || step === void 0 ? void 0 : step.label) || entry);
28001
28022
  const id = uuid$1.v4();
28002
- const { formState } = reactHookForm.useFormContext();
28003
28023
  // FIXME not sure it works as intended with more two or more parts
28004
28024
  const error = entry.split('.').reduce((acc, curr) => acc && acc[curr], formState.errors);
28005
28025
  const isDirty = entry.split('.').reduce((acc, curr) => acc && acc[curr], formState.dirtyFields);
28006
28026
  const isTouched = entry.split('.').reduce((acc, curr) => acc && acc[curr], formState.touchedFields);
28007
28027
  const errorDisplayed = formState.isSubmitted || isDirty || isTouched;
28008
28028
  if (render) {
28009
- return render({ entry, label: computedLabel, error, help, children });
28029
+ return render({ entry, label: computedLabel, error, help: step === null || step === void 0 ? void 0 : step.help, children });
28010
28030
  }
28011
28031
  return (React__default["default"].createElement("div", { className: 'mrf-mt_10', style: { position: 'relative' } },
28012
28032
  computedLabel && React__default["default"].createElement("label", { className: 'mrf-flex mrf-ai_center mrf-mb_5', htmlFor: entry },
28013
28033
  React__default["default"].createElement("span", null, computedLabel),
28014
- help && React__default["default"].createElement(React__default["default"].Fragment, null,
28034
+ (step === null || step === void 0 ? void 0 : step.help) && React__default["default"].createElement(React__default["default"].Fragment, null,
28015
28035
  React__default["default"].createElement(ReactToolTip__default["default"], { html: true, place: 'bottom', id: id }),
28016
- React__default["default"].createElement("span", { className: 'mrf-flex mrf-ai_center', "data-html": true, "data-tip": help, "data-for": id },
28036
+ React__default["default"].createElement("span", { className: 'mrf-flex mrf-ai_center', "data-html": true, "data-tip": step === null || step === void 0 ? void 0 : step.help, "data-for": id },
28017
28037
  React__default["default"].createElement(reactFeather.HelpCircle, { style: { color: 'gray', width: 17, marginLeft: '.5rem', cursor: 'help' } })))),
28018
28038
  children,
28019
28039
  error && React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-feedback', { ['mrf-txt_red']: !!errorDisplayed }) }, error.message)));
@@ -28124,16 +28144,18 @@ const validate = (flow, schema, value) => {
28124
28144
  abortEarly: false
28125
28145
  });
28126
28146
  };
28127
- const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28147
+ const Watcher = React__default["default"].memo(({ options, control, schema, onSubmit, handleSubmit }) => {
28128
28148
  const data = reactHookForm.useWatch({ control });
28149
+ const realSubmit = (d) => handleSubmit(() => {
28150
+ onSubmit(d);
28151
+ })();
28152
+ const debouncedSubmit = React.useCallback(debounce__default["default"](realSubmit, 250, { leading: true }), []);
28129
28153
  useHashEffect(() => {
28130
- if (options.autosubmit) {
28131
- handleSubmit(() => {
28132
- onSubmit(cleanOutputArray(data, schema));
28133
- })();
28154
+ if (options === null || options === void 0 ? void 0 : options.autosubmit) {
28155
+ debouncedSubmit(data);
28134
28156
  }
28135
28157
  }, [data]);
28136
- if (options.watch) {
28158
+ if (options === null || options === void 0 ? void 0 : options.watch) {
28137
28159
  if (typeof options.watch === 'function') {
28138
28160
  options.watch(cleanOutputArray(data, schema));
28139
28161
  }
@@ -28144,7 +28166,9 @@ const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28144
28166
  }
28145
28167
  }
28146
28168
  return null;
28147
- };
28169
+ }, () => {
28170
+ return true;
28171
+ });
28148
28172
  const Form = React__default["default"].forwardRef(function Form({ schema, flow, value, inputWrapper, onSubmit, onError = () => { }, footer, style = {}, className, options = {}, nostyle }, ref) {
28149
28173
  const formFlow = flow || Object.keys(schema);
28150
28174
  const maybeCustomHttpClient = (url, method) => {
@@ -28214,25 +28238,7 @@ const Form = React__default["default"].forwardRef(function Form({ schema, flow,
28214
28238
  console.error(`no step found for the entry "${entry}" in the given schema. Your form might not work properly. Please fix it`);
28215
28239
  return null;
28216
28240
  }
28217
- const visibleStep = option(step)
28218
- .map((s) => s.visible)
28219
- .map((visible) => {
28220
- let value;
28221
- switch (typeof visible) {
28222
- case 'object':
28223
- value = getValues(visible.ref);
28224
- return option(visible.test).map(test => test(value, idx)).getOrElse(value);
28225
- case 'boolean':
28226
- return visible;
28227
- default:
28228
- return true;
28229
- }
28230
- })
28231
- .getOrElse(true);
28232
- if (!visibleStep) {
28233
- return null;
28234
- }
28235
- return (React__default["default"].createElement(BasicWrapper, { key: `${entry}-${idx}`, entry: entry, functionalProperty: functionalProperty, label: step === null || step === void 0 ? void 0 : step.label, help: step === null || step === void 0 ? void 0 : step.help, render: inputWrapper },
28241
+ return (React__default["default"].createElement(BasicWrapper, { key: `${entry}-${idx}`, entry: entry, functionalProperty: functionalProperty, render: inputWrapper, step: step },
28236
28242
  React__default["default"].createElement(Step, { key: idx, entry: entry, step: step, schema: schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, functionalProperty: functionalProperty })));
28237
28243
  }),
28238
28244
  React__default["default"].createElement(Footer, { render: footer, reset: () => reset(defaultValues), valid: handleSubmit(data => onSubmit(cleanOutputArray(data, schema)), onError), actions: options.actions }))));
@@ -28249,8 +28255,8 @@ const Footer = (props) => {
28249
28255
  isSubmitDisplayed && React__default["default"].createElement("button", { className: 'mrf-btn mrf-btn_green mrf-ml_10', type: "submit" }, ((_p = (_o = props.actions) === null || _o === void 0 ? void 0 : _o.submit) === null || _p === void 0 ? void 0 : _p.label) || 'Save')));
28250
28256
  };
28251
28257
  const Step = (props) => {
28252
- let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, onAfterChange } = props;
28253
- const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, trigger, getValues, setValue, watch, register } = reactHookForm.useFormContext();
28258
+ let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, parentInformations } = props;
28259
+ const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, getValues, setValue, watch } = reactHookForm.useFormContext();
28254
28260
  if (entry && typeof entry === 'object') {
28255
28261
  const errored = extractFlowString(entry).some(step => !!errors[step] && (dirtyFields[step] || touchedFields[step]));
28256
28262
  return (React__default["default"].createElement(Collapse, Object.assign({}, entry, { errored: errored }), entry.flow.map((en, entryIdx) => {
@@ -28259,32 +28265,15 @@ const Step = (props) => {
28259
28265
  console.error(`no step found for the entry "${en}" in the given schema. Your form might not work properly. Please fix it`);
28260
28266
  return null;
28261
28267
  }
28262
- const visibleStep = option(stp)
28263
- .map(s => s.visible)
28264
- .map(visible => {
28265
- let value;
28266
- switch (typeof visible) {
28267
- case 'object':
28268
- value = getValues(visible.ref);
28269
- return option(visible.test).map(test => test(value, index)).getOrElse(value);
28270
- case 'boolean':
28271
- return visible;
28272
- default:
28273
- return true;
28274
- }
28275
- })
28276
- .getOrElse(true);
28277
- if (!visibleStep) {
28278
- return null;
28279
- }
28280
- return (React__default["default"].createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, label: stp === null || stp === void 0 ? void 0 : stp.label, help: stp === null || stp === void 0 ? void 0 : stp.help, render: inputWrapper },
28281
- React__default["default"].createElement(Step, { entry: en, step: stp, schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: stp === null || stp === void 0 ? void 0 : stp.defaultValue, functionalProperty: functionalProperty })));
28268
+ return (React__default["default"].createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, step: stp, render: inputWrapper },
28269
+ React__default["default"].createElement(Step, { entry: en, step: stp, schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: stp === null || stp === void 0 ? void 0 : stp.defaultValue, functionalProperty: functionalProperty, parentInformations: parentInformations })));
28282
28270
  })));
28283
28271
  }
28284
28272
  const error = entry.split('.').reduce((acc, curr) => acc && acc[curr], errors);
28285
28273
  const isDirty = entry.split('.').reduce((acc, curr) => acc && acc[curr], dirtyFields);
28286
28274
  const isTouched = entry.split('.').reduce((acc, curr) => acc && acc[curr], touchedFields);
28287
28275
  const errorDisplayed = (!!error && (isSubmitted || isDirty || isTouched));
28276
+ const informations = { path: entry, parent: parentInformations, index };
28288
28277
  step = step;
28289
28278
  if (step.onAfterChange) {
28290
28279
  const data = watch();
@@ -28298,11 +28287,12 @@ const Step = (props) => {
28298
28287
  step.onAfterChange({
28299
28288
  entry,
28300
28289
  value: getValues(entry),
28301
- rawValues: newData,
28290
+ rawValues: getValues(),
28302
28291
  previousValue: currentData,
28303
28292
  getValue: (e) => getValues(e),
28304
28293
  setValue,
28305
- onChange: (v) => setValue(entry, v)
28294
+ onChange: (v) => setValue(entry, v),
28295
+ informations
28306
28296
  });
28307
28297
  }
28308
28298
  if (step.array) {
@@ -28311,7 +28301,7 @@ const Step = (props) => {
28311
28301
  }, error: !!error },
28312
28302
  React__default["default"].createElement(ArrayStep, { entry: entry, step: step, disabled: functionalProperty(entry, step.disabled || false), component: ((props, idx) => {
28313
28303
  var _a;
28314
- return (React__default["default"].createElement(Step, { entry: `${entry}.${idx}.value`, step: Object.assign(Object.assign({}, (schema[realEntry || entry])), { render: step.itemRender, onChange: undefined, array: false, onAfterChange: step.onAfterChange }), schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: (_a = props.defaultValue) === null || _a === void 0 ? void 0 : _a.value, index: idx, functionalProperty: functionalProperty }));
28304
+ return (React__default["default"].createElement(Step, { entry: `${entry}.${idx}.value`, step: Object.assign(Object.assign({}, (schema[realEntry || entry])), { render: step.itemRender, onChange: undefined, array: false, onAfterChange: step.onAfterChange }), schema: schema, inputWrapper: inputWrapper, httpClient: httpClient, defaultValue: (_a = props.defaultValue) === null || _a === void 0 ? void 0 : _a.value, index: idx, functionalProperty: functionalProperty, parentInformations: informations }));
28315
28305
  }) })));
28316
28306
  }
28317
28307
  switch (step.type) {
@@ -28331,7 +28321,7 @@ const Step = (props) => {
28331
28321
  case format.buttonsSelect:
28332
28322
  case format.select: {
28333
28323
  return (React__default["default"].createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
28334
- React__default["default"].createElement(SelectInput, Object.assign({ className: classNames__default["default"]('mrf-flex_grow_1', step.className, { 'mrf-input__invalid': !!errorDisplayed }), disabled: functionalProperty(entry, step.disabled || false) }, step.props, { possibleValues: step.options, httpClient: httpClient, isMulti: step.isMulti, createOption: step.createOption, transformer: step.transformer, buttons: step.format === format.buttonsSelect, optionsFrom: step.optionsFrom }))));
28324
+ React__default["default"].createElement(SelectInput, Object.assign({ className: classNames__default["default"]('mrf-flex_grow_1', step.className, { 'mrf-input__invalid': !!errorDisplayed }), disabled: functionalProperty(entry, step.disabled || false) }, step.props, { possibleValues: step.options, httpClient: httpClient, isMulti: step.isMulti, createOption: step.createOption, onCreateOption: step.onCreateOption, transformer: step.transformer, buttons: step.format === format.buttonsSelect, optionsFrom: step.optionsFrom }))));
28335
28325
  }
28336
28326
  default:
28337
28327
  return (React__default["default"].createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
@@ -28359,7 +28349,7 @@ const Step = (props) => {
28359
28349
  case format.form: //todo: disabled ?
28360
28350
  const flow = option(step.flow).getOrElse(option(step.schema).map(s => Object.keys(s)).getOrElse([]));
28361
28351
  return (React__default["default"].createElement(CustomizableInput, { render: step.render, field: { parent, setValue: (key, value) => setValue(key, value), rawValues: getValues(), value: getValues(entry), onChange: (v) => setValue(entry, v, { shouldValidate: true }) } },
28362
- React__default["default"].createElement(NestedForm, { schema: step.schema, flow: flow, step: step, parent: entry, inputWrapper: inputWrapper, maybeCustomHttpClient: httpClient, value: getValues(entry) || defaultValue, index: index, functionalProperty: functionalProperty, errorDisplayed: errorDisplayed })));
28352
+ React__default["default"].createElement(NestedForm, { schema: step.schema, flow: flow, step: step, parent: entry, inputWrapper: inputWrapper, maybeCustomHttpClient: httpClient, value: getValues(entry) || defaultValue, functionalProperty: functionalProperty, errorDisplayed: errorDisplayed, informations: informations })));
28363
28353
  case format.code:
28364
28354
  return (React__default["default"].createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed, component: (field, props) => (React__default["default"].createElement(CodeInput, Object.assign({}, props, {
28365
28355
  /* TODO className={classNames(step.className, { 'mrf-input__invalid': !!error })}*/
@@ -28450,9 +28440,9 @@ const ArrayStep = ({ entry, step, component, disabled }) => {
28450
28440
  }, disabled: disabled }, "Add"),
28451
28441
  error && React__default["default"].createElement("div", { className: "mrf-invalid-feedback" }, error.message))));
28452
28442
  };
28453
- const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, index }) => {
28443
+ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, informations }) => {
28454
28444
  var _a;
28455
- const { getValues, setValue, watch, control, formState: { errors, dirtyFields, touchedFields } } = reactHookForm.useFormContext();
28445
+ const { getValues, setValue, control, formState: { errors, dirtyFields, touchedFields } } = reactHookForm.useFormContext();
28456
28446
  const [collapsed, setCollapsed] = React.useState(!!step.collapsed);
28457
28447
  reactHookForm.useWatch({ name: ((_a = step === null || step === void 0 ? void 0 : step.conditionalSchema) === null || _a === void 0 ? void 0 : _a.ref) || "", control });
28458
28448
  const schemaAndFlow = option(step.conditionalSchema)
@@ -28479,29 +28469,15 @@ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient,
28479
28469
  }, [schemaAndFlow.schema]);
28480
28470
  const computedSandF = schemaAndFlow.flow.reduce((acc, entry) => {
28481
28471
  const step = (typeof entry === "string") ? schemaAndFlow.schema[entry] : schemaAndFlow.schema[entry.label];
28482
- const visibleStep = option(step)
28483
- .map(s => s.visible)
28484
- .map(visible => {
28485
- switch (typeof visible) {
28486
- case 'object':
28487
- const value = watch(visible.ref);
28488
- return option(visible.test).map(test => test(value, index)).getOrElse(value);
28489
- case 'boolean':
28490
- return visible;
28491
- default:
28492
- return true;
28493
- }
28494
- })
28495
- .getOrElse(true);
28496
- return [...acc, { step, visibleStep, entry }];
28472
+ return [...acc, { step, entry }];
28497
28473
  }, []);
28498
- const bordered = computedSandF.filter(x => x.visibleStep).length >= 1 && step.label !== null;
28474
+ const bordered = computedSandF.length >= 1 && step.label !== null;
28499
28475
  return (React__default["default"].createElement("div", { className: classNames__default["default"]({ ['mrf-nestedform__border']: bordered, ['mrf-border__error']: !!errorDisplayed }), style: { position: 'relative' } },
28500
28476
  !!step.collapsable && schemaAndFlow.flow.length > 1 && collapsed &&
28501
28477
  React__default["default"].createElement(reactFeather.ChevronDown, { size: 30, className: 'mrf-cursor_pointer', style: { position: 'absolute', top: -35, right: 0, zIndex: 100 }, strokeWidth: "2", onClick: () => setCollapsed(!collapsed) }),
28502
28478
  !!step.collapsable && schemaAndFlow.flow.length > 1 && !collapsed &&
28503
28479
  React__default["default"].createElement(reactFeather.ChevronUp, { size: 30, className: 'mrf-cursor_pointer', style: { position: 'absolute', top: -35, right: 0, zIndex: 100 }, strokeWidth: "2", onClick: () => setCollapsed(!collapsed) }),
28504
- computedSandF.map(({ step, visibleStep, entry }, idx) => {
28480
+ computedSandF.map(({ step, entry }, idx) => {
28505
28481
  if (!step && typeof entry === 'string') {
28506
28482
  console.error(`no step found for the entry "${entry}" in the given schema. Your form might not work properly. Please fix it`);
28507
28483
  return null;
@@ -28514,31 +28490,13 @@ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient,
28514
28490
  console.error(`no step found for the entry "${en}" in the given schema. Your form might not work properly. Please fix it`);
28515
28491
  return null;
28516
28492
  }
28517
- const visibleStep = option(stp)
28518
- .map(s => s.visible)
28519
- .map(visible => {
28520
- let value;
28521
- switch (typeof visible) {
28522
- case 'object':
28523
- value = getValues(visible.ref);
28524
- return option(visible.test).map(test => test(value, index)).getOrElse(value);
28525
- case 'boolean':
28526
- return visible;
28527
- default:
28528
- return true;
28529
- }
28530
- })
28531
- .getOrElse(true);
28532
- if (!visibleStep) {
28533
- return null;
28534
- }
28535
- return (React__default["default"].createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, label: (step === null || step === void 0 ? void 0 : step.label) === null ? null : (step === null || step === void 0 ? void 0 : step.label) || entry, help: stp === null || stp === void 0 ? void 0 : stp.help, render: inputWrapper },
28493
+ return (React__default["default"].createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, step: stp, render: inputWrapper },
28536
28494
  React__default["default"].createElement(Step, { entry: en, step: stp, schema: schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, defaultValue: stp === null || stp === void 0 ? void 0 : stp.defaultValue, functionalProperty: functionalProperty })));
28537
28495
  }));
28538
28496
  // TODO return collapse, then entry will always be a string in below return
28539
28497
  }
28540
- return (React__default["default"].createElement(BasicWrapper, { key: `${entry}.${idx}`, className: classNames__default["default"]({ ['mrf-display__none']: (collapsed && !step.visibleOnCollapse) || !visibleStep }), entry: `${parent}.${entry}`, functionalProperty: functionalProperty, label: (step === null || step === void 0 ? void 0 : step.label) === null ? null : (step === null || step === void 0 ? void 0 : step.label) || entry, help: step.help, render: inputWrapper },
28541
- React__default["default"].createElement(Step, { key: `step.${entry}.${idx}`, entry: `${parent}.${entry}`, realEntry: entry, step: schemaAndFlow.schema[entry], parent: parent, schema: schemaAndFlow.schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, defaultValue: value && value[entry], functionalProperty: functionalProperty })));
28498
+ return (React__default["default"].createElement(BasicWrapper, { key: `${entry}.${idx}`, className: classNames__default["default"]({ ['mrf-display__none']: (collapsed && !step.visibleOnCollapse) }), entry: `${parent}.${entry}`, functionalProperty: functionalProperty, step: step, render: inputWrapper },
28499
+ React__default["default"].createElement(Step, { key: `step.${entry}.${idx}`, entry: `${parent}.${entry}`, realEntry: entry, step: schemaAndFlow.schema[entry], parent: parent, schema: schemaAndFlow.schema, inputWrapper: inputWrapper, httpClient: maybeCustomHttpClient, defaultValue: value && value[entry], functionalProperty: functionalProperty, parentInformations: informations })));
28542
28500
  })));
28543
28501
  };
28544
28502
  function extractFlowString(entry) {
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@maif/react-forms",
3
3
  "description": "Build react safe forms as fast as possible",
4
- "version": "1.1.0",
4
+ "version": "1.1.3",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
7
- "types": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
8
  "source": "src/index.ts",
9
9
  "author": "MAIF team",
10
10
  "keywords": [
@@ -32,8 +32,8 @@
32
32
  "README.md"
33
33
  ],
34
34
  "scripts": {
35
- "build": "rollup -c",
36
- "dev": "rollup -c -w",
35
+ "build": "tsc --emitDeclarationOnly && rollup -c",
36
+ "dev": "tsc --emitDeclarationOnly && rollup -c -w",
37
37
  "test": "jest",
38
38
  "tdd": "jest --watch"
39
39
  },
@@ -68,6 +68,14 @@
68
68
  "@rollup/plugin-json": "^4.1.0",
69
69
  "@rollup/plugin-node-resolve": "^13.1.3",
70
70
  "@rollup/plugin-typescript": "^8.3.2",
71
+ "@testing-library/jest-dom": "^5.11.4",
72
+ "@testing-library/react": "^11.1.0",
73
+ "@testing-library/user-event": "^12.1.10",
74
+ "@types/jest": "^26.0.24",
75
+ "@types/lodash.debounce": "4.0.7",
76
+ "@types/node": "^16.3.0",
77
+ "@types/react": "^17.0.14",
78
+ "@types/react-dom": "^17.0.9",
71
79
  "@types/object-hash": "^2.2.1",
72
80
  "@types/showdown": "^2.0.0",
73
81
  "@types/uuid": "^8.3.4",
@@ -87,6 +95,7 @@
87
95
  "rollup-plugin-commonjs": "^10.1.0",
88
96
  "rollup-plugin-copy": "^3.4.0",
89
97
  "rollup-plugin-delete": "^2.0.0",
98
+ "rollup-plugin-dts": "^4.2.2",
90
99
  "rollup-plugin-peer-deps-external": "^2.2.4",
91
100
  "rollup-plugin-scss": "^3.0.0",
92
101
  "rollup-plugin-terser": "^7.0.2",
@@ -107,20 +116,14 @@
107
116
  "@codemirror/theme-one-dark": "^0.19.1",
108
117
  "@fortawesome/fontawesome-free": "^5.15.3",
109
118
  "@hookform/resolvers": "2.4.0",
110
- "@testing-library/jest-dom": "^5.11.4",
111
- "@testing-library/react": "^11.1.0",
112
- "@testing-library/user-event": "^12.1.10",
113
- "@types/jest": "^26.0.24",
114
- "@types/node": "^16.3.0",
115
- "@types/react": "^17.0.14",
116
- "@types/react-dom": "^17.0.9",
117
119
  "classnames": "2.3.0",
118
120
  "fast-deep-equal": "^3.1.3",
119
121
  "highlight.js": "^11.5.1",
122
+ "lodash.debounce": "4.0.8",
120
123
  "moment": "2.29.1",
121
124
  "object-hash": "3.0.0",
122
125
  "react-feather": "2.0.9",
123
- "react-hook-form": "7.29.0",
126
+ "react-hook-form": "7.32.1",
124
127
  "react-rainbow-components": "1.26.0",
125
128
  "react-select": "5.2.1",
126
129
  "react-tooltip": "4.2.21",