@maif/react-forms 1.1.1 → 1.1.4

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';
@@ -177,13 +178,18 @@ const BooleanInput = React__default.forwardRef(({ onChange, value, readOnly }, r
177
178
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
178
179
  }
179
180
  };
180
- return (React__default.createElement("div", { className: classNames({ ['mrf-cursor_pointer']: !readOnly, ['mrf-cursor_not_allowed']: readOnly }) },
181
- !!value && React__default.createElement("div", { className: classNames('mrf-content_switch_button_on'), onClick: () => handleClick(false) },
182
- React__default.createElement("div", { className: classNames('mrf-switch_button_on') })),
183
- !value && value !== null && React__default.createElement("div", { className: classNames('mrf-content_switch_button_off'), onClick: () => handleClick(true) },
184
- React__default.createElement("div", { className: classNames('mrf-switch_button_off') })),
185
- value === null && React__default.createElement("div", { className: classNames('mrf-content_switch_button_null'), onClick: () => handleClick(true) },
186
- React__default.createElement("div", { className: classNames('mrf-switch_button_null') }))));
181
+ let className = classNames("mrf-content_switch", {
182
+ "mrf-content_switch_button_on": !!value,
183
+ "mrf-content_switch_button_off": !value && value !== null,
184
+ "mrf-content_switch_button_null": value === null,
185
+ "mrf-cursor_pointer": !readOnly,
186
+ "mrf-cursor_not_allowed": readOnly,
187
+ });
188
+ let callback = () => handleClick(true);
189
+ if (!!value) {
190
+ callback = () => handleClick(false);
191
+ }
192
+ return React__default.createElement("input", { type: "checkbox", className: className, onChange: callback });
187
193
  });
188
194
 
189
195
  const Collapse = (props) => {
@@ -278,7 +284,7 @@ const useHashEffect = (func, deps) => {
278
284
  const depsHash = cleanHash(deps);
279
285
  const prevDepsHash = cleanHash(prevDeps.current);
280
286
  if (depsHash !== prevDepsHash) {
281
- prevDeps.current = deps;
287
+ prevDeps.current = Object.assign({}, deps);
282
288
  func();
283
289
  }
284
290
  }, deps); /* FIXME deps or [deps] ? */
@@ -27921,7 +27927,7 @@ const ControlledInput = (inputProps) => {
27921
27927
  return prop;
27922
27928
  }
27923
27929
  };
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) => {
27930
+ 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
27931
  const value = (() => {
27926
27932
  if (!e) {
27927
27933
  if (step.type === type.bool ||
@@ -27960,7 +27966,6 @@ const usePrevious = (value) => {
27960
27966
  };
27961
27967
  const BasicWrapper = ({ entry, children, render, functionalProperty, step }) => {
27962
27968
  const { formState, watch } = useFormContext();
27963
- console.debug({ entry, step });
27964
27969
  if (typeof entry === 'object') {
27965
27970
  return children;
27966
27971
  }
@@ -28108,16 +28113,18 @@ const validate = (flow, schema, value) => {
28108
28113
  abortEarly: false
28109
28114
  });
28110
28115
  };
28111
- const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28116
+ const Watcher = React__default.memo(({ options, control, schema, onSubmit, handleSubmit }) => {
28112
28117
  const data = useWatch({ control });
28118
+ const realSubmit = (d) => handleSubmit(() => {
28119
+ onSubmit(d);
28120
+ })();
28121
+ const debouncedSubmit = useCallback(debounce(realSubmit, 250, { leading: true }), []);
28113
28122
  useHashEffect(() => {
28114
- if (options.autosubmit) {
28115
- handleSubmit(() => {
28116
- onSubmit(cleanOutputArray(data, schema));
28117
- })();
28123
+ if (options === null || options === void 0 ? void 0 : options.autosubmit) {
28124
+ debouncedSubmit(data);
28118
28125
  }
28119
28126
  }, [data]);
28120
- if (options.watch) {
28127
+ if (options === null || options === void 0 ? void 0 : options.watch) {
28121
28128
  if (typeof options.watch === 'function') {
28122
28129
  options.watch(cleanOutputArray(data, schema));
28123
28130
  }
@@ -28128,7 +28135,9 @@ const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28128
28135
  }
28129
28136
  }
28130
28137
  return null;
28131
- };
28138
+ }, () => {
28139
+ return true;
28140
+ });
28132
28141
  const Form = React__default.forwardRef(function Form({ schema, flow, value, inputWrapper, onSubmit, onError = () => { }, footer, style = {}, className, options = {}, nostyle }, ref) {
28133
28142
  const formFlow = flow || Object.keys(schema);
28134
28143
  const maybeCustomHttpClient = (url, method) => {
@@ -28186,7 +28195,6 @@ const Form = React__default.forwardRef(function Form({ schema, flow, value, inpu
28186
28195
  trigger,
28187
28196
  methods: Object.assign(Object.assign({}, methods), { data: () => cleanOutputArray(getValues(), schema) })
28188
28197
  }));
28189
- console.debug({ formFlow });
28190
28198
  return (React__default.createElement(FormProvider, Object.assign({}, methods),
28191
28199
  React__default.createElement(Watcher, { options: options, control: methods.control, schema: schema, onSubmit: onSubmit, handleSubmit: handleSubmit }),
28192
28200
  React__default.createElement("form", { className: className || `mrf-pr_15 mrf-w_100`, onSubmit: handleSubmit(data => {
@@ -28216,8 +28224,8 @@ const Footer = (props) => {
28216
28224
  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')));
28217
28225
  };
28218
28226
  const Step = (props) => {
28219
- let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, onAfterChange } = props;
28220
- const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, trigger, getValues, setValue, watch, register } = useFormContext();
28227
+ let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, parentInformations } = props;
28228
+ const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, getValues, setValue, watch } = useFormContext();
28221
28229
  if (entry && typeof entry === 'object') {
28222
28230
  const errored = extractFlowString(entry).some(step => !!errors[step] && (dirtyFields[step] || touchedFields[step]));
28223
28231
  return (React__default.createElement(Collapse, Object.assign({}, entry, { errored: errored }), entry.flow.map((en, entryIdx) => {
@@ -28227,13 +28235,14 @@ const Step = (props) => {
28227
28235
  return null;
28228
28236
  }
28229
28237
  return (React__default.createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, step: stp, render: inputWrapper },
28230
- 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 })));
28238
+ 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 })));
28231
28239
  })));
28232
28240
  }
28233
28241
  const error = entry.split('.').reduce((acc, curr) => acc && acc[curr], errors);
28234
28242
  const isDirty = entry.split('.').reduce((acc, curr) => acc && acc[curr], dirtyFields);
28235
28243
  const isTouched = entry.split('.').reduce((acc, curr) => acc && acc[curr], touchedFields);
28236
28244
  const errorDisplayed = (!!error && (isSubmitted || isDirty || isTouched));
28245
+ const informations = { path: entry, parent: parentInformations, index };
28237
28246
  step = step;
28238
28247
  if (step.onAfterChange) {
28239
28248
  const data = watch();
@@ -28247,11 +28256,12 @@ const Step = (props) => {
28247
28256
  step.onAfterChange({
28248
28257
  entry,
28249
28258
  value: getValues(entry),
28250
- rawValues: newData,
28259
+ rawValues: getValues(),
28251
28260
  previousValue: currentData,
28252
28261
  getValue: (e) => getValues(e),
28253
28262
  setValue,
28254
- onChange: (v) => setValue(entry, v)
28263
+ onChange: (v) => setValue(entry, v),
28264
+ informations
28255
28265
  });
28256
28266
  }
28257
28267
  if (step.array) {
@@ -28260,7 +28270,7 @@ const Step = (props) => {
28260
28270
  }, error: !!error },
28261
28271
  React__default.createElement(ArrayStep, { entry: entry, step: step, disabled: functionalProperty(entry, step.disabled || false), component: ((props, idx) => {
28262
28272
  var _a;
28263
- 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 }));
28273
+ 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 }));
28264
28274
  }) })));
28265
28275
  }
28266
28276
  switch (step.type) {
@@ -28280,7 +28290,7 @@ const Step = (props) => {
28280
28290
  case format.buttonsSelect:
28281
28291
  case format.select: {
28282
28292
  return (React__default.createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
28283
- 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 }))));
28293
+ 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 }))));
28284
28294
  }
28285
28295
  default:
28286
28296
  return (React__default.createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
@@ -28308,7 +28318,7 @@ const Step = (props) => {
28308
28318
  case format.form: //todo: disabled ?
28309
28319
  const flow = option(step.flow).getOrElse(option(step.schema).map(s => Object.keys(s)).getOrElse([]));
28310
28320
  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 }) } },
28311
- 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 })));
28321
+ 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 })));
28312
28322
  case format.code:
28313
28323
  return (React__default.createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed, component: (field, props) => (React__default.createElement(CodeInput, Object.assign({}, props, {
28314
28324
  /* TODO className={classNames(step.className, { 'mrf-input__invalid': !!error })}*/
@@ -28399,9 +28409,9 @@ const ArrayStep = ({ entry, step, component, disabled }) => {
28399
28409
  }, disabled: disabled }, "Add"),
28400
28410
  error && React__default.createElement("div", { className: "mrf-invalid-feedback" }, error.message))));
28401
28411
  };
28402
- const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, index }) => {
28412
+ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, informations }) => {
28403
28413
  var _a;
28404
- const { getValues, setValue, watch, control, formState: { errors, dirtyFields, touchedFields } } = useFormContext();
28414
+ const { getValues, setValue, control, formState: { errors, dirtyFields, touchedFields } } = useFormContext();
28405
28415
  const [collapsed, setCollapsed] = useState(!!step.collapsed);
28406
28416
  useWatch({ name: ((_a = step === null || step === void 0 ? void 0 : step.conditionalSchema) === null || _a === void 0 ? void 0 : _a.ref) || "", control });
28407
28417
  const schemaAndFlow = option(step.conditionalSchema)
@@ -28455,7 +28465,7 @@ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient,
28455
28465
  // TODO return collapse, then entry will always be a string in below return
28456
28466
  }
28457
28467
  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 },
28458
- 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 })));
28468
+ 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 })));
28459
28469
  })));
28460
28470
  };
28461
28471
  function extractFlowString(entry) {
package/lib/index.css CHANGED
@@ -294,6 +294,10 @@
294
294
  margin-left: 5px;
295
295
  }
296
296
 
297
+ .mrf-content_switch {
298
+ appearance: none;
299
+ }
300
+
297
301
  .mrf-content_switch_button_on {
298
302
  width: 35px;
299
303
  height: 22px;
@@ -305,6 +309,18 @@
305
309
  justify-content: flex-end;
306
310
  }
307
311
 
312
+ .mrf-content_switch_button_on::before {
313
+ content: "";
314
+ cursor: pointer;
315
+ width: 20px;
316
+ height: 20px;
317
+ background-color: var(--form-bg-color, #fff);
318
+ border-radius: 20px;
319
+ border: 1px solid var(--success-hover-color, #1e7e34);
320
+ box-shadow: 1px 0px 5px 0px rgba(0, 0, 0, 0.3);
321
+ margin-top: -1px;
322
+ }
323
+
308
324
  .mrf-content_switch_button_off {
309
325
  width: 35px;
310
326
  height: 22px;
@@ -316,6 +332,18 @@
316
332
  justify-content: flex-start;
317
333
  }
318
334
 
335
+ .mrf-content_switch_button_off::before {
336
+ content: "";
337
+ background-color: var(--form-bg-color, #fff);
338
+ border-radius: 20px;
339
+ cursor: pointer;
340
+ width: 20px;
341
+ height: 20px;
342
+ border: 1px solid var(--error-hover-color, #bd2130);
343
+ box-shadow: 1px 0px 5px 0px rgba(0, 0, 0, 0.3);
344
+ margin-top: -1px;
345
+ }
346
+
319
347
  .mrf-content_switch_button_null {
320
348
  width: 35px;
321
349
  height: 22px;
@@ -327,34 +355,16 @@
327
355
  justify-content: flex-start;
328
356
  }
329
357
 
330
- .mrf-switch_button_on {
331
- cursor: pointer;
332
- width: 20px;
333
- height: 20px;
334
- background-color: var(--form-bg-color, #fff);
335
- border-radius: 20px;
336
- border: 1px solid var(--success-hover-color, #1e7e34);
337
- box-shadow: 1px 0px 5px 0px rgba(0, 0, 0, 0.3);
338
- }
339
-
340
- .mrf-switch_button_off {
358
+ .mrf-content_switch_button_null::before {
359
+ content: "";
341
360
  background-color: var(--form-bg-color, #fff);
342
361
  border-radius: 20px;
343
362
  cursor: pointer;
344
363
  width: 20px;
345
364
  height: 20px;
346
- border: 1px solid var(--error-hover-color, #bd2130);
347
- box-shadow: 1px 0px 5px 0px rgba(0, 0, 0, 0.3);
348
- }
349
-
350
- .mrf-switch_button_null {
351
- background-color: var(--form-bg-color, #fff);
352
- border-radius: 20px;
353
- cursor: pointer;
354
- width: 22px;
355
- height: 22px;
356
365
  margin-top: -1px;
357
366
  margin-left: -1px;
358
367
  border: 1px solid var(--neutral-hover-color, #5c636a);
359
368
  box-shadow: 1px 0px 5px 0px rgba(0, 0, 0, 0.3);
369
+ margin-top: -1px;
360
370
  }
package/lib/index.d.ts CHANGED
@@ -138,7 +138,7 @@ declare type SelectOption = {
138
138
  declare const SelectInput: <T extends {
139
139
  [x: string]: any;
140
140
  }>(props: {
141
- possibleValues: T[];
141
+ possibleValues?: T[] | undefined;
142
142
  transformer?: {
143
143
  label: string;
144
144
  value: string;
@@ -146,10 +146,10 @@ declare const SelectInput: <T extends {
146
146
  value?: any;
147
147
  defaultValue?: any;
148
148
  isMulti?: boolean | undefined;
149
- optionsFrom: string | Promise<T[]> | ((param: {
149
+ optionsFrom?: string | Promise<T[]> | ((param: {
150
150
  rawValues: object;
151
151
  value: any;
152
- }) => string | Promise<T[]>);
152
+ }) => string | Promise<T[]>) | undefined;
153
153
  fetchCondition?: (() => boolean) | undefined;
154
154
  id?: string | undefined;
155
155
  httpClient?: ((url: string, method: string) => Promise<Response>) | undefined;
@@ -302,24 +302,24 @@ interface SchemaEntry {
302
302
  className?: string;
303
303
  style?: object;
304
304
  onChange?: (param: object) => void;
305
- render: SchemaRenderType;
305
+ render?: SchemaRenderType;
306
306
  itemRender?: SchemaRenderType;
307
- props: object;
308
- options: Array<any | {
307
+ props?: object;
308
+ options?: Array<any | {
309
309
  label: string;
310
310
  value: any;
311
311
  }>;
312
- optionsFrom: string;
313
- transformer: ((v: any) => SelectOption) | {
312
+ optionsFrom?: string;
313
+ transformer?: ((v: any) => SelectOption) | {
314
314
  label: string;
315
315
  value: string;
316
316
  };
317
- conditionalSchema: ConditionnalSchema;
318
- constraints: Array<Constraint | {
317
+ conditionalSchema?: ConditionnalSchema;
318
+ constraints?: Array<Constraint | {
319
319
  type: TConstraintType;
320
320
  message?: string;
321
321
  }>;
322
- flow: Array<string | FlowObject>;
322
+ flow?: Array<string | FlowObject>;
323
323
  onAfterChange?: (obj: {
324
324
  entry: string;
325
325
  value: object;
@@ -328,9 +328,10 @@ interface SchemaEntry {
328
328
  getValue: (entry: string) => any;
329
329
  setValue: (entry: string, value: any) => void;
330
330
  onChange: (v: any) => void;
331
+ informations?: Informations;
331
332
  }) => void;
332
333
  visibleOnCollapse?: boolean;
333
- addableDefaultValue: any;
334
+ addableDefaultValue?: any;
334
335
  collapsed?: boolean;
335
336
  collapsable?: boolean;
336
337
  }
@@ -340,6 +341,11 @@ interface FlowObject {
340
341
  collapse: boolean;
341
342
  }
342
343
  declare type Flow = Array<string | FlowObject>;
344
+ interface Informations {
345
+ path: string;
346
+ parent?: Informations;
347
+ index?: number;
348
+ }
343
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>>>;
344
350
  declare const Form: React.ForwardRefExoticComponent<{
345
351
  schema: Schema;
@@ -348,7 +354,10 @@ declare const Form: React.ForwardRefExoticComponent<{
348
354
  inputWrapper?: ((props: object) => JSX.Element) | undefined;
349
355
  onSubmit: (obj: object) => void;
350
356
  onError?: (() => void) | undefined;
351
- footer?: ((props: object) => JSX.Element) | undefined;
357
+ footer?: ((props: {
358
+ reset: () => void;
359
+ valid: () => void;
360
+ }) => JSX.Element) | undefined;
352
361
  style?: object | undefined;
353
362
  className?: string | undefined;
354
363
  options?: Option | undefined;
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);
@@ -212,13 +214,18 @@ const BooleanInput = React__default["default"].forwardRef(({ onChange, value, re
212
214
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
213
215
  }
214
216
  };
215
- return (React__default["default"].createElement("div", { className: classNames__default["default"]({ ['mrf-cursor_pointer']: !readOnly, ['mrf-cursor_not_allowed']: readOnly }) },
216
- !!value && React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-content_switch_button_on'), onClick: () => handleClick(false) },
217
- React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-switch_button_on') })),
218
- !value && value !== null && React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-content_switch_button_off'), onClick: () => handleClick(true) },
219
- React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-switch_button_off') })),
220
- value === null && React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-content_switch_button_null'), onClick: () => handleClick(true) },
221
- React__default["default"].createElement("div", { className: classNames__default["default"]('mrf-switch_button_null') }))));
217
+ let className = classNames__default["default"]("mrf-content_switch", {
218
+ "mrf-content_switch_button_on": !!value,
219
+ "mrf-content_switch_button_off": !value && value !== null,
220
+ "mrf-content_switch_button_null": value === null,
221
+ "mrf-cursor_pointer": !readOnly,
222
+ "mrf-cursor_not_allowed": readOnly,
223
+ });
224
+ let callback = () => handleClick(true);
225
+ if (!!value) {
226
+ callback = () => handleClick(false);
227
+ }
228
+ return React__default["default"].createElement("input", { type: "checkbox", className: className, onChange: callback });
222
229
  });
223
230
 
224
231
  const Collapse = (props) => {
@@ -313,7 +320,7 @@ const useHashEffect = (func, deps) => {
313
320
  const depsHash = cleanHash(deps);
314
321
  const prevDepsHash = cleanHash(prevDeps.current);
315
322
  if (depsHash !== prevDepsHash) {
316
- prevDeps.current = deps;
323
+ prevDeps.current = Object.assign({}, deps);
317
324
  func();
318
325
  }
319
326
  }, deps); /* FIXME deps or [deps] ? */
@@ -27956,7 +27963,7 @@ const ControlledInput = (inputProps) => {
27956
27963
  return prop;
27957
27964
  }
27958
27965
  };
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) => {
27966
+ 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
27967
  const value = (() => {
27961
27968
  if (!e) {
27962
27969
  if (step.type === type.bool ||
@@ -27995,7 +28002,6 @@ const usePrevious = (value) => {
27995
28002
  };
27996
28003
  const BasicWrapper = ({ entry, children, render, functionalProperty, step }) => {
27997
28004
  const { formState, watch } = reactHookForm.useFormContext();
27998
- console.debug({ entry, step });
27999
28005
  if (typeof entry === 'object') {
28000
28006
  return children;
28001
28007
  }
@@ -28143,16 +28149,18 @@ const validate = (flow, schema, value) => {
28143
28149
  abortEarly: false
28144
28150
  });
28145
28151
  };
28146
- const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28152
+ const Watcher = React__default["default"].memo(({ options, control, schema, onSubmit, handleSubmit }) => {
28147
28153
  const data = reactHookForm.useWatch({ control });
28154
+ const realSubmit = (d) => handleSubmit(() => {
28155
+ onSubmit(d);
28156
+ })();
28157
+ const debouncedSubmit = React.useCallback(debounce__default["default"](realSubmit, 250, { leading: true }), []);
28148
28158
  useHashEffect(() => {
28149
- if (options.autosubmit) {
28150
- handleSubmit(() => {
28151
- onSubmit(cleanOutputArray(data, schema));
28152
- })();
28159
+ if (options === null || options === void 0 ? void 0 : options.autosubmit) {
28160
+ debouncedSubmit(data);
28153
28161
  }
28154
28162
  }, [data]);
28155
- if (options.watch) {
28163
+ if (options === null || options === void 0 ? void 0 : options.watch) {
28156
28164
  if (typeof options.watch === 'function') {
28157
28165
  options.watch(cleanOutputArray(data, schema));
28158
28166
  }
@@ -28163,7 +28171,9 @@ const Watcher = ({ options, control, schema, onSubmit, handleSubmit }) => {
28163
28171
  }
28164
28172
  }
28165
28173
  return null;
28166
- };
28174
+ }, () => {
28175
+ return true;
28176
+ });
28167
28177
  const Form = React__default["default"].forwardRef(function Form({ schema, flow, value, inputWrapper, onSubmit, onError = () => { }, footer, style = {}, className, options = {}, nostyle }, ref) {
28168
28178
  const formFlow = flow || Object.keys(schema);
28169
28179
  const maybeCustomHttpClient = (url, method) => {
@@ -28221,7 +28231,6 @@ const Form = React__default["default"].forwardRef(function Form({ schema, flow,
28221
28231
  trigger,
28222
28232
  methods: Object.assign(Object.assign({}, methods), { data: () => cleanOutputArray(getValues(), schema) })
28223
28233
  }));
28224
- console.debug({ formFlow });
28225
28234
  return (React__default["default"].createElement(reactHookForm.FormProvider, Object.assign({}, methods),
28226
28235
  React__default["default"].createElement(Watcher, { options: options, control: methods.control, schema: schema, onSubmit: onSubmit, handleSubmit: handleSubmit }),
28227
28236
  React__default["default"].createElement("form", { className: className || `mrf-pr_15 mrf-w_100`, onSubmit: handleSubmit(data => {
@@ -28251,8 +28260,8 @@ const Footer = (props) => {
28251
28260
  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')));
28252
28261
  };
28253
28262
  const Step = (props) => {
28254
- let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, onAfterChange } = props;
28255
- const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, trigger, getValues, setValue, watch, register } = reactHookForm.useFormContext();
28263
+ let { entry, realEntry, step, schema, inputWrapper, httpClient, defaultValue, index, functionalProperty, parent, parentInformations } = props;
28264
+ const { formState: { errors, dirtyFields, touchedFields, isSubmitted }, control, getValues, setValue, watch } = reactHookForm.useFormContext();
28256
28265
  if (entry && typeof entry === 'object') {
28257
28266
  const errored = extractFlowString(entry).some(step => !!errors[step] && (dirtyFields[step] || touchedFields[step]));
28258
28267
  return (React__default["default"].createElement(Collapse, Object.assign({}, entry, { errored: errored }), entry.flow.map((en, entryIdx) => {
@@ -28262,13 +28271,14 @@ const Step = (props) => {
28262
28271
  return null;
28263
28272
  }
28264
28273
  return (React__default["default"].createElement(BasicWrapper, { key: `collapse-${en}-${entryIdx}`, entry: en, functionalProperty: functionalProperty, step: stp, render: inputWrapper },
28265
- 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 })));
28274
+ 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 })));
28266
28275
  })));
28267
28276
  }
28268
28277
  const error = entry.split('.').reduce((acc, curr) => acc && acc[curr], errors);
28269
28278
  const isDirty = entry.split('.').reduce((acc, curr) => acc && acc[curr], dirtyFields);
28270
28279
  const isTouched = entry.split('.').reduce((acc, curr) => acc && acc[curr], touchedFields);
28271
28280
  const errorDisplayed = (!!error && (isSubmitted || isDirty || isTouched));
28281
+ const informations = { path: entry, parent: parentInformations, index };
28272
28282
  step = step;
28273
28283
  if (step.onAfterChange) {
28274
28284
  const data = watch();
@@ -28282,11 +28292,12 @@ const Step = (props) => {
28282
28292
  step.onAfterChange({
28283
28293
  entry,
28284
28294
  value: getValues(entry),
28285
- rawValues: newData,
28295
+ rawValues: getValues(),
28286
28296
  previousValue: currentData,
28287
28297
  getValue: (e) => getValues(e),
28288
28298
  setValue,
28289
- onChange: (v) => setValue(entry, v)
28299
+ onChange: (v) => setValue(entry, v),
28300
+ informations
28290
28301
  });
28291
28302
  }
28292
28303
  if (step.array) {
@@ -28295,7 +28306,7 @@ const Step = (props) => {
28295
28306
  }, error: !!error },
28296
28307
  React__default["default"].createElement(ArrayStep, { entry: entry, step: step, disabled: functionalProperty(entry, step.disabled || false), component: ((props, idx) => {
28297
28308
  var _a;
28298
- 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 }));
28309
+ 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 }));
28299
28310
  }) })));
28300
28311
  }
28301
28312
  switch (step.type) {
@@ -28315,7 +28326,7 @@ const Step = (props) => {
28315
28326
  case format.buttonsSelect:
28316
28327
  case format.select: {
28317
28328
  return (React__default["default"].createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
28318
- 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 }))));
28329
+ 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 }))));
28319
28330
  }
28320
28331
  default:
28321
28332
  return (React__default["default"].createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed },
@@ -28343,7 +28354,7 @@ const Step = (props) => {
28343
28354
  case format.form: //todo: disabled ?
28344
28355
  const flow = option(step.flow).getOrElse(option(step.schema).map(s => Object.keys(s)).getOrElse([]));
28345
28356
  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 }) } },
28346
- 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 })));
28357
+ 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 })));
28347
28358
  case format.code:
28348
28359
  return (React__default["default"].createElement(ControlledInput, { step: step, entry: entry, errorDisplayed: errorDisplayed, component: (field, props) => (React__default["default"].createElement(CodeInput, Object.assign({}, props, {
28349
28360
  /* TODO className={classNames(step.className, { 'mrf-input__invalid': !!error })}*/
@@ -28434,9 +28445,9 @@ const ArrayStep = ({ entry, step, component, disabled }) => {
28434
28445
  }, disabled: disabled }, "Add"),
28435
28446
  error && React__default["default"].createElement("div", { className: "mrf-invalid-feedback" }, error.message))));
28436
28447
  };
28437
- const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, index }) => {
28448
+ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient, errorDisplayed, value, step, functionalProperty, informations }) => {
28438
28449
  var _a;
28439
- const { getValues, setValue, watch, control, formState: { errors, dirtyFields, touchedFields } } = reactHookForm.useFormContext();
28450
+ const { getValues, setValue, control, formState: { errors, dirtyFields, touchedFields } } = reactHookForm.useFormContext();
28440
28451
  const [collapsed, setCollapsed] = React.useState(!!step.collapsed);
28441
28452
  reactHookForm.useWatch({ name: ((_a = step === null || step === void 0 ? void 0 : step.conditionalSchema) === null || _a === void 0 ? void 0 : _a.ref) || "", control });
28442
28453
  const schemaAndFlow = option(step.conditionalSchema)
@@ -28490,7 +28501,7 @@ const NestedForm = ({ schema, flow, parent, inputWrapper, maybeCustomHttpClient,
28490
28501
  // TODO return collapse, then entry will always be a string in below return
28491
28502
  }
28492
28503
  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 },
28493
- 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 })));
28504
+ 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 })));
28494
28505
  })));
28495
28506
  };
28496
28507
  function extractFlowString(entry) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maif/react-forms",
3
3
  "description": "Build react safe forms as fast as possible",
4
- "version": "1.1.1",
4
+ "version": "1.1.4",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -72,6 +72,7 @@
72
72
  "@testing-library/react": "^11.1.0",
73
73
  "@testing-library/user-event": "^12.1.10",
74
74
  "@types/jest": "^26.0.24",
75
+ "@types/lodash.debounce": "4.0.7",
75
76
  "@types/node": "^16.3.0",
76
77
  "@types/react": "^17.0.14",
77
78
  "@types/react-dom": "^17.0.9",
@@ -118,10 +119,11 @@
118
119
  "classnames": "2.3.0",
119
120
  "fast-deep-equal": "^3.1.3",
120
121
  "highlight.js": "^11.5.1",
122
+ "lodash.debounce": "4.0.8",
121
123
  "moment": "2.29.1",
122
124
  "object-hash": "3.0.0",
123
125
  "react-feather": "2.0.9",
124
- "react-hook-form": "7.29.0",
126
+ "react-hook-form": "7.32.1",
125
127
  "react-rainbow-components": "1.26.0",
126
128
  "react-select": "5.2.1",
127
129
  "react-tooltip": "4.2.21",