@react-fabric/form 1.0.0-beta.6 → 1.0.0-beta.61

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 (187) hide show
  1. package/{src/input/ArrayInput.module.css → css/_arrayInput.css} +8 -8
  2. package/css/_colorPicker.css +65 -0
  3. package/{src/internal/Field.module.css → css/_field.css} +66 -30
  4. package/{src/input/File.module.css → css/_file.css} +21 -6
  5. package/css/styles.css +27 -0
  6. package/dist/cjs/builder/FileField.js +40 -28
  7. package/dist/cjs/builder/FormField.js +50 -34
  8. package/dist/cjs/builder/SchemaEditor.js +72 -0
  9. package/dist/cjs/builder/components/AddSchemaFields.js +63 -0
  10. package/dist/cjs/builder/components/SchemaArrayForm.js +145 -0
  11. package/dist/cjs/builder/components/SchemaField.js +414 -0
  12. package/dist/cjs/form/Controller.js +46 -1
  13. package/dist/cjs/form/Form.js +71 -13
  14. package/dist/cjs/hooks/useFileUploader.js +16 -0
  15. package/dist/cjs/hooks/useFormBuilder.js +67 -18
  16. package/dist/cjs/i18n/ar.json.js +5 -4
  17. package/dist/cjs/i18n/en.json.js +5 -5
  18. package/dist/cjs/index.js +12 -2
  19. package/dist/cjs/input/ArrayInput.js +128 -38
  20. package/dist/cjs/input/AvatarInput.js +43 -23
  21. package/dist/cjs/input/Checkbox.js +18 -8
  22. package/dist/cjs/input/ColorInput.js +114 -59
  23. package/dist/cjs/input/ColorPicker.js +60 -76
  24. package/dist/cjs/input/DateInput.js +197 -0
  25. package/dist/cjs/input/Field.js +10 -4
  26. package/dist/cjs/input/File.js +15 -8
  27. package/dist/cjs/input/Hidden.js +13 -2
  28. package/dist/cjs/input/Input.js +24 -10
  29. package/dist/cjs/input/Number.js +22 -10
  30. package/dist/cjs/input/Password.js +23 -13
  31. package/dist/cjs/input/Radio.js +14 -5
  32. package/dist/cjs/input/RadioGroup.js +10 -1
  33. package/dist/cjs/input/{Range.js → RangeSlider.js} +16 -8
  34. package/dist/cjs/input/Search.js +32 -22
  35. package/dist/cjs/input/Slider.js +12 -6
  36. package/dist/cjs/input/Switch.js +20 -9
  37. package/dist/cjs/input/Textarea.js +29 -8
  38. package/dist/cjs/internal/ErrorIcon.js +2 -2
  39. package/dist/cjs/internal/FieldWrapper.js +11 -4
  40. package/dist/cjs/internal/InputWrapper.js +29 -22
  41. package/dist/cjs/select/AutoComplete.js +22 -13
  42. package/dist/cjs/select/DualList.js +34 -12
  43. package/dist/cjs/select/List.js +49 -21
  44. package/dist/cjs/select/Options.js +49 -42
  45. package/dist/cjs/select/Select.js +21 -10
  46. package/dist/cjs/select/useSelect.js +22 -11
  47. package/dist/cjs/types/schema.js +43 -0
  48. package/dist/cjs/utils/eventHandlers.js +15 -5
  49. package/dist/esm/builder/FileField.js +42 -30
  50. package/dist/esm/builder/FormField.js +50 -34
  51. package/dist/esm/builder/SchemaEditor.js +72 -0
  52. package/dist/esm/builder/components/AddSchemaFields.js +63 -0
  53. package/dist/esm/builder/components/SchemaArrayForm.js +145 -0
  54. package/dist/esm/builder/components/SchemaField.js +414 -0
  55. package/dist/esm/form/Controller.js +46 -1
  56. package/dist/esm/form/Form.js +73 -16
  57. package/dist/esm/hooks/useFileUploader.js +16 -0
  58. package/dist/esm/hooks/useFormBuilder.js +65 -16
  59. package/dist/esm/i18n/ar.json.js +5 -4
  60. package/dist/esm/i18n/en.json.js +5 -5
  61. package/dist/esm/index.js +6 -2
  62. package/dist/esm/input/ArrayInput.js +128 -38
  63. package/dist/esm/input/AvatarInput.js +43 -23
  64. package/dist/esm/input/Checkbox.js +19 -9
  65. package/dist/esm/input/ColorInput.js +116 -61
  66. package/dist/esm/input/ColorPicker.js +60 -76
  67. package/dist/esm/input/DateInput.js +197 -0
  68. package/dist/esm/input/Field.js +11 -5
  69. package/dist/esm/input/File.js +18 -11
  70. package/dist/esm/input/Hidden.js +13 -2
  71. package/dist/esm/input/Input.js +26 -12
  72. package/dist/esm/input/Number.js +24 -12
  73. package/dist/esm/input/Password.js +26 -16
  74. package/dist/esm/input/Radio.js +15 -6
  75. package/dist/esm/input/RadioGroup.js +11 -2
  76. package/dist/esm/input/{Range.js → RangeSlider.js} +16 -8
  77. package/dist/esm/input/Search.js +35 -25
  78. package/dist/esm/input/Slider.js +12 -6
  79. package/dist/esm/input/Switch.js +20 -9
  80. package/dist/esm/input/Textarea.js +30 -9
  81. package/dist/esm/internal/ErrorIcon.js +3 -3
  82. package/dist/esm/internal/FieldWrapper.js +11 -4
  83. package/dist/esm/internal/InputWrapper.js +30 -23
  84. package/dist/esm/select/AutoComplete.js +23 -14
  85. package/dist/esm/select/DualList.js +35 -13
  86. package/dist/esm/select/List.js +50 -22
  87. package/dist/esm/select/Options.js +49 -42
  88. package/dist/esm/select/Select.js +22 -11
  89. package/dist/esm/select/useSelect.js +23 -12
  90. package/{src/input/ColorPicker.module.css → dist/esm/types/schema.js} +18 -27
  91. package/dist/esm/utils/eventHandlers.js +15 -5
  92. package/dist/types/builder/FileField.d.ts +4 -2
  93. package/dist/types/builder/FormField.d.ts +3 -1
  94. package/dist/types/builder/SchemaEditor.d.ts +9 -0
  95. package/dist/types/builder/components/AddSchemaFields.d.ts +2 -0
  96. package/dist/types/builder/components/SchemaArrayForm.d.ts +2 -0
  97. package/dist/types/builder/components/SchemaField.d.ts +10 -0
  98. package/dist/types/form/Controller.d.ts +47 -2
  99. package/dist/types/form/Form.d.ts +49 -6
  100. package/dist/types/hooks/useFileUploader.d.ts +16 -0
  101. package/dist/types/hooks/useFormBuilder.d.ts +38 -1
  102. package/dist/types/index.d.ts +6 -3
  103. package/dist/types/input/ArrayInput.d.ts +69 -12
  104. package/dist/types/input/AvatarInput.d.ts +23 -3
  105. package/dist/types/input/Checkbox.d.ts +13 -4
  106. package/dist/types/input/ColorInput.d.ts +15 -2
  107. package/dist/types/input/ColorPicker.d.ts +11 -1
  108. package/dist/types/input/DateInput.d.ts +28 -0
  109. package/dist/types/input/Field.d.ts +5 -1
  110. package/dist/types/input/File.d.ts +9 -0
  111. package/dist/types/input/Hidden.d.ts +13 -1
  112. package/dist/types/input/Input.d.ts +9 -1
  113. package/dist/types/input/Number.d.ts +9 -1
  114. package/dist/types/input/Password.d.ts +7 -1
  115. package/dist/types/input/Radio.d.ts +9 -1
  116. package/dist/types/input/RadioGroup.d.ts +8 -1
  117. package/dist/types/input/RangeSlider.d.ts +67 -0
  118. package/dist/types/input/Search.d.ts +14 -1
  119. package/dist/types/input/Slider.d.ts +8 -2
  120. package/dist/types/input/Switch.d.ts +10 -2
  121. package/dist/types/input/Textarea.d.ts +15 -1
  122. package/dist/types/internal/FieldWrapper.d.ts +1 -1
  123. package/dist/types/internal/InputWrapper.d.ts +1 -1
  124. package/dist/types/ranger/index.d.ts +2 -2
  125. package/dist/types/select/AutoComplete.d.ts +8 -1
  126. package/dist/types/select/DualList.d.ts +21 -7
  127. package/dist/types/select/List.d.ts +9 -1
  128. package/dist/types/select/Options.d.ts +4 -3
  129. package/dist/types/select/Select.d.ts +9 -1
  130. package/dist/types/select/useSelect.d.ts +10 -6
  131. package/dist/types/types/index.d.ts +38 -10
  132. package/dist/types/types/schema.d.ts +78 -33
  133. package/dist/types/utils/eventHandlers.d.ts +2 -2
  134. package/package.json +22 -20
  135. package/src/builder/FileField.tsx +56 -30
  136. package/src/builder/FormField.tsx +52 -32
  137. package/src/builder/SchemaEditor.tsx +79 -0
  138. package/src/builder/components/AddSchemaFields.tsx +75 -0
  139. package/src/builder/components/SchemaArrayForm.tsx +155 -0
  140. package/src/builder/components/SchemaField.tsx +435 -0
  141. package/src/form/Controller.tsx +48 -3
  142. package/src/form/Form.tsx +84 -13
  143. package/src/hooks/useFileUploader.ts +16 -0
  144. package/src/hooks/useFormBuilder.tsx +70 -19
  145. package/src/i18n/ar.json +5 -4
  146. package/src/i18n/en.json +5 -5
  147. package/src/index.ts +12 -3
  148. package/src/input/ArrayInput.tsx +195 -66
  149. package/src/input/AvatarInput.tsx +66 -18
  150. package/src/input/Checkbox.tsx +22 -9
  151. package/src/input/ColorInput.tsx +128 -72
  152. package/src/input/ColorPicker.tsx +54 -72
  153. package/src/input/DateInput.tsx +260 -0
  154. package/src/input/Field.tsx +15 -11
  155. package/src/input/File.tsx +18 -16
  156. package/src/input/Hidden.tsx +17 -2
  157. package/src/input/Input.tsx +27 -13
  158. package/src/input/Number.tsx +22 -13
  159. package/src/input/Password.tsx +28 -18
  160. package/src/input/Radio.tsx +15 -6
  161. package/src/input/RadioGroup.tsx +12 -3
  162. package/src/input/{Range.tsx → RangeSlider.tsx} +17 -9
  163. package/src/input/Search.tsx +36 -25
  164. package/src/input/Slider.tsx +20 -11
  165. package/src/input/Switch.tsx +17 -6
  166. package/src/input/Textarea.tsx +34 -9
  167. package/src/internal/ErrorIcon.tsx +3 -3
  168. package/src/internal/FieldWrapper.tsx +8 -4
  169. package/src/internal/InputWrapper.tsx +56 -30
  170. package/src/select/AutoComplete.tsx +16 -6
  171. package/src/select/DualList.tsx +40 -22
  172. package/src/select/List.tsx +52 -8
  173. package/src/select/Options.tsx +50 -46
  174. package/src/select/Select.tsx +29 -10
  175. package/src/select/useSelect.tsx +26 -9
  176. package/src/types/index.ts +42 -10
  177. package/src/types/schema.ts +96 -41
  178. package/src/utils/eventHandlers.ts +14 -4
  179. package/dist/cjs/input/ArrayInput.module.css +0 -1
  180. package/dist/cjs/input/ColorPicker.module.css +0 -1
  181. package/dist/cjs/input/File.module.css +0 -1
  182. package/dist/cjs/internal/Field.module.css +0 -1
  183. package/dist/esm/input/ArrayInput.module.css +0 -1
  184. package/dist/esm/input/ColorPicker.module.css +0 -1
  185. package/dist/esm/input/File.module.css +0 -1
  186. package/dist/esm/internal/Field.module.css +0 -1
  187. package/dist/types/input/Range.d.ts +0 -59
@@ -1,33 +1,43 @@
1
1
  'use client';
2
2
 
3
3
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
4
+ import { yupResolver } from '@hookform/resolvers/yup';
5
+ import { EmptyContent } from '@react-fabric/core';
4
6
  import { yup, isNil, isEmpty } from '@react-fabric/utilities';
5
7
  import { useMemo, Fragment } from 'react';
6
8
  import { FormField } from '../builder/FormField.js';
7
- import { jsx } from 'react/jsx-runtime';
9
+ import { DATA_TYPES } from '../types/schema.js';
10
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
11
 
9
12
  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; }
10
13
  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; }
11
14
  var makeYupField = function makeYupField(field) {
12
- var yupField = yup.string();
13
- if (field.datatype === "schema") {
15
+ var yupField = yup.string().trim();
16
+ if (field.datatype === DATA_TYPES.SCHEMA) {
14
17
  var child = Object.fromEntries(field.schema.map(function (field) {
15
18
  return [field.id, makeYupField(field)];
16
19
  }));
17
20
  yupField = yup.object(child);
18
21
  }
19
- if (field.datatype === "boolean") yupField = yup["boolean"]();
20
- if (field.datatype === "decimal" || field.datatype === "number" || field.datatype === "range") {
22
+ if (field.datatype === DATA_TYPES.BOOL) {
23
+ yupField = yup["boolean"]();
24
+ if (field.required) yupField = yupField.test({
25
+ test: function test(value) {
26
+ return !!value;
27
+ }
28
+ });
29
+ }
30
+ if (field.datatype === DATA_TYPES.NUMBER || field.datatype === DATA_TYPES.RANGE) {
21
31
  yupField = yup.number();
22
32
  !isNil(field.min) && (yupField = yupField.min(field.min));
23
33
  !isNil(field.max) && (yupField = yupField.max(field.max));
24
- if (field.datatype === "range") yupField = yup.array(yupField);
34
+ if (field.datatype === DATA_TYPES.RANGE) yupField = yup.array(yupField);
25
35
  }
26
- if (field.datatype === "string") {
27
- field.options && (yupField = yupField.oneOf(field.options));
36
+ if (field.datatype === DATA_TYPES.STRING) {
37
+ field.options && !field.allowCustom && (yupField = yupField.oneOf(field.options));
28
38
  field.regex && (yupField = yupField.matches(new RegExp(field.regex)));
29
39
  }
30
- if (field.datatype === "file") {
40
+ if (field.datatype === DATA_TYPES.FILE) {
31
41
  yupField = yup.object({
32
42
  filename: yup.string().required(),
33
43
  path: yup.string().required()
@@ -53,6 +63,36 @@ var makeYupField = function makeYupField(field) {
53
63
  }
54
64
  return yupField.label(field.label);
55
65
  };
66
+
67
+ /**
68
+ * useFormBuilder hook to create a form definition based on a schema.
69
+ * It generates a Yup validation schema and a form definition component.
70
+ *
71
+ * @param {FormSchema} schema - The schema defining the form fields.
72
+ * @param {Object} options - Optional parameters for the form builder.
73
+ * @returns An object containing the form definition and the Yup validation schema.
74
+ *
75
+ * @example
76
+ * ```jsx
77
+ * const { formDef, schemaDef } = useFormBuilder(schema, {
78
+ * prefix: "form",
79
+ * inline: true,
80
+ * fileUrl: (path) => `/files/${path}`,
81
+ * uploadHandler: async (file) => {
82
+ * // handle file upload
83
+ * },
84
+ * optionLists: {
85
+ * // define option lists for select fields
86
+ * }
87
+ * * });
88
+ * <FormBuilder
89
+ * schema={schemaDef}
90
+ * onSubmit={(data) => console.log(data)}
91
+ * >
92
+ * {formDef}
93
+ * </FormBuilder>
94
+ * ```
95
+ */
56
96
  var useFormBuilder = function useFormBuilder(schema) {
57
97
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
58
98
  var filteredSchema = useMemo(function () {
@@ -61,25 +101,34 @@ var useFormBuilder = function useFormBuilder(schema) {
61
101
  return !!schm.id;
62
102
  })) !== null && _schema$filter !== void 0 ? _schema$filter : [];
63
103
  }, [schema]);
64
- var schemaDef = yup.object(Object.fromEntries(filteredSchema.map(function (field) {
65
- return [field.id, makeYupField(field)];
66
- })));
67
- var formDef = /*#__PURE__*/jsx(Fragment, {
68
- children: filteredSchema.map(function (field, idx) {
104
+ var schemaDef = useMemo(function () {
105
+ return yup.object(Object.fromEntries(filteredSchema.map(function (field) {
106
+ return [field.id, makeYupField(field)];
107
+ })));
108
+ }, [filteredSchema]);
109
+ var resolver = useMemo(function () {
110
+ return yupResolver(schemaDef);
111
+ }, [schemaDef]);
112
+ var formDef = /*#__PURE__*/jsxs(Fragment, {
113
+ children: [filteredSchema.map(function (field, idx) {
69
114
  return /*#__PURE__*/jsx("div", {
70
115
  className: "mb-4",
71
- children: field.datatype === "schema" ? null : /*#__PURE__*/jsx(FormField, _objectSpread(_objectSpread({}, field), {}, {
116
+ children: field.datatype === DATA_TYPES.SCHEMA ? null : /*#__PURE__*/jsx(FormField, _objectSpread(_objectSpread({}, field), {}, {
72
117
  autoFocus: idx === 0,
73
118
  fileUrl: options.fileUrl,
119
+ optionLists: options.optionLists,
74
120
  uploadHandler: options.uploadHandler,
75
121
  inline: options.inline,
76
122
  prefix: options.prefix
77
123
  }))
78
124
  }, field.id);
79
- })
125
+ }), filteredSchema.length === 0 && /*#__PURE__*/jsx(EmptyContent, {
126
+ message: "No schema defined"
127
+ })]
80
128
  });
81
129
  return {
82
130
  formDef: formDef,
131
+ resolver: resolver,
83
132
  schemaDef: schemaDef
84
133
  };
85
134
  };
@@ -2,17 +2,18 @@
2
2
 
3
3
  var addArray = "اضافة عنصر";
4
4
  var password = {
5
- show: "عرض كلمة المرور",
6
- hide: "اخفاء كلمة المرور"
5
+ hide: "اخفاء كلمة المرور",
6
+ show: "عرض كلمة المرور"
7
7
  };
8
8
  var select = {
9
+ createOption: "إنشاء خيار جديد ل ",
9
10
  emptyList: "لا توجد خيارات متاحة",
10
- notFound: "لم يتم العثور على خيارات ل ",
11
- createOption: "إنشاء خيار جديد ل "
11
+ notFound: "لم يتم العثور على خيارات ل "
12
12
  };
13
13
  var yup = {
14
14
  arrayMax: "{{label}} حدد ما يصل {{max}} غرض",
15
15
  arrayMin: "{{label}} اختر على الأقل {{min}} غرض",
16
+ empty: "{{label}} يجب ألا يكون فارغًا",
16
17
  invalid: "{{label}} نوع بيانات غير صالح",
17
18
  invalidType: "{{label}} غير صالح",
18
19
  numberMax: "{{label}} الحد الأقصى {{max}}",
@@ -2,19 +2,19 @@
2
2
 
3
3
  var addArray = "Add Item";
4
4
  var password = {
5
- show: "Show password",
6
- hide: "Hide password"
5
+ hide: "Hide password",
6
+ show: "Show password"
7
7
  };
8
8
  var select = {
9
+ createOption: "Create new option for <0>{{query}}</0>",
9
10
  emptyList: "No options available",
10
- notFound: "No options found for <0>{{query}}</0>",
11
- createOption: "Create new option for <0>{{query}}</0>"
11
+ notFound: "No options found for <0>{{query}}</0>"
12
12
  };
13
13
  var yup = {
14
14
  arrayMax: "{{label}} must contain upto {{max}} item",
15
15
  arrayMin: "{{label}} must contain atleast {{min}} item",
16
- invalid: "{{label}} invalid",
17
16
  empty: "{{label}} must not be empty",
17
+ invalid: "{{label}} invalid",
18
18
  invalidType: "{{label}} invalid datatype",
19
19
  numberMax: "{{label}} maximum {{max}}",
20
20
  numberMin: "{{label}} minimum {{min}}",
package/dist/esm/index.js CHANGED
@@ -2,13 +2,17 @@
2
2
 
3
3
  import './i18n/index.js';
4
4
  export { Controller } from './form/Controller.js';
5
- export { Form } from './form/Form.js';
5
+ export { Form, useForm } from './form/Form.js';
6
+ export { SchemaEditor } from './builder/SchemaEditor.js';
6
7
  export { useFileUploader } from './hooks/useFileUploader.js';
7
8
  export { useFormBuilder } from './hooks/useFormBuilder.js';
9
+ export { DATA_TYPES, SCHEMA_CUSTOM_LIST } from './types/schema.js';
8
10
  export { ArrayInput } from './input/ArrayInput.js';
11
+ export { AvatarInput } from './input/AvatarInput.js';
9
12
  export { Checkbox } from './input/Checkbox.js';
10
13
  export { ColorInput } from './input/ColorInput.js';
11
14
  export { ColorPicker } from './input/ColorPicker.js';
15
+ export { DateInput } from './input/DateInput.js';
12
16
  export { Field } from './input/Field.js';
13
17
  export { FileInput } from './input/File.js';
14
18
  export { HiddenInput } from './input/Hidden.js';
@@ -17,7 +21,7 @@ export { Number } from './input/Number.js';
17
21
  export { Password } from './input/Password.js';
18
22
  export { Radio } from './input/Radio.js';
19
23
  export { RadioGroup } from './input/RadioGroup.js';
20
- export { Range } from './input/Range.js';
24
+ export { RangeSlider } from './input/RangeSlider.js';
21
25
  export { Search } from './input/Search.js';
22
26
  export { Slider } from './input/Slider.js';
23
27
  export { Switch } from './input/Switch.js';
@@ -1,33 +1,75 @@
1
1
  'use client';
2
2
 
3
3
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
4
+ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
4
5
  import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
5
6
  import { DndContext } from '@dnd-kit/core';
6
7
  import { SortableContext, useSortable } from '@dnd-kit/sortable';
7
- import { Icon, CoreIcons, Button, Tooltip } from '@react-fabric/core';
8
- import { isString } from '@react-fabric/utilities';
8
+ import { Icon, Tooltip, Button, cloneChildren } from '@react-fabric/core';
9
+ import { isFalse, isString } from '@react-fabric/utilities';
9
10
  import classNames from 'classnames';
10
- import { useMemo, useCallback, useImperativeHandle, Children, cloneElement } from 'react';
11
+ import { useState, useEffect, useMemo, useCallback, useImperativeHandle, cloneElement } from 'react';
11
12
  import { useFormContext, useFieldArray } from 'react-hook-form';
12
13
  import { useTranslation } from 'react-i18next';
13
14
  import { FieldWrapper } from '../internal/FieldWrapper.js';
14
- import classes from './ArrayInput.module.css';
15
15
  import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
16
16
  import { CSS } from '@dnd-kit/utilities';
17
17
  import { jsx, jsxs } from 'react/jsx-runtime';
18
18
 
19
- var _excluded = ["name", "children", "addLabel", "fixedList", "focusName", "onAdd", "arrayRef", "enableSorting", "disabled", "readOnly", "minItems"];
19
+ var _excluded = ["name", "children", "addLabel", "focusName", "buttonPosition", "onAdd", "onRemove", "onBeforeRemove", "canRemove", "arrayRef", "enableSorting", "disabled", "readOnly", "minItems", "maxItems"];
20
20
  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; }
21
21
  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; }
22
+ /**
23
+ * ArrayInput component for managing an array of items in a form.
24
+ * It allows adding, removing, and sorting items within the array.
25
+ * It integrates with react-hook-form for form state management and validation.
26
+ * It supports fixed-length lists, custom add/remove handlers, and can display validation errors.
27
+ * It also provides options for inline display and custom button positioning.
28
+ *
29
+ * It uses the `useFieldArray` hook from `react-hook-form` to manage the array state and provides a simple interface for adding and removing items.
30
+ *
31
+ * It also supports drag-and-drop sorting using `@dnd-kit/core` and `@dnd-kit/sortable` for a better user experience when reordering items.
32
+ *
33
+ * @param {ArrayInputProps<T>} props - The properties for the ArrayInput component.
34
+ * @returns {JSX.Element} The rendered ArrayInput component.
35
+ *
36
+ * @example
37
+ * ```jsx
38
+ * <ArrayInput
39
+ * name="items"
40
+ * label="Items"
41
+ * addLabel="Add Item"
42
+ * onAdd={() => ({ name: "", value: "" })}
43
+ * onRemove={(item, index) => console.log("Removed item:", item, "at index:", index)}
44
+ * onBeforeRemove={(item, index) => confirm(`Are you sure you want to remove item at index ${index}?`)}
45
+ * canRemove={({ item, index, lastItem }) => !lastItem} // Prevent removing the last item
46
+ * >
47
+ * {({ index, name }) => (
48
+ * <Input
49
+ * name={name}
50
+ * label={`Item ${index + 1}`}
51
+ * placeholder="Enter item value"
52
+ * required={index === 0} // Make the first item required
53
+ * />
54
+ * )}
55
+ * </ArrayInput>
56
+ * ```
57
+ *
58
+ * @see {@link https://react-hook-form.com/api/usefieldarray} for more details on `useFieldArray`.
59
+ * @see {@link https://react-dnd.github.io/react-dnd/about} for more details on DnD context and sorting.
60
+ */
22
61
  var ArrayInput = function ArrayInput(_ref) {
23
- var _error$values$label, _error$values, _error$values2;
24
62
  var name = _ref.name,
25
63
  children = _ref.children,
26
64
  addLabel = _ref.addLabel,
27
- fixedList = _ref.fixedList,
28
65
  _ref$focusName = _ref.focusName,
29
66
  focusName = _ref$focusName === void 0 ? "" : _ref$focusName,
67
+ _ref$buttonPosition = _ref.buttonPosition,
68
+ buttonPosition = _ref$buttonPosition === void 0 ? "bottom" : _ref$buttonPosition,
30
69
  onAdd = _ref.onAdd,
70
+ onRemove = _ref.onRemove,
71
+ onBeforeRemove = _ref.onBeforeRemove,
72
+ canRemove = _ref.canRemove,
31
73
  arrayRef = _ref.arrayRef,
32
74
  enableSorting = _ref.enableSorting,
33
75
  _ref$disabled = _ref.disabled,
@@ -36,6 +78,8 @@ var ArrayInput = function ArrayInput(_ref) {
36
78
  readOnly = _ref$readOnly === void 0 ? false : _ref$readOnly,
37
79
  _ref$minItems = _ref.minItems,
38
80
  minItems = _ref$minItems === void 0 ? 0 : _ref$minItems,
81
+ _ref$maxItems = _ref.maxItems,
82
+ maxItems = _ref$maxItems === void 0 ? Number.MAX_SAFE_INTEGER : _ref$maxItems,
39
83
  rest = _objectWithoutProperties(_ref, _excluded);
40
84
  var _useTranslation = useTranslation("form"),
41
85
  t = _useTranslation.t;
@@ -43,34 +87,70 @@ var ArrayInput = function ArrayInput(_ref) {
43
87
  if (!(form !== null && form !== void 0 && form.control)) throw new Error("ArrayInput must be contained within a Form element");
44
88
  var _useFieldArray = useFieldArray({
45
89
  name: name,
90
+ keyName: "__ID__",
46
91
  control: form.control
47
92
  }),
48
93
  fields = _useFieldArray.fields,
49
94
  append = _useFieldArray.append,
50
95
  remove = _useFieldArray.remove,
51
96
  move = _useFieldArray.move;
97
+ var _useState = useState([]),
98
+ _useState2 = _slicedToArray(_useState, 2),
99
+ initialList = _useState2[0],
100
+ setInitialList = _useState2[1];
101
+ useEffect(function () {
102
+ setInitialList(fields.map(function (f) {
103
+ return f.__ID__;
104
+ }));
105
+ }, []);
52
106
  var error = useMemo(function () {
53
107
  var _form$formState$error, _form$formState$error2, _form$formState$error3;
54
108
  return (_form$formState$error = (_form$formState$error2 = form.formState.errors[name]) === null || _form$formState$error2 === void 0 ? void 0 : _form$formState$error2.message) !== null && _form$formState$error !== void 0 ? _form$formState$error : (_form$formState$error3 = form.formState.errors[name]) === null || _form$formState$error3 === void 0 || (_form$formState$error3 = _form$formState$error3.root) === null || _form$formState$error3 === void 0 ? void 0 : _form$formState$error3.message;
55
109
  }, [form.formState.errors]);
110
+ var removeCheck = useCallback(function (item, index) {
111
+ if (canRemove === false) return false;
112
+ if (canRemove === "newonly") {
113
+ return !initialList.includes(item.__ID__);
114
+ }
115
+ if (typeof canRemove === "function") {
116
+ return canRemove({
117
+ item: item,
118
+ index: index,
119
+ lastItem: index + 1 === fields.length
120
+ });
121
+ }
122
+ return true;
123
+ }, [canRemove, initialList, fields]);
56
124
  var handleAdd = useCallback(function (item) {
125
+ if (!item) return;
57
126
  append(item);
58
127
  setTimeout(function () {
59
128
  form.setFocus("".concat(name, ".").concat(fields.length).concat(focusName ? "." + focusName : ""));
60
129
  }, 100);
61
130
  }, [name, fields, focusName]);
131
+ var handleRemove = useCallback(function (item, index) {
132
+ var ret = onBeforeRemove === null || onBeforeRemove === void 0 ? void 0 : onBeforeRemove(item, index);
133
+ void Promise.resolve(ret).then(function (b) {
134
+ if (!isFalse(b)) {
135
+ remove(index);
136
+ onRemove === null || onRemove === void 0 || onRemove(item, index);
137
+ }
138
+ });
139
+ }, [remove, onRemove, onBeforeRemove]);
62
140
  useImperativeHandle(arrayRef, function () {
63
141
  return {
64
142
  addItem: handleAdd,
65
143
  removeItem: remove
66
144
  };
67
145
  });
68
- var Wrapper = useCallback(function (_ref2) {
146
+ var Wrapper = useCallback(
147
+ // eslint-disable-next-line @typescript-eslint/promise-function-async
148
+ function (_ref2) {
69
149
  var children = _ref2.children;
70
150
  if (enableSorting) {
71
151
  // pass id list to dnd context
72
152
  var idMap = fields.map(function (item) {
73
- return item.id;
153
+ return item.__ID__;
74
154
  });
75
155
  var handleDragEnd = function handleDragEnd(e) {
76
156
  if (e.over && e.active.id !== e.over.id) {
@@ -116,7 +196,7 @@ var ArrayInput = function ArrayInput(_ref) {
116
196
  },
117
197
  children: [/*#__PURE__*/jsx(Icon, _objectSpread(_objectSpread({
118
198
  className: isDragging ? "cursor-grabbing" : "cursor-grab",
119
- icon: CoreIcons.dragHandle
199
+ icon: "icon-[mdi--drag-vertical]"
120
200
  }, attributes), listeners)), children]
121
201
  });
122
202
  }
@@ -127,18 +207,47 @@ var ArrayInput = function ArrayInput(_ref) {
127
207
  }, [enableSorting]);
128
208
  // @ts-expect-error ignore
129
209
  SortableItem.displayName = "SortableItem";
210
+ var addButton = useMemo(function () {
211
+ var _error$values$label, _error$values, _error$values2;
212
+ return /*#__PURE__*/jsx("div", {
213
+ className: "flex justify-end",
214
+ children: /*#__PURE__*/jsx(Tooltip, {
215
+ color: "danger-200",
216
+ content: isString(error) ? "".concat(error) : t(error === null || error === void 0 ? void 0 : error.key, error !== null && error !== void 0 && error.values ? _objectSpread(_objectSpread({}, error === null || error === void 0 ? void 0 : error.values), {}, {
217
+ label: t((_error$values$label = (_error$values = error.values) === null || _error$values === void 0 ? void 0 : _error$values.label) !== null && _error$values$label !== void 0 ? _error$values$label : "form:badkey", (_error$values2 = error.values) === null || _error$values2 === void 0 ? void 0 : _error$values2.path)
218
+ }) : {}),
219
+ children: /*#__PURE__*/jsx(Button, {
220
+ size: "sm",
221
+ "aria-label": "Add item",
222
+ icon: "icon-[mdi--plus-circle-outline]",
223
+ onClick: function onClick() {
224
+ return handleAdd(onAdd === null || onAdd === void 0 ? void 0 : onAdd());
225
+ },
226
+ "data-invalid": !!error,
227
+ disabled: !!disabled || readOnly || fields.length > maxItems,
228
+ className: classNames("fabric-addButton", canRemove !== false && "me-10"),
229
+ children: addLabel !== null && addLabel !== void 0 ? addLabel : t("form:addArray")
230
+ })
231
+ })
232
+ });
233
+ }, [error, fields, handleAdd, canRemove, disabled, readOnly, addLabel, maxItems]);
130
234
  return /*#__PURE__*/jsxs("div", {
131
- className: classes.arrayInput,
235
+ className: "fabric-arrayInput",
132
236
  children: [/*#__PURE__*/jsx(FieldWrapper, _objectSpread(_objectSpread({}, rest), {}, {
237
+ appendLabel: /*#__PURE__*/jsx("div", {
238
+ className: "-me-2",
239
+ children: onAdd && buttonPosition !== "bottom" && addButton
240
+ }),
133
241
  children: /*#__PURE__*/jsx(Wrapper, {
134
242
  children: fields.map(function (item, index) {
135
243
  return /*#__PURE__*/jsxs(SortableItem, {
136
- id: item.id,
244
+ id: item.__ID__,
137
245
  className: "flex items-center flex-nowrap gap-2 mb-1",
138
246
  children: [typeof children === "function" ? children({
139
247
  index: index,
248
+ item: item,
140
249
  name: "".concat(name, ".").concat(index)
141
- }) : Children.map(children, function (child) {
250
+ }) : cloneChildren(children, function (child) {
142
251
  return /*#__PURE__*/cloneElement(child, Object.assign({
143
252
  disabled: disabled,
144
253
  readOnly: readOnly,
@@ -149,40 +258,21 @@ var ArrayInput = function ArrayInput(_ref) {
149
258
  required: undefined,
150
259
  appendLabel: undefined
151
260
  }));
152
- }), !fixedList && /*#__PURE__*/jsx(Button, {
261
+ }), canRemove !== false && /*#__PURE__*/jsx(Button, {
153
262
  "aria-label": "Remove item",
154
- icon: CoreIcons.remove,
263
+ icon: "icon-[mdi--minus-circle-outline]",
155
264
  color: "danger",
156
265
  variant: "link",
157
266
  className: "self-end",
158
- disabled: disabled || readOnly || fields.length <= minItems,
267
+ disabled: disabled || readOnly || fields.length <= minItems || !removeCheck(item, index),
159
268
  onClick: function onClick() {
160
- return remove(index);
269
+ return handleRemove(item, index);
161
270
  }
162
271
  })]
163
- }, item.id);
164
- })
165
- })
166
- })), !fixedList && onAdd && /*#__PURE__*/jsx("div", {
167
- className: "flex justify-end",
168
- children: /*#__PURE__*/jsx(Tooltip, {
169
- color: "danger",
170
- content: isString(error) ? "".concat(error) : t(error === null || error === void 0 ? void 0 : error.key, error !== null && error !== void 0 && error.values ? _objectSpread(_objectSpread({}, error === null || error === void 0 ? void 0 : error.values), {}, {
171
- label: t((_error$values$label = (_error$values = error.values) === null || _error$values === void 0 ? void 0 : _error$values.label) !== null && _error$values$label !== void 0 ? _error$values$label : "form:badkey", (_error$values2 = error.values) === null || _error$values2 === void 0 ? void 0 : _error$values2.path)
172
- }) : {}),
173
- children: /*#__PURE__*/jsx(Button, {
174
- "aria-label": "Add item",
175
- icon: CoreIcons.insert,
176
- onClick: function onClick() {
177
- return handleAdd(onAdd());
178
- },
179
- "data-invalid": !!error,
180
- disabled: !!disabled || readOnly,
181
- className: classNames(classes.addButton, "me-10"),
182
- children: addLabel !== null && addLabel !== void 0 ? addLabel : t("addArray")
272
+ }, item.__ID__);
183
273
  })
184
274
  })
185
- })]
275
+ })), onAdd && buttonPosition !== "top" && addButton]
186
276
  });
187
277
  };
188
278
 
@@ -6,19 +6,34 @@ import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator';
6
6
  import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
7
7
  import _regeneratorRuntime from '@babel/runtime/regenerator';
8
8
  import { Avatar, Icon, ProgressBar } from '@react-fabric/core';
9
+ import classNames from 'classnames';
9
10
  import { useState, useEffect } from 'react';
10
11
  import { useFileUploader } from '../hooks/useFileUploader.js';
11
12
  import { HiddenInput } from './Hidden.js';
12
13
  import { jsxs, jsx } from 'react/jsx-runtime';
13
14
 
14
- var _excluded = ["src", "size", "fileUrl", "uploadHandler"];
15
+ var _excluded = ["size", "avatarName", "avatarClassName", "value", "rounded", "defaultValue", "fallbackIcon", "variant", "fileUrl", "uploadHandler"];
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; }
18
+ /**
19
+ * Avatar input component for uploading and displaying user avatars.
20
+ * It allows users to select an image file, upload it, and display the avatar.
21
+ * It also provides a way to remove the uploaded file and shows upload progress.
22
+ *
23
+ * @param {Props} props - The properties for the AvatarInput component.
24
+ * @returns {JSX.Element} - The rendered AvatarInput component.
25
+ */
17
26
  var AvatarInput = function AvatarInput(_ref) {
18
27
  var _list$;
19
- var src = _ref.src,
20
- _ref$size = _ref.size,
28
+ var _ref$size = _ref.size,
21
29
  size = _ref$size === void 0 ? "6rem" : _ref$size,
30
+ avatarName = _ref.avatarName,
31
+ avatarClassName = _ref.avatarClassName,
32
+ value = _ref.value,
33
+ rounded = _ref.rounded,
34
+ defaultValue = _ref.defaultValue,
35
+ fallbackIcon = _ref.fallbackIcon,
36
+ variant = _ref.variant,
22
37
  fileUrl = _ref.fileUrl,
23
38
  uploadHandler = _ref.uploadHandler,
24
39
  rest = _objectWithoutProperties(_ref, _excluded);
@@ -40,7 +55,7 @@ var AvatarInput = function AvatarInput(_ref) {
40
55
  return function (_x, _x2) {
41
56
  return _ref2.apply(this, arguments);
42
57
  };
43
- }(), rest.value, false),
58
+ }(), value, false),
44
59
  files = _useFileUploader.files,
45
60
  list = _useFileUploader.list,
46
61
  upload = _useFileUploader.upload,
@@ -64,23 +79,29 @@ var AvatarInput = function AvatarInput(_ref) {
64
79
  reader.readAsDataURL(blob);
65
80
  }));
66
81
  } else {
67
- setBase64("");
82
+ var _ref3, _fileUrl;
83
+ setBase64((_ref3 = (_fileUrl = fileUrl === null || fileUrl === void 0 ? void 0 : fileUrl(defaultValue !== null && defaultValue !== void 0 ? defaultValue : "")) !== null && _fileUrl !== void 0 ? _fileUrl : defaultValue) !== null && _ref3 !== void 0 ? _ref3 : "");
68
84
  }
69
- }, [files, list]);
85
+ }, [files, list, defaultValue]);
70
86
  useEffect(function () {
71
- var _fileUrl;
72
- src && setBase64((_fileUrl = fileUrl === null || fileUrl === void 0 ? void 0 : fileUrl(src)) !== null && _fileUrl !== void 0 ? _fileUrl : src);
73
- }, [src]);
87
+ var _fileUrl2, _fileUrl3;
88
+ !value && defaultValue && setBase64((_fileUrl2 = fileUrl === null || fileUrl === void 0 ? void 0 : fileUrl(defaultValue)) !== null && _fileUrl2 !== void 0 ? _fileUrl2 : defaultValue);
89
+ value && setBase64((_fileUrl3 = fileUrl === null || fileUrl === void 0 ? void 0 : fileUrl(value)) !== null && _fileUrl3 !== void 0 ? _fileUrl3 : value);
90
+ }, [value, defaultValue]);
74
91
  return /*#__PURE__*/jsxs("div", {
75
- className: "flex flex-nowrap items-end",
92
+ className: "flex flex-nowrap items-end overflow-hidden",
76
93
  children: [/*#__PURE__*/jsxs("div", {
77
- className: "inline-block leading-none rounded-full relative outline overflow-hidden",
94
+ className: classNames("inline-block leading-none relative outline overflow-hidden", rounded && "rounded-full", !rounded && "rounded"),
78
95
  children: [/*#__PURE__*/jsx(Avatar, {
79
- name: "temp",
96
+ name: avatarName !== null && avatarName !== void 0 ? avatarName : "temp",
80
97
  size: size,
81
- avatar: base64
98
+ avatar: base64,
99
+ rounded: rounded,
100
+ variant: variant,
101
+ fallbackIcon: fallbackIcon,
102
+ className: avatarClassName
82
103
  }), /*#__PURE__*/jsxs("div", {
83
- className: "absolute inset-x-0 bottom-0 cursor-pointer bg-opacity-20 hover:bg-opacity-50 bg-black text-white text-xs text-center py-1",
104
+ className: "absolute inset-x-0 bottom-0 cursor-pointer opacity-50 bg-black/50 hover:opacity-90 text-white text-xs text-center py-1",
84
105
  children: [/*#__PURE__*/jsx("span", {
85
106
  children: "Edit"
86
107
  }), /*#__PURE__*/jsx("input", {
@@ -93,36 +114,35 @@ var AvatarInput = function AvatarInput(_ref) {
93
114
  })]
94
115
  })]
95
116
  }), /*#__PURE__*/jsx(HiddenInput, _objectSpread({
96
- hiddenValue: list === null || list === void 0 || (_list$ = list[0]) === null || _list$ === void 0 ? void 0 : _list$.path
117
+ hiddenValue: list === null || list === void 0 || (_list$ = list[0]) === null || _list$ === void 0 ? void 0 : _list$.path,
118
+ defaultValue: defaultValue
97
119
  }, rest)), files.map(function (file, idx) {
98
120
  return /*#__PURE__*/jsxs("div", {
99
- className: "px-2 py-1 flex-1",
121
+ className: "px-2 py-1 flex-1 overflow-hidden",
100
122
  children: [/*#__PURE__*/jsxs("div", {
101
123
  className: "flex flex-nowrap gap-1 items-center",
102
- children: [/*#__PURE__*/jsx("div", {
103
- className: "flex-initial truncate pe-2",
104
- children: file.filename
105
- }), file.error && /*#__PURE__*/jsx("div", {
124
+ children: [file.error && /*#__PURE__*/jsx("div", {
106
125
  className: "flex-1 truncate px-2",
107
126
  children: /*#__PURE__*/jsx("span", {
108
127
  className: "text-danger-600",
109
128
  children: file.error
110
129
  })
111
130
  }), file.progress && /*#__PURE__*/jsx(Icon, {
112
- icon: "mdi mdi-stop-circle",
131
+ icon: "icon-[mdi--stop]",
113
132
  bg: "danger",
114
133
  color: "white",
115
134
  size: "sm",
116
- className: "p-[2px]",
135
+ className: "p-0.5 flex-content",
117
136
  "aria-label": "abort",
118
137
  onClick: function onClick() {
119
138
  var _file$abort;
120
139
  return (_file$abort = file.abort) === null || _file$abort === void 0 ? void 0 : _file$abort.call(file);
121
140
  }
122
141
  }), !file.progress && /*#__PURE__*/jsx(Icon, {
123
- icon: "mdi mdi-trash-can",
142
+ icon: "icon-[mdi--trash-can-outline]",
124
143
  color: "danger",
125
144
  size: "sm",
145
+ className: "flex-content",
126
146
  "aria-label": "remove",
127
147
  onClick: function onClick() {
128
148
  return remove(file.key);