@react-fabric/form 1.0.0-beta.33 → 1.0.0-beta.34

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.
Files changed (48) hide show
  1. package/dist/cjs/builder/FormField.js +3 -3
  2. package/dist/cjs/builder/SchemaEditor.js +44 -33
  3. package/dist/cjs/form/Form.js +11 -4
  4. package/dist/cjs/input/ColorInput.js +1 -1
  5. package/dist/cjs/input/DateInput.js +2 -2
  6. package/dist/cjs/input/File.js +1 -1
  7. package/dist/cjs/input/Hidden.js +1 -1
  8. package/dist/cjs/input/Input.js +1 -1
  9. package/dist/cjs/input/Number.js +1 -1
  10. package/dist/cjs/input/Password.js +1 -1
  11. package/dist/cjs/input/RangeSlider.js +1 -1
  12. package/dist/cjs/input/Search.js +1 -1
  13. package/dist/cjs/input/Slider.js +1 -1
  14. package/dist/cjs/input/Textarea.js +1 -1
  15. package/dist/esm/builder/FormField.js +3 -3
  16. package/dist/esm/builder/SchemaEditor.js +45 -34
  17. package/dist/esm/form/Form.js +11 -4
  18. package/dist/esm/input/ColorInput.js +1 -1
  19. package/dist/esm/input/DateInput.js +2 -2
  20. package/dist/esm/input/File.js +1 -1
  21. package/dist/esm/input/Hidden.js +1 -1
  22. package/dist/esm/input/Input.js +1 -1
  23. package/dist/esm/input/Number.js +1 -1
  24. package/dist/esm/input/Password.js +1 -1
  25. package/dist/esm/input/RangeSlider.js +1 -1
  26. package/dist/esm/input/Search.js +1 -1
  27. package/dist/esm/input/Slider.js +1 -1
  28. package/dist/esm/input/Textarea.js +1 -1
  29. package/dist/types/builder/SchemaEditor.d.ts +7 -1
  30. package/dist/types/form/Form.d.ts +2 -5
  31. package/dist/types/input/ColorInput.d.ts +1 -1
  32. package/dist/types/types/index.d.ts +1 -1
  33. package/package.json +5 -5
  34. package/src/builder/FormField.tsx +3 -3
  35. package/src/builder/SchemaEditor.tsx +42 -26
  36. package/src/form/Form.tsx +6 -8
  37. package/src/input/ColorInput.tsx +5 -2
  38. package/src/input/DateInput.tsx +2 -2
  39. package/src/input/File.tsx +1 -1
  40. package/src/input/Hidden.tsx +4 -3
  41. package/src/input/Input.tsx +1 -1
  42. package/src/input/Number.tsx +1 -1
  43. package/src/input/Password.tsx +1 -1
  44. package/src/input/RangeSlider.tsx +1 -1
  45. package/src/input/Search.tsx +1 -1
  46. package/src/input/Slider.tsx +1 -1
  47. package/src/input/Textarea.tsx +1 -1
  48. package/src/types/index.ts +1 -1
@@ -106,7 +106,7 @@ var FormField = function FormField(_ref) {
106
106
  });
107
107
  return rest.multiple && !hasOptions ? /*#__PURE__*/jsxRuntime.jsx(ArrayInput.ArrayInput, {
108
108
  name: fieldName,
109
- label: t(label, label),
109
+ label: t("fb.".concat(id), label || id),
110
110
  required: required,
111
111
  onAdd: function onAdd() {
112
112
  return String("");
@@ -118,8 +118,8 @@ var FormField = function FormField(_ref) {
118
118
  name: fieldName,
119
119
  children: /*#__PURE__*/jsxRuntime.jsx(E, _objectSpread(_objectSpread({}, props), {}, {
120
120
  autoFocus: autoFocus,
121
- label: t(label, label),
122
- placeholder: t(label, label),
121
+ label: t("fb.".concat(id), label || id),
122
+ placeholder: t("fb.".concat(id), label || id),
123
123
  required: required,
124
124
  inline: inline
125
125
  }))
@@ -12,6 +12,7 @@ var ArrayInput = require('../input/ArrayInput.js');
12
12
  var Checkbox = require('../input/Checkbox.js');
13
13
  var DateInput = require('../input/DateInput.js');
14
14
  var Field = require('../input/Field.js');
15
+ var Hidden = require('../input/Hidden.js');
15
16
  var Input = require('../input/Input.js');
16
17
  var Number = require('../input/Number.js');
17
18
  var Select = require('../select/Select.js');
@@ -24,6 +25,7 @@ var CUSTOM_LIST = "--CUSTOM--";
24
25
  var SchemaField = function SchemaField(_ref) {
25
26
  var field = _ref.field,
26
27
  getModel = _ref.getModel,
28
+ onRemove = _ref.onRemove,
27
29
  _ref$optionLists = _ref.optionLists,
28
30
  optionLists = _ref$optionLists === void 0 ? utilities.EMPTY_ARRAY : _ref$optionLists,
29
31
  allowRemove = _ref.allowRemove,
@@ -81,7 +83,7 @@ var SchemaField = function SchemaField(_ref) {
81
83
  setCustomOptions(model.optionList === CUSTOM_LIST);
82
84
  }, 10);
83
85
  }, []);
84
- react.useEffect(function () {
86
+ var handleTypeChange = react.useCallback(function (type) {
85
87
  if (type) {
86
88
  var modelRef = getModel();
87
89
  var reset = {
@@ -115,8 +117,9 @@ var SchemaField = function SchemaField(_ref) {
115
117
  setMultiple(false);
116
118
  }
117
119
  onTypeChange(reset);
120
+ setType(type);
118
121
  }
119
- }, [type]);
122
+ }, []);
120
123
  return /*#__PURE__*/jsxRuntime.jsxs(core.Collapsable, {
121
124
  open: true,
122
125
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -131,11 +134,17 @@ var SchemaField = function SchemaField(_ref) {
131
134
  "aria-label": "Delete",
132
135
  stopPropagation: true,
133
136
  icon: core.CoreIcons.trash,
137
+ onClick: onRemove,
134
138
  className: "invisible group-hover/field:visible"
135
139
  })]
136
140
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
137
141
  className: "flex flex-col gap-1 pb-4",
138
142
  children: [/*#__PURE__*/jsxRuntime.jsx(Controller.Controller, {
143
+ name: "".concat(field, ".id"),
144
+ children: /*#__PURE__*/jsxRuntime.jsx(Hidden.HiddenInput, {
145
+ hiddenValue: field
146
+ })
147
+ }), /*#__PURE__*/jsxRuntime.jsx(Controller.Controller, {
139
148
  name: "".concat(field, ".datatype"),
140
149
  children: /*#__PURE__*/jsxRuntime.jsx(Select.Select, {
141
150
  inline: true,
@@ -143,7 +152,7 @@ var SchemaField = function SchemaField(_ref) {
143
152
  placeholder: "Data type",
144
153
  options: acceptableTypes,
145
154
  onChange: function onChange(val) {
146
- return setType(val);
155
+ return handleTypeChange(val);
147
156
  }
148
157
  })
149
158
  }), /*#__PURE__*/jsxRuntime.jsx(Controller.Controller, {
@@ -357,39 +366,47 @@ var SchemaEditor = function SchemaEditor(_ref2) {
357
366
  acceptableTypes = _ref2.acceptableTypes,
358
367
  _ref2$optionLists = _ref2.optionLists,
359
368
  optionLists = _ref2$optionLists === void 0 ? utilities.EMPTY_ARRAY : _ref2$optionLists,
369
+ children = _ref2.children,
360
370
  onChange = _ref2.onChange;
361
371
  var formRef = react.useRef(null);
362
- var schemaRef = react.useRef({});
363
- var _useState9 = react.useState({}),
372
+ var _useState9 = react.useState([]),
364
373
  _useState10 = _slicedToArray(_useState9, 2),
365
- schema$1 = _useState10[0],
366
- setSchema = _useState10[1];
367
- var _useState11 = react.useState([]),
368
- _useState12 = _slicedToArray(_useState11, 2),
369
- schemaFields = _useState12[0],
370
- setSchemaFields = _useState12[1];
374
+ schemaFields = _useState10[0],
375
+ setSchemaFields = _useState10[1];
371
376
  react.useEffect(function () {
377
+ var _formRef$current$getV, _formRef$current, _formRef$current2;
372
378
  var schemaMap = Object.fromEntries(schemaDef.map(function (schema) {
373
379
  return [schema.id, schema];
374
380
  }));
381
+ var currentModel = (_formRef$current$getV = (_formRef$current = formRef.current) === null || _formRef$current === void 0 ? void 0 : _formRef$current.getValues()) !== null && _formRef$current$getV !== void 0 ? _formRef$current$getV : {};
375
382
  var schema = Object.fromEntries(Object.keys(schemaMap).map(function (field) {
376
- var _schemaRef$current$fi;
377
- return [field, (_schemaRef$current$fi = schemaRef.current[field]) !== null && _schemaRef$current$fi !== void 0 ? _schemaRef$current$fi : schemaMap[field]];
383
+ var _currentModel$field;
384
+ return [field, (_currentModel$field = currentModel[field]) !== null && _currentModel$field !== void 0 ? _currentModel$field : schemaMap[field]];
378
385
  }));
379
- setSchema(schema);
380
- setSchemaFields(Object.keys(schema));
386
+ (_formRef$current2 = formRef.current) === null || _formRef$current2 === void 0 || _formRef$current2.setValues(schema);
387
+ setTimeout(function () {
388
+ setSchemaFields(Object.keys(schema));
389
+ }, 100);
381
390
  }, [schemaDef]);
382
391
  var handleChange = react.useCallback(function (model) {
383
392
  onChange === null || onChange === void 0 || onChange(Object.values(model));
384
393
  }, []);
385
394
  var handleTypeChange = react.useCallback(function (field, val) {
386
- var _formRef$current;
387
- (_formRef$current = formRef.current) === null || _formRef$current === void 0 || _formRef$current.setValue(field, val);
395
+ var _formRef$current3;
396
+ (_formRef$current3 = formRef.current) === null || _formRef$current3 === void 0 || _formRef$current3.setValue(field, val);
397
+ }, []);
398
+ var handleRemove = react.useCallback(function (field) {
399
+ var _formRef$current$getV2, _formRef$current4, _formRef$current5;
400
+ var newSchema = (_formRef$current$getV2 = (_formRef$current4 = formRef.current) === null || _formRef$current4 === void 0 ? void 0 : _formRef$current4.getValues()) !== null && _formRef$current$getV2 !== void 0 ? _formRef$current$getV2 : {};
401
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
402
+ delete newSchema[field];
403
+ (_formRef$current5 = formRef.current) === null || _formRef$current5 === void 0 || _formRef$current5.setValues(newSchema);
404
+ setTimeout(function () {
405
+ setSchemaFields(Object.keys(newSchema));
406
+ }, 100);
388
407
  }, []);
389
408
  return /*#__PURE__*/jsxRuntime.jsxs(Form.Form, {
390
409
  formRef: formRef,
391
- values: schema$1,
392
- defaultValues: schema$1,
393
410
  onSubmit: handleChange,
394
411
  children: [/*#__PURE__*/jsxRuntime.jsx(core.Content, {
395
412
  className: "divide-y",
@@ -398,9 +415,12 @@ var SchemaEditor = function SchemaEditor(_ref2) {
398
415
  field: field,
399
416
  allowRemove: allowRemove,
400
417
  optionLists: optionLists,
418
+ onRemove: function onRemove() {
419
+ return handleRemove(field);
420
+ },
401
421
  getModel: function getModel() {
402
- var _formRef$current2;
403
- return (_formRef$current2 = formRef.current) === null || _formRef$current2 === void 0 ? void 0 : _formRef$current2.getValues()[field];
422
+ var _formRef$current6;
423
+ return (_formRef$current6 = formRef.current) === null || _formRef$current6 === void 0 ? void 0 : _formRef$current6.getValues()[field];
404
424
  },
405
425
  onTypeChange: function onTypeChange(val) {
406
426
  return handleTypeChange(field, val);
@@ -408,19 +428,10 @@ var SchemaEditor = function SchemaEditor(_ref2) {
408
428
  acceptableTypes: acceptableTypes !== null && acceptableTypes !== void 0 ? acceptableTypes : Object.values(schema.DATA_TYPES)
409
429
  }, field);
410
430
  })
411
- }), /*#__PURE__*/jsxRuntime.jsxs(core.Footer, {
431
+ }), children && /*#__PURE__*/jsxRuntime.jsx(core.Footer, {
412
432
  flex: true,
413
- justify: "end",
414
- className: "sticky bottom-0 border-t bg-base px-6 py-2",
415
- children: [/*#__PURE__*/jsxRuntime.jsx(core.Button, {
416
- type: "reset",
417
- variant: "link",
418
- children: "Reset"
419
- }), /*#__PURE__*/jsxRuntime.jsx(core.Button, {
420
- type: "submit",
421
- variant: "solid",
422
- children: "Submit"
423
- })]
433
+ className: "border-t bg-base px-6 py-2",
434
+ children: children
424
435
  })]
425
436
  });
426
437
  };
@@ -7,11 +7,12 @@ var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProp
7
7
  var _regeneratorRuntime = require('@babel/runtime/regenerator');
8
8
  var yup = require('@hookform/resolvers/yup');
9
9
  var core = require('@react-fabric/core');
10
+ var utilities = require('@react-fabric/utilities');
10
11
  var react = require('react');
11
12
  var reactHookForm = require('react-hook-form');
12
13
  var jsxRuntime = require('react/jsx-runtime');
13
14
 
14
- var _excluded = ["formRef", "schema", "children", "values", "defaultValues", "onSubmit", "onChange"];
15
+ var _excluded = ["formRef", "schema", "children", "defaultValues", "onSubmit", "onChange"];
15
16
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
16
17
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17
18
  var DEFAULT_SUBMIT = function DEFAULT_SUBMIT() {
@@ -21,16 +22,16 @@ var Form = function Form(_ref) {
21
22
  var formRef = _ref.formRef,
22
23
  schema = _ref.schema,
23
24
  children = _ref.children,
24
- values = _ref.values,
25
- defaultValues = _ref.defaultValues,
25
+ _ref$defaultValues = _ref.defaultValues,
26
+ defaultValues = _ref$defaultValues === void 0 ? utilities.EMPTY_OBJECT : _ref$defaultValues,
26
27
  _ref$onSubmit = _ref.onSubmit,
27
28
  onSubmit = _ref$onSubmit === void 0 ? DEFAULT_SUBMIT : _ref$onSubmit,
28
29
  onChange = _ref.onChange,
29
30
  rest = _objectWithoutProperties(_ref, _excluded);
30
31
  var ref = react.useRef(null);
31
32
  var form = reactHookForm.useForm({
32
- values: values,
33
33
  shouldFocusError: true,
34
+ shouldUnregister: true,
34
35
  resolver: schema && yup.yupResolver(schema),
35
36
  defaultValues: defaultValues
36
37
  });
@@ -95,6 +96,12 @@ var Form = function Form(_ref) {
95
96
  return form.reset(v);
96
97
  }, 50);
97
98
  },
99
+ removeField: function removeField(field) {
100
+ return form.unregister(field, {
101
+ keepDefaultValue: false,
102
+ keepValue: false
103
+ });
104
+ },
98
105
  setValue: function setValue(k, v) {
99
106
  return setTimeout(function () {
100
107
  return form.setValue(k, v, {
@@ -41,7 +41,7 @@ var ColorInput = function ColorInput(_ref) {
41
41
  var handleChange = react.useCallback(function (e) {
42
42
  setActualValue(e !== null && e !== void 0 ? e : defaultColor);
43
43
  onChange != null && react.startTransition(function () {
44
- return onChange(e);
44
+ return onChange(e !== null && e !== void 0 ? e : null);
45
45
  });
46
46
  }, [onChange]);
47
47
  var arrowRef = react.useRef(null);
@@ -68,7 +68,7 @@ var DateInput = function DateInput(_ref) {
68
68
  setActualValue("");
69
69
  setInputValue("");
70
70
  onChange != null && react.startTransition(function () {
71
- return onChange("");
71
+ return onChange(null);
72
72
  });
73
73
  }
74
74
  }, [onChange, inputFormat]);
@@ -86,7 +86,7 @@ var DateInput = function DateInput(_ref) {
86
86
  setActualValue("");
87
87
  setInputValue("");
88
88
  onChange != null && react.startTransition(function () {
89
- return onChange("");
89
+ return onChange(null);
90
90
  });
91
91
  }
92
92
  }, [onChange, inputFormat]);
@@ -90,7 +90,7 @@ var FileInput = function FileInput(_ref) {
90
90
  } else {
91
91
  var _e$target$files, _e$target$files$item, _e$target$files2;
92
92
  setActualValue(e === null || e === void 0 || (_e$target$files = e.target.files) === null || _e$target$files === void 0 ? void 0 : _e$target$files.item(0));
93
- onChange === null || onChange === void 0 || onChange((_e$target$files$item = e === null || e === void 0 || (_e$target$files2 = e.target.files) === null || _e$target$files2 === void 0 ? void 0 : _e$target$files2.item(0)) !== null && _e$target$files$item !== void 0 ? _e$target$files$item : undefined);
93
+ onChange === null || onChange === void 0 || onChange((_e$target$files$item = e === null || e === void 0 || (_e$target$files2 = e.target.files) === null || _e$target$files2 === void 0 ? void 0 : _e$target$files2.item(0)) !== null && _e$target$files$item !== void 0 ? _e$target$files$item : null);
94
94
  if (!e && inputRef.current) inputRef.current.value = "";
95
95
  }
96
96
  }, [onChange, multiple, showList]);
@@ -36,7 +36,7 @@ var HiddenInput = function HiddenInput(_ref) {
36
36
  value = _ref$value === void 0 ? "" : _ref$value,
37
37
  name = _ref.name;
38
38
  react.useEffect(function () {
39
- setTimeout(function () {
39
+ hiddenValue && setTimeout(function () {
40
40
  onChange === null || onChange === void 0 || onChange(hiddenValue);
41
41
  }, 50);
42
42
  }, [hiddenValue]);
@@ -42,7 +42,7 @@ var Input = function Input(_ref) {
42
42
  var handleChange = react.useCallback(function (e) {
43
43
  var value = e === null || e === void 0 ? void 0 : e.target.value;
44
44
  setActualValue(value !== null && value !== void 0 ? value : "");
45
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
45
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
46
46
  }, [onchange]);
47
47
  return /*#__PURE__*/jsxRuntime.jsx(InputWrapper.InputWrapper, _objectSpread(_objectSpread({
48
48
  showClear: !!actualValue,
@@ -42,7 +42,7 @@ var Number = function Number(_ref) {
42
42
  var handleChange = react.useCallback(function (e) {
43
43
  var number = e === null || e === void 0 ? void 0 : e.target.valueAsNumber;
44
44
  setActualValue(number !== null && number !== void 0 ? number : "");
45
- onChange === null || onChange === void 0 || onChange(number !== null && number !== void 0 ? number : undefined);
45
+ onChange === null || onChange === void 0 || onChange(number !== null && number !== void 0 ? number : null);
46
46
  }, [onChange]);
47
47
  return /*#__PURE__*/jsxRuntime.jsx(InputWrapper.InputWrapper, _objectSpread(_objectSpread({
48
48
  showClear: !!actualValue,
@@ -50,7 +50,7 @@ var Password = function Password(_ref) {
50
50
  var handleChange = react.useCallback(function (e) {
51
51
  var value = e === null || e === void 0 ? void 0 : e.target.value;
52
52
  setActualValue(value !== null && value !== void 0 ? value : "");
53
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
53
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
54
54
  }, [onChange]);
55
55
  return /*#__PURE__*/jsxRuntime.jsxs(InputWrapper.InputWrapper, _objectSpread(_objectSpread({
56
56
  showClear: !!actualValue,
@@ -71,7 +71,7 @@ var RangeSlider = function RangeSlider(_ref) {
71
71
  }, [showValue]);
72
72
  var handleChange = react.useCallback(function (val) {
73
73
  setActualValue(val !== null && val !== void 0 ? val : [min, max]);
74
- onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : undefined);
74
+ onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : null);
75
75
  }, [onChange, min, max]);
76
76
  var minDisplay = react.useMemo(function () {
77
77
  return /*#__PURE__*/jsxRuntime.jsx("span", {
@@ -53,7 +53,7 @@ var Search = function Search(_ref) {
53
53
  var value = e === null || e === void 0 ? void 0 : e.target.value;
54
54
  refValue.current = value !== null && value !== void 0 ? value : "";
55
55
  setActualValue(value !== null && value !== void 0 ? value : "");
56
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
56
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
57
57
 
58
58
  // value was cleared so force fire onSearch
59
59
  if (searchOnChange) {
@@ -73,7 +73,7 @@ var Slider = function Slider(_ref) {
73
73
  var handleChange = react.useCallback(function (value) {
74
74
  var val = useInfinity && value === max ? Infinity : value;
75
75
  setActualValue(val !== null && val !== void 0 ? val : 0);
76
- onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : undefined);
76
+ onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : null);
77
77
  }, [onChange, max, useInfinity]);
78
78
  var minDisplay = react.useMemo(function () {
79
79
  return /*#__PURE__*/jsxRuntime.jsx("span", {
@@ -47,7 +47,7 @@ var Textarea = function Textarea(_ref) {
47
47
  var handleChange = react.useCallback(function (e) {
48
48
  var value = e === null || e === void 0 ? void 0 : e.target.value;
49
49
  setActualValue(value !== null && value !== void 0 ? value : "");
50
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
50
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
51
51
  }, [onChange]);
52
52
  react.useEffect(function () {
53
53
  if (variableRows) {
@@ -106,7 +106,7 @@ var FormField = function FormField(_ref) {
106
106
  });
107
107
  return rest.multiple && !hasOptions ? /*#__PURE__*/jsx(ArrayInput, {
108
108
  name: fieldName,
109
- label: t(label, label),
109
+ label: t("fb.".concat(id), label || id),
110
110
  required: required,
111
111
  onAdd: function onAdd() {
112
112
  return String("");
@@ -118,8 +118,8 @@ var FormField = function FormField(_ref) {
118
118
  name: fieldName,
119
119
  children: /*#__PURE__*/jsx(E, _objectSpread(_objectSpread({}, props), {}, {
120
120
  autoFocus: autoFocus,
121
- label: t(label, label),
122
- placeholder: t(label, label),
121
+ label: t("fb.".concat(id), label || id),
122
+ placeholder: t("fb.".concat(id), label || id),
123
123
  required: required,
124
124
  inline: inline
125
125
  }))
@@ -3,7 +3,7 @@
3
3
  import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
4
4
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
5
5
  import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
6
- import { Content, Footer, Button, useOverlayService, Modal, Collapsable, CoreIcons, ToggleButtonGroup } from '@react-fabric/core';
6
+ import { Content, Footer, useOverlayService, Modal, Button, Collapsable, CoreIcons, ToggleButtonGroup } from '@react-fabric/core';
7
7
  import { EMPTY_ARRAY } from '@react-fabric/utilities';
8
8
  import { useRef, useState, useEffect, useCallback, Fragment } from 'react';
9
9
  import { Controller } from '../form/Controller.js';
@@ -12,6 +12,7 @@ import { ArrayInput } from '../input/ArrayInput.js';
12
12
  import { Checkbox } from '../input/Checkbox.js';
13
13
  import { DateInput } from '../input/DateInput.js';
14
14
  import { Field } from '../input/Field.js';
15
+ import { HiddenInput } from '../input/Hidden.js';
15
16
  import { Input } from '../input/Input.js';
16
17
  import { Number } from '../input/Number.js';
17
18
  import { Select } from '../select/Select.js';
@@ -24,6 +25,7 @@ var CUSTOM_LIST = "--CUSTOM--";
24
25
  var SchemaField = function SchemaField(_ref) {
25
26
  var field = _ref.field,
26
27
  getModel = _ref.getModel,
28
+ onRemove = _ref.onRemove,
27
29
  _ref$optionLists = _ref.optionLists,
28
30
  optionLists = _ref$optionLists === void 0 ? EMPTY_ARRAY : _ref$optionLists,
29
31
  allowRemove = _ref.allowRemove,
@@ -81,7 +83,7 @@ var SchemaField = function SchemaField(_ref) {
81
83
  setCustomOptions(model.optionList === CUSTOM_LIST);
82
84
  }, 10);
83
85
  }, []);
84
- useEffect(function () {
86
+ var handleTypeChange = useCallback(function (type) {
85
87
  if (type) {
86
88
  var modelRef = getModel();
87
89
  var reset = {
@@ -115,8 +117,9 @@ var SchemaField = function SchemaField(_ref) {
115
117
  setMultiple(false);
116
118
  }
117
119
  onTypeChange(reset);
120
+ setType(type);
118
121
  }
119
- }, [type]);
122
+ }, []);
120
123
  return /*#__PURE__*/jsxs(Collapsable, {
121
124
  open: true,
122
125
  children: [/*#__PURE__*/jsxs("div", {
@@ -131,11 +134,17 @@ var SchemaField = function SchemaField(_ref) {
131
134
  "aria-label": "Delete",
132
135
  stopPropagation: true,
133
136
  icon: CoreIcons.trash,
137
+ onClick: onRemove,
134
138
  className: "invisible group-hover/field:visible"
135
139
  })]
136
140
  }), /*#__PURE__*/jsxs("div", {
137
141
  className: "flex flex-col gap-1 pb-4",
138
142
  children: [/*#__PURE__*/jsx(Controller, {
143
+ name: "".concat(field, ".id"),
144
+ children: /*#__PURE__*/jsx(HiddenInput, {
145
+ hiddenValue: field
146
+ })
147
+ }), /*#__PURE__*/jsx(Controller, {
139
148
  name: "".concat(field, ".datatype"),
140
149
  children: /*#__PURE__*/jsx(Select, {
141
150
  inline: true,
@@ -143,7 +152,7 @@ var SchemaField = function SchemaField(_ref) {
143
152
  placeholder: "Data type",
144
153
  options: acceptableTypes,
145
154
  onChange: function onChange(val) {
146
- return setType(val);
155
+ return handleTypeChange(val);
147
156
  }
148
157
  })
149
158
  }), /*#__PURE__*/jsx(Controller, {
@@ -357,39 +366,47 @@ var SchemaEditor = function SchemaEditor(_ref2) {
357
366
  acceptableTypes = _ref2.acceptableTypes,
358
367
  _ref2$optionLists = _ref2.optionLists,
359
368
  optionLists = _ref2$optionLists === void 0 ? EMPTY_ARRAY : _ref2$optionLists,
369
+ children = _ref2.children,
360
370
  onChange = _ref2.onChange;
361
371
  var formRef = useRef(null);
362
- var schemaRef = useRef({});
363
- var _useState9 = useState({}),
372
+ var _useState9 = useState([]),
364
373
  _useState10 = _slicedToArray(_useState9, 2),
365
- schema = _useState10[0],
366
- setSchema = _useState10[1];
367
- var _useState11 = useState([]),
368
- _useState12 = _slicedToArray(_useState11, 2),
369
- schemaFields = _useState12[0],
370
- setSchemaFields = _useState12[1];
374
+ schemaFields = _useState10[0],
375
+ setSchemaFields = _useState10[1];
371
376
  useEffect(function () {
377
+ var _formRef$current$getV, _formRef$current, _formRef$current2;
372
378
  var schemaMap = Object.fromEntries(schemaDef.map(function (schema) {
373
379
  return [schema.id, schema];
374
380
  }));
381
+ var currentModel = (_formRef$current$getV = (_formRef$current = formRef.current) === null || _formRef$current === void 0 ? void 0 : _formRef$current.getValues()) !== null && _formRef$current$getV !== void 0 ? _formRef$current$getV : {};
375
382
  var schema = Object.fromEntries(Object.keys(schemaMap).map(function (field) {
376
- var _schemaRef$current$fi;
377
- return [field, (_schemaRef$current$fi = schemaRef.current[field]) !== null && _schemaRef$current$fi !== void 0 ? _schemaRef$current$fi : schemaMap[field]];
383
+ var _currentModel$field;
384
+ return [field, (_currentModel$field = currentModel[field]) !== null && _currentModel$field !== void 0 ? _currentModel$field : schemaMap[field]];
378
385
  }));
379
- setSchema(schema);
380
- setSchemaFields(Object.keys(schema));
386
+ (_formRef$current2 = formRef.current) === null || _formRef$current2 === void 0 || _formRef$current2.setValues(schema);
387
+ setTimeout(function () {
388
+ setSchemaFields(Object.keys(schema));
389
+ }, 100);
381
390
  }, [schemaDef]);
382
391
  var handleChange = useCallback(function (model) {
383
392
  onChange === null || onChange === void 0 || onChange(Object.values(model));
384
393
  }, []);
385
394
  var handleTypeChange = useCallback(function (field, val) {
386
- var _formRef$current;
387
- (_formRef$current = formRef.current) === null || _formRef$current === void 0 || _formRef$current.setValue(field, val);
395
+ var _formRef$current3;
396
+ (_formRef$current3 = formRef.current) === null || _formRef$current3 === void 0 || _formRef$current3.setValue(field, val);
397
+ }, []);
398
+ var handleRemove = useCallback(function (field) {
399
+ var _formRef$current$getV2, _formRef$current4, _formRef$current5;
400
+ var newSchema = (_formRef$current$getV2 = (_formRef$current4 = formRef.current) === null || _formRef$current4 === void 0 ? void 0 : _formRef$current4.getValues()) !== null && _formRef$current$getV2 !== void 0 ? _formRef$current$getV2 : {};
401
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
402
+ delete newSchema[field];
403
+ (_formRef$current5 = formRef.current) === null || _formRef$current5 === void 0 || _formRef$current5.setValues(newSchema);
404
+ setTimeout(function () {
405
+ setSchemaFields(Object.keys(newSchema));
406
+ }, 100);
388
407
  }, []);
389
408
  return /*#__PURE__*/jsxs(Form, {
390
409
  formRef: formRef,
391
- values: schema,
392
- defaultValues: schema,
393
410
  onSubmit: handleChange,
394
411
  children: [/*#__PURE__*/jsx(Content, {
395
412
  className: "divide-y",
@@ -398,9 +415,12 @@ var SchemaEditor = function SchemaEditor(_ref2) {
398
415
  field: field,
399
416
  allowRemove: allowRemove,
400
417
  optionLists: optionLists,
418
+ onRemove: function onRemove() {
419
+ return handleRemove(field);
420
+ },
401
421
  getModel: function getModel() {
402
- var _formRef$current2;
403
- return (_formRef$current2 = formRef.current) === null || _formRef$current2 === void 0 ? void 0 : _formRef$current2.getValues()[field];
422
+ var _formRef$current6;
423
+ return (_formRef$current6 = formRef.current) === null || _formRef$current6 === void 0 ? void 0 : _formRef$current6.getValues()[field];
404
424
  },
405
425
  onTypeChange: function onTypeChange(val) {
406
426
  return handleTypeChange(field, val);
@@ -408,19 +428,10 @@ var SchemaEditor = function SchemaEditor(_ref2) {
408
428
  acceptableTypes: acceptableTypes !== null && acceptableTypes !== void 0 ? acceptableTypes : Object.values(DATA_TYPES)
409
429
  }, field);
410
430
  })
411
- }), /*#__PURE__*/jsxs(Footer, {
431
+ }), children && /*#__PURE__*/jsx(Footer, {
412
432
  flex: true,
413
- justify: "end",
414
- className: "sticky bottom-0 border-t bg-base px-6 py-2",
415
- children: [/*#__PURE__*/jsx(Button, {
416
- type: "reset",
417
- variant: "link",
418
- children: "Reset"
419
- }), /*#__PURE__*/jsx(Button, {
420
- type: "submit",
421
- variant: "solid",
422
- children: "Submit"
423
- })]
433
+ className: "border-t bg-base px-6 py-2",
434
+ children: children
424
435
  })]
425
436
  });
426
437
  };
@@ -7,11 +7,12 @@ import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProper
7
7
  import _regeneratorRuntime from '@babel/runtime/regenerator';
8
8
  import { yupResolver } from '@hookform/resolvers/yup';
9
9
  import { useDebounce } from '@react-fabric/core';
10
+ import { EMPTY_OBJECT } from '@react-fabric/utilities';
10
11
  import { useRef, useTransition, useEffect, useCallback, useImperativeHandle } from 'react';
11
12
  import { useForm, FormProvider } from 'react-hook-form';
12
13
  import { jsx, jsxs } from 'react/jsx-runtime';
13
14
 
14
- var _excluded = ["formRef", "schema", "children", "values", "defaultValues", "onSubmit", "onChange"];
15
+ var _excluded = ["formRef", "schema", "children", "defaultValues", "onSubmit", "onChange"];
15
16
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
16
17
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
17
18
  var DEFAULT_SUBMIT = function DEFAULT_SUBMIT() {
@@ -21,16 +22,16 @@ var Form = function Form(_ref) {
21
22
  var formRef = _ref.formRef,
22
23
  schema = _ref.schema,
23
24
  children = _ref.children,
24
- values = _ref.values,
25
- defaultValues = _ref.defaultValues,
25
+ _ref$defaultValues = _ref.defaultValues,
26
+ defaultValues = _ref$defaultValues === void 0 ? EMPTY_OBJECT : _ref$defaultValues,
26
27
  _ref$onSubmit = _ref.onSubmit,
27
28
  onSubmit = _ref$onSubmit === void 0 ? DEFAULT_SUBMIT : _ref$onSubmit,
28
29
  onChange = _ref.onChange,
29
30
  rest = _objectWithoutProperties(_ref, _excluded);
30
31
  var ref = useRef(null);
31
32
  var form = useForm({
32
- values: values,
33
33
  shouldFocusError: true,
34
+ shouldUnregister: true,
34
35
  resolver: schema && yupResolver(schema),
35
36
  defaultValues: defaultValues
36
37
  });
@@ -95,6 +96,12 @@ var Form = function Form(_ref) {
95
96
  return form.reset(v);
96
97
  }, 50);
97
98
  },
99
+ removeField: function removeField(field) {
100
+ return form.unregister(field, {
101
+ keepDefaultValue: false,
102
+ keepValue: false
103
+ });
104
+ },
98
105
  setValue: function setValue(k, v) {
99
106
  return setTimeout(function () {
100
107
  return form.setValue(k, v, {
@@ -41,7 +41,7 @@ var ColorInput = function ColorInput(_ref) {
41
41
  var handleChange = useCallback(function (e) {
42
42
  setActualValue(e !== null && e !== void 0 ? e : defaultColor);
43
43
  onChange != null && startTransition(function () {
44
- return onChange(e);
44
+ return onChange(e !== null && e !== void 0 ? e : null);
45
45
  });
46
46
  }, [onChange]);
47
47
  var arrowRef = useRef(null);
@@ -68,7 +68,7 @@ var DateInput = function DateInput(_ref) {
68
68
  setActualValue("");
69
69
  setInputValue("");
70
70
  onChange != null && startTransition(function () {
71
- return onChange("");
71
+ return onChange(null);
72
72
  });
73
73
  }
74
74
  }, [onChange, inputFormat]);
@@ -86,7 +86,7 @@ var DateInput = function DateInput(_ref) {
86
86
  setActualValue("");
87
87
  setInputValue("");
88
88
  onChange != null && startTransition(function () {
89
- return onChange("");
89
+ return onChange(null);
90
90
  });
91
91
  }
92
92
  }, [onChange, inputFormat]);
@@ -90,7 +90,7 @@ var FileInput = function FileInput(_ref) {
90
90
  } else {
91
91
  var _e$target$files, _e$target$files$item, _e$target$files2;
92
92
  setActualValue(e === null || e === void 0 || (_e$target$files = e.target.files) === null || _e$target$files === void 0 ? void 0 : _e$target$files.item(0));
93
- onChange === null || onChange === void 0 || onChange((_e$target$files$item = e === null || e === void 0 || (_e$target$files2 = e.target.files) === null || _e$target$files2 === void 0 ? void 0 : _e$target$files2.item(0)) !== null && _e$target$files$item !== void 0 ? _e$target$files$item : undefined);
93
+ onChange === null || onChange === void 0 || onChange((_e$target$files$item = e === null || e === void 0 || (_e$target$files2 = e.target.files) === null || _e$target$files2 === void 0 ? void 0 : _e$target$files2.item(0)) !== null && _e$target$files$item !== void 0 ? _e$target$files$item : null);
94
94
  if (!e && inputRef.current) inputRef.current.value = "";
95
95
  }
96
96
  }, [onChange, multiple, showList]);
@@ -36,7 +36,7 @@ var HiddenInput = function HiddenInput(_ref) {
36
36
  value = _ref$value === void 0 ? "" : _ref$value,
37
37
  name = _ref.name;
38
38
  useEffect(function () {
39
- setTimeout(function () {
39
+ hiddenValue && setTimeout(function () {
40
40
  onChange === null || onChange === void 0 || onChange(hiddenValue);
41
41
  }, 50);
42
42
  }, [hiddenValue]);
@@ -42,7 +42,7 @@ var Input = function Input(_ref) {
42
42
  var handleChange = useCallback(function (e) {
43
43
  var value = e === null || e === void 0 ? void 0 : e.target.value;
44
44
  setActualValue(value !== null && value !== void 0 ? value : "");
45
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
45
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
46
46
  }, [onchange]);
47
47
  return /*#__PURE__*/jsx(InputWrapper, _objectSpread(_objectSpread({
48
48
  showClear: !!actualValue,
@@ -42,7 +42,7 @@ var Number = function Number(_ref) {
42
42
  var handleChange = useCallback(function (e) {
43
43
  var number = e === null || e === void 0 ? void 0 : e.target.valueAsNumber;
44
44
  setActualValue(number !== null && number !== void 0 ? number : "");
45
- onChange === null || onChange === void 0 || onChange(number !== null && number !== void 0 ? number : undefined);
45
+ onChange === null || onChange === void 0 || onChange(number !== null && number !== void 0 ? number : null);
46
46
  }, [onChange]);
47
47
  return /*#__PURE__*/jsx(InputWrapper, _objectSpread(_objectSpread({
48
48
  showClear: !!actualValue,
@@ -50,7 +50,7 @@ var Password = function Password(_ref) {
50
50
  var handleChange = useCallback(function (e) {
51
51
  var value = e === null || e === void 0 ? void 0 : e.target.value;
52
52
  setActualValue(value !== null && value !== void 0 ? value : "");
53
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
53
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
54
54
  }, [onChange]);
55
55
  return /*#__PURE__*/jsxs(InputWrapper, _objectSpread(_objectSpread({
56
56
  showClear: !!actualValue,
@@ -71,7 +71,7 @@ var RangeSlider = function RangeSlider(_ref) {
71
71
  }, [showValue]);
72
72
  var handleChange = useCallback(function (val) {
73
73
  setActualValue(val !== null && val !== void 0 ? val : [min, max]);
74
- onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : undefined);
74
+ onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : null);
75
75
  }, [onChange, min, max]);
76
76
  var minDisplay = useMemo(function () {
77
77
  return /*#__PURE__*/jsx("span", {
@@ -53,7 +53,7 @@ var Search = function Search(_ref) {
53
53
  var value = e === null || e === void 0 ? void 0 : e.target.value;
54
54
  refValue.current = value !== null && value !== void 0 ? value : "";
55
55
  setActualValue(value !== null && value !== void 0 ? value : "");
56
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
56
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
57
57
 
58
58
  // value was cleared so force fire onSearch
59
59
  if (searchOnChange) {
@@ -73,7 +73,7 @@ var Slider = function Slider(_ref) {
73
73
  var handleChange = useCallback(function (value) {
74
74
  var val = useInfinity && value === max ? Infinity : value;
75
75
  setActualValue(val !== null && val !== void 0 ? val : 0);
76
- onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : undefined);
76
+ onChange === null || onChange === void 0 || onChange(val !== null && val !== void 0 ? val : null);
77
77
  }, [onChange, max, useInfinity]);
78
78
  var minDisplay = useMemo(function () {
79
79
  return /*#__PURE__*/jsx("span", {
@@ -47,7 +47,7 @@ var Textarea = function Textarea(_ref) {
47
47
  var handleChange = useCallback(function (e) {
48
48
  var value = e === null || e === void 0 ? void 0 : e.target.value;
49
49
  setActualValue(value !== null && value !== void 0 ? value : "");
50
- onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : undefined);
50
+ onChange === null || onChange === void 0 || onChange(value !== null && value !== void 0 ? value : null);
51
51
  }, [onChange]);
52
52
  useEffect(function () {
53
53
  if (variableRows) {
@@ -1,10 +1,16 @@
1
+ /// <reference types="react" />
2
+ import { type Elements } from "@react-fabric/core/dist/types/types";
1
3
  import { DATA_TYPES, type FormSchema } from "../types/schema";
2
4
  interface Props {
3
5
  schemaDef: FormSchema;
4
6
  allowRemove?: boolean;
5
7
  acceptableTypes?: DATA_TYPES[];
6
8
  optionLists?: string[];
9
+ /**
10
+ * Footer actions
11
+ */
12
+ children?: Elements<JSX.Element> | Array<Elements<JSX.Element>>;
7
13
  onChange: (schema: FormSchema) => void;
8
14
  }
9
- export declare const SchemaEditor: ({ schemaDef, allowRemove, acceptableTypes, optionLists, onChange, }: Props) => import("react/jsx-runtime").JSX.Element;
15
+ export declare const SchemaEditor: ({ schemaDef, allowRemove, acceptableTypes, optionLists, children, onChange, }: Props) => import("react/jsx-runtime").JSX.Element;
10
16
  export {};
@@ -8,6 +8,7 @@ export interface FormRef<K extends KeyValue> {
8
8
  submit: () => void;
9
9
  validate: () => Promise<boolean>;
10
10
  getValues: () => K;
11
+ removeField: (field: string) => void;
11
12
  setValue: (key: keyof K, value: AnyObject) => void;
12
13
  setValues: (values: K) => void;
13
14
  }
@@ -17,10 +18,6 @@ export interface FormProps<K extends KeyValue = KeyValue> {
17
18
  * form data schema
18
19
  */
19
20
  schema?: yup.ObjectSchema<K>;
20
- /**
21
- * current form model
22
- */
23
- values?: K;
24
21
  /**
25
22
  * default data values
26
23
  */
@@ -34,4 +31,4 @@ export interface FormProps<K extends KeyValue = KeyValue> {
34
31
  */
35
32
  onSubmit?: (values: K) => void;
36
33
  }
37
- export declare const Form: <K extends KeyValue<any>>({ formRef, schema, children, values, defaultValues, onSubmit, onChange, ...rest }: PropsWithChildren<FormProps<K>>) => import("react/jsx-runtime").JSX.Element;
34
+ export declare const Form: <K extends KeyValue<any>>({ formRef, schema, children, defaultValues, onSubmit, onChange, ...rest }: PropsWithChildren<FormProps<K>>) => import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import { type RefProp } from "@react-fabric/core/dist/types/types";
2
2
  import { type InputProps } from "../types";
3
3
  import { type ColorProps } from "./ColorPicker";
4
- export interface ColorInputProps extends InputProps, ColorProps, RefProp {
4
+ export interface ColorInputProps extends InputProps, Omit<ColorProps, "onChange">, RefProp {
5
5
  /**
6
6
  * show eydrop picker
7
7
  */
@@ -8,7 +8,7 @@ export interface InputProps<V = string> extends TestProps {
8
8
  /**
9
9
  * change handler
10
10
  */
11
- onChange?: (value?: V) => void;
11
+ onChange?: (value?: V | null) => void;
12
12
  /**
13
13
  * on focus event handler
14
14
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-fabric/form",
3
- "version": "1.0.0-beta.33",
3
+ "version": "1.0.0-beta.34",
4
4
  "description": "RUF: Form package",
5
5
  "author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
6
6
  "license": "MIT",
@@ -39,9 +39,9 @@
39
39
  "@dnd-kit/utilities": "^3.2.2",
40
40
  "@floating-ui/react": "^0.26.24",
41
41
  "@hookform/resolvers": "^3.9.0",
42
- "@react-fabric/core": "^1.0.0-beta.33",
43
- "@react-fabric/date": "^1.0.0-beta.33",
44
- "@react-fabric/utilities": "^1.0.0-beta.33",
42
+ "@react-fabric/core": "^1.0.0-beta.34",
43
+ "@react-fabric/date": "^1.0.0-beta.34",
44
+ "@react-fabric/utilities": "^1.0.0-beta.34",
45
45
  "classnames": "^2.5.1",
46
46
  "color": "^4.2.3",
47
47
  "react-color": "^2.19.3",
@@ -61,5 +61,5 @@
61
61
  "node": ">=18.12.0",
62
62
  "npm": ">=8.19.0"
63
63
  },
64
- "gitHead": "3b7ffc99aac7b8fdc72c7122c39db55d1104297f"
64
+ "gitHead": "dcd1c1b247b6597b168a0649d2b3a53463b9c37e"
65
65
  }
@@ -151,7 +151,7 @@ export const FormField = ({
151
151
  return rest.multiple && !hasOptions ? (
152
152
  <ArrayInput
153
153
  name={fieldName}
154
- label={t(label, label)}
154
+ label={t(`fb.${id}`, label || id)}
155
155
  required={required}
156
156
  onAdd={() => String("")}
157
157
  >
@@ -164,8 +164,8 @@ export const FormField = ({
164
164
  <E
165
165
  {...props}
166
166
  autoFocus={autoFocus}
167
- label={t(label, label)}
168
- placeholder={t(label, label)}
167
+ label={t(`fb.${id}`, label || id)}
168
+ placeholder={t(`fb.${id}`, label || id)}
169
169
  required={required}
170
170
  inline={inline}
171
171
  />
@@ -31,6 +31,7 @@ import {
31
31
  ToggleButtonGroup,
32
32
  useOverlayService,
33
33
  } from "@react-fabric/core";
34
+ import { type Elements } from "@react-fabric/core/dist/types/types";
34
35
  import { EMPTY_ARRAY } from "@react-fabric/utilities";
35
36
  import { Fragment, useCallback, useEffect, useRef, useState } from "react";
36
37
  import { Controller } from "../form/Controller";
@@ -39,6 +40,7 @@ import { ArrayInput } from "../input/ArrayInput";
39
40
  import { Checkbox } from "../input/Checkbox";
40
41
  import { DateInput } from "../input/DateInput";
41
42
  import { Field } from "../input/Field";
43
+ import { HiddenInput } from "../input/Hidden";
42
44
  import { Input } from "../input/Input";
43
45
  import { Number } from "../input/Number";
44
46
  import { Select } from "../select/Select";
@@ -60,6 +62,11 @@ interface Props {
60
62
 
61
63
  optionLists?: string[];
62
64
 
65
+ /**
66
+ * Footer actions
67
+ */
68
+ children?: Elements<JSX.Element> | Array<Elements<JSX.Element>>;
69
+
63
70
  onChange: (schema: FormSchema) => void;
64
71
  }
65
72
 
@@ -68,12 +75,14 @@ const CUSTOM_LIST = "--CUSTOM--";
68
75
  const SchemaField = ({
69
76
  field,
70
77
  getModel,
78
+ onRemove,
71
79
  optionLists = EMPTY_ARRAY,
72
80
  allowRemove,
73
81
  onTypeChange,
74
82
  acceptableTypes,
75
83
  }: {
76
84
  field: string;
85
+ onRemove: () => void;
77
86
  getModel: () => KeyValue;
78
87
  onTypeChange: (val: KeyValue) => void;
79
88
  } & Omit<Props, "schemaDef" | "onChange">) => {
@@ -113,7 +122,7 @@ const SchemaField = ({
113
122
  }, 10);
114
123
  }, []);
115
124
 
116
- useEffect(() => {
125
+ const handleTypeChange = useCallback((type: DATA_TYPES) => {
117
126
  if (type) {
118
127
  const modelRef = getModel();
119
128
  let reset = {
@@ -147,8 +156,9 @@ const SchemaField = ({
147
156
  setMultiple(false);
148
157
  }
149
158
  onTypeChange(reset);
159
+ setType(type);
150
160
  }
151
- }, [type]);
161
+ }, []);
152
162
 
153
163
  return (
154
164
  <Collapsable key={field} open>
@@ -162,18 +172,22 @@ const SchemaField = ({
162
172
  aria-label="Delete"
163
173
  stopPropagation
164
174
  icon={CoreIcons.trash}
175
+ onClick={onRemove}
165
176
  className="invisible group-hover/field:visible"
166
177
  />
167
178
  )}
168
179
  </div>
169
180
  <div className="flex flex-col gap-1 pb-4">
181
+ <Controller name={`${field}.id`}>
182
+ <HiddenInput hiddenValue={field} />
183
+ </Controller>
170
184
  <Controller name={`${field}.datatype`}>
171
185
  <Select
172
186
  inline
173
187
  label="Type"
174
188
  placeholder="Data type"
175
189
  options={acceptableTypes}
176
- onChange={(val) => setType(val as unknown as DATA_TYPES)}
190
+ onChange={(val) => handleTypeChange(val as unknown as DATA_TYPES)}
177
191
  />
178
192
  </Controller>
179
193
  <Controller name={`${field}.label`}>
@@ -374,11 +388,10 @@ export const SchemaEditor = ({
374
388
  allowRemove,
375
389
  acceptableTypes,
376
390
  optionLists = EMPTY_ARRAY,
391
+ children,
377
392
  onChange,
378
393
  }: Props) => {
379
394
  const formRef = useRef<FormRef<KeyValue>>(null);
380
- const schemaRef = useRef<KeyValue>({});
381
- const [schema, setSchema] = useState<KeyValue<SchemaDef>>({});
382
395
  const [schemaFields, setSchemaFields] = useState<string[]>([]);
383
396
 
384
397
  useEffect(() => {
@@ -386,14 +399,18 @@ export const SchemaEditor = ({
386
399
  schemaDef.map((schema) => [schema.id, schema]),
387
400
  );
388
401
 
402
+ const currentModel: KeyValue = formRef.current?.getValues() ?? {};
403
+
389
404
  const schema = Object.fromEntries(
390
405
  Object.keys(schemaMap).map((field) => [
391
406
  field,
392
- schemaRef.current[field] ?? schemaMap[field],
407
+ currentModel[field] ?? schemaMap[field],
393
408
  ]),
394
409
  );
395
- setSchema(schema);
396
- setSchemaFields(Object.keys(schema));
410
+ formRef.current?.setValues(schema);
411
+ setTimeout(() => {
412
+ setSchemaFields(Object.keys(schema));
413
+ }, 100);
397
414
  }, [schemaDef]);
398
415
 
399
416
  const handleChange = useCallback((model: KeyValue<SchemaDef>) => {
@@ -404,13 +421,18 @@ export const SchemaEditor = ({
404
421
  formRef.current?.setValue(field, val);
405
422
  }, []);
406
423
 
424
+ const handleRemove = useCallback((field: string) => {
425
+ const newSchema: KeyValue = formRef.current?.getValues() ?? {};
426
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
427
+ delete newSchema[field];
428
+ formRef.current?.setValues(newSchema);
429
+ setTimeout(() => {
430
+ setSchemaFields(Object.keys(newSchema));
431
+ }, 100);
432
+ }, []);
433
+
407
434
  return (
408
- <Form
409
- formRef={formRef}
410
- values={schema}
411
- defaultValues={schema}
412
- onSubmit={handleChange}
413
- >
435
+ <Form formRef={formRef} onSubmit={handleChange}>
414
436
  <Content className="divide-y">
415
437
  {schemaFields.map((field) => (
416
438
  <SchemaField
@@ -418,24 +440,18 @@ export const SchemaEditor = ({
418
440
  field={field}
419
441
  allowRemove={allowRemove}
420
442
  optionLists={optionLists}
443
+ onRemove={() => handleRemove(field)}
421
444
  getModel={() => formRef.current?.getValues()[field]}
422
445
  onTypeChange={(val: KeyValue) => handleTypeChange(field, val)}
423
446
  acceptableTypes={acceptableTypes ?? Object.values(DATA_TYPES)}
424
447
  />
425
448
  ))}
426
449
  </Content>
427
- <Footer
428
- flex
429
- justify="end"
430
- className="sticky bottom-0 border-t bg-base px-6 py-2"
431
- >
432
- <Button type="reset" variant="link">
433
- Reset
434
- </Button>
435
- <Button type="submit" variant="solid">
436
- Submit
437
- </Button>
438
- </Footer>
450
+ {children && (
451
+ <Footer flex className="border-t bg-base px-6 py-2">
452
+ {children}
453
+ </Footer>
454
+ )}
439
455
  </Form>
440
456
  );
441
457
  };
package/src/form/Form.tsx CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  import { yupResolver } from "@hookform/resolvers/yup";
25
25
  import { useDebounce } from "@react-fabric/core";
26
- import { type yup } from "@react-fabric/utilities";
26
+ import { EMPTY_OBJECT, type yup } from "@react-fabric/utilities";
27
27
  import {
28
28
  useCallback,
29
29
  useEffect,
@@ -47,6 +47,7 @@ export interface FormRef<K extends KeyValue> {
47
47
  submit: () => void;
48
48
  validate: () => Promise<boolean>;
49
49
  getValues: () => K;
50
+ removeField: (field: string) => void;
50
51
  setValue: (key: keyof K, value: AnyObject) => void;
51
52
  setValues: (values: K) => void;
52
53
  }
@@ -57,10 +58,6 @@ export interface FormProps<K extends KeyValue = KeyValue> {
57
58
  * form data schema
58
59
  */
59
60
  schema?: yup.ObjectSchema<K>;
60
- /**
61
- * current form model
62
- */
63
- values?: K;
64
61
  /**
65
62
  * default data values
66
63
  */
@@ -81,16 +78,15 @@ export const Form = <K extends KeyValue>({
81
78
  formRef,
82
79
  schema,
83
80
  children,
84
- values,
85
- defaultValues,
81
+ defaultValues = EMPTY_OBJECT as K,
86
82
  onSubmit = DEFAULT_SUBMIT,
87
83
  onChange,
88
84
  ...rest
89
85
  }: PropsWithChildren<FormProps<K>>) => {
90
86
  const ref = useRef<HTMLFormElement>(null);
91
87
  const form = useForm<K>({
92
- values,
93
88
  shouldFocusError: true,
89
+ shouldUnregister: true,
94
90
  resolver: schema && (yupResolver(schema) as AnyObject),
95
91
  defaultValues: defaultValues as DefaultValues<K>,
96
92
  });
@@ -125,6 +121,8 @@ export const Form = <K extends KeyValue>({
125
121
  validate: async () => await form.trigger(),
126
122
  getValues: () => form.getValues(),
127
123
  setValues: (v) => setTimeout(() => form.reset(v), 50),
124
+ removeField: (field: AnyObject) =>
125
+ form.unregister(field, { keepDefaultValue: false, keepValue: false }),
128
126
  setValue: (k, v) =>
129
127
  setTimeout(
130
128
  () =>
@@ -48,7 +48,10 @@ import {
48
48
  import { type InputProps } from "../types";
49
49
  import { ColorPicker, type ColorProps } from "./ColorPicker";
50
50
 
51
- export interface ColorInputProps extends InputProps, ColorProps, RefProp {
51
+ export interface ColorInputProps
52
+ extends InputProps,
53
+ Omit<ColorProps, "onChange">,
54
+ RefProp {
52
55
  /**
53
56
  * show eydrop picker
54
57
  */
@@ -82,7 +85,7 @@ export const ColorInput = ({
82
85
  const handleChange = useCallback(
83
86
  (e?: string) => {
84
87
  setActualValue(e ?? defaultColor);
85
- onChange != null && startTransition(() => onChange(e));
88
+ onChange != null && startTransition(() => onChange(e ?? null));
86
89
  },
87
90
  [onChange],
88
91
  );
@@ -120,7 +120,7 @@ export const DateInput = ({
120
120
  } else {
121
121
  setActualValue("");
122
122
  setInputValue("");
123
- onChange != null && startTransition(() => onChange(""));
123
+ onChange != null && startTransition(() => onChange(null));
124
124
  }
125
125
  },
126
126
  [onChange, inputFormat],
@@ -137,7 +137,7 @@ export const DateInput = ({
137
137
  } else {
138
138
  setActualValue("");
139
139
  setInputValue("");
140
- onChange != null && startTransition(() => onChange(""));
140
+ onChange != null && startTransition(() => onChange(null));
141
141
  }
142
142
  },
143
143
  [onChange, inputFormat],
@@ -134,7 +134,7 @@ export const FileInput = ({
134
134
  }
135
135
  } else {
136
136
  setActualValue(e?.target.files?.item(0));
137
- onChange?.(e?.target.files?.item(0) ?? undefined);
137
+ onChange?.(e?.target.files?.item(0) ?? null);
138
138
  if (!e && inputRef.current) inputRef.current.value = "";
139
139
  }
140
140
  },
@@ -54,9 +54,10 @@ export const HiddenInput = ({
54
54
  name,
55
55
  }: Props) => {
56
56
  useEffect(() => {
57
- setTimeout(() => {
58
- onChange?.(hiddenValue);
59
- }, 50);
57
+ hiddenValue &&
58
+ setTimeout(() => {
59
+ onChange?.(hiddenValue);
60
+ }, 50);
60
61
  }, [hiddenValue]);
61
62
  return (
62
63
  <Fragment>
@@ -73,7 +73,7 @@ export const Input = ({
73
73
  (e?: ChangeEvent<HTMLInputElement>) => {
74
74
  const value = e?.target.value;
75
75
  setActualValue(value ?? "");
76
- onChange?.(value ?? undefined);
76
+ onChange?.(value ?? null);
77
77
  },
78
78
  [onchange],
79
79
  );
@@ -84,7 +84,7 @@ export const Number = ({
84
84
  (e?: ChangeEvent<HTMLInputElement>) => {
85
85
  const number = e?.target.valueAsNumber;
86
86
  setActualValue(number ?? "");
87
- onChange?.(number ?? undefined);
87
+ onChange?.(number ?? null);
88
88
  },
89
89
  [onChange],
90
90
  );
@@ -83,7 +83,7 @@ export const Password = ({
83
83
  (e?: ChangeEvent<HTMLInputElement>) => {
84
84
  const value = e?.target.value;
85
85
  setActualValue(value ?? "");
86
- onChange?.(value ?? undefined);
86
+ onChange?.(value ?? null);
87
87
  },
88
88
  [onChange],
89
89
  );
@@ -141,7 +141,7 @@ export const RangeSlider = ({
141
141
  const handleChange = useCallback(
142
142
  (val: [number, number]) => {
143
143
  setActualValue(val ?? [min, max]);
144
- onChange?.(val ?? undefined);
144
+ onChange?.(val ?? null);
145
145
  },
146
146
  [onChange, min, max],
147
147
  );
@@ -96,7 +96,7 @@ export const Search = ({
96
96
  const value = e?.target.value;
97
97
  refValue.current = value ?? "";
98
98
  setActualValue(value ?? "");
99
- onChange?.(value ?? undefined);
99
+ onChange?.(value ?? null);
100
100
 
101
101
  // value was cleared so force fire onSearch
102
102
  if (searchOnChange) {
@@ -146,7 +146,7 @@ export const Slider = ({
146
146
  (value: number) => {
147
147
  const val = useInfinity && value === max ? Infinity : value;
148
148
  setActualValue(val ?? 0);
149
- onChange?.(val ?? undefined);
149
+ onChange?.(val ?? null);
150
150
  },
151
151
  [onChange, max, useInfinity],
152
152
  );
@@ -86,7 +86,7 @@ export const Textarea = ({
86
86
  (e?: ChangeEvent<HTMLTextAreaElement>) => {
87
87
  const value = e?.target.value;
88
88
  setActualValue(value ?? "");
89
- onChange?.(value ?? undefined);
89
+ onChange?.(value ?? null);
90
90
  },
91
91
  [onChange],
92
92
  );
@@ -34,7 +34,7 @@ export interface InputProps<V = string> extends TestProps {
34
34
  /**
35
35
  * change handler
36
36
  */
37
- onChange?: (value?: V) => void;
37
+ onChange?: (value?: V | null) => void;
38
38
  /**
39
39
  * on focus event handler
40
40
  */