@donotdev/crud 0.0.6 → 0.0.7

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 (304) hide show
  1. package/README.md +18 -2
  2. package/dist/CrudService.d.ts +91 -8
  3. package/dist/CrudService.d.ts.map +1 -1
  4. package/dist/CrudService.js +1 -1
  5. package/dist/CrudStore.d.ts +45 -2
  6. package/dist/CrudStore.d.ts.map +1 -1
  7. package/dist/CrudStore.js +1 -1
  8. package/dist/FieldRegistry.d.ts +56 -20
  9. package/dist/FieldRegistry.d.ts.map +1 -1
  10. package/dist/FieldRegistry.js +1 -1
  11. package/dist/adapters/FirestoreAdapter.d.ts +4 -4
  12. package/dist/adapters/FirestoreAdapter.d.ts.map +1 -1
  13. package/dist/adapters/FirestoreAdapter.js +1 -1
  14. package/dist/adapters/FunctionsAdapter.d.ts +3 -2
  15. package/dist/adapters/FunctionsAdapter.d.ts.map +1 -1
  16. package/dist/adapters/FunctionsAdapter.js +1 -1
  17. package/dist/builtinFieldTypes.d.ts +4 -0
  18. package/dist/builtinFieldTypes.d.ts.map +1 -1
  19. package/dist/builtinFieldTypes.js +1 -1
  20. package/dist/components/CrudButton.d.ts +1 -1
  21. package/dist/components/CrudButton.d.ts.map +1 -1
  22. package/dist/components/CrudButton.js +1 -1
  23. package/dist/components/DisplayFieldRenderer.d.ts +15 -11
  24. package/dist/components/DisplayFieldRenderer.d.ts.map +1 -1
  25. package/dist/components/DisplayFieldRenderer.js +1 -1
  26. package/dist/components/EntityCardList.d.ts +27 -0
  27. package/dist/components/EntityCardList.d.ts.map +1 -0
  28. package/dist/components/EntityCardList.js +1 -0
  29. package/dist/components/EntityDisplayRenderer.d.ts +43 -0
  30. package/dist/components/EntityDisplayRenderer.d.ts.map +1 -0
  31. package/dist/components/EntityDisplayRenderer.js +1 -0
  32. package/dist/components/EntityFormRenderer.d.ts +21 -26
  33. package/dist/components/EntityFormRenderer.d.ts.map +1 -1
  34. package/dist/components/EntityFormRenderer.js +1 -5
  35. package/dist/components/EntityList.d.ts +24 -0
  36. package/dist/components/EntityList.d.ts.map +1 -0
  37. package/dist/components/EntityList.js +1 -0
  38. package/dist/components/FormFieldRenderer.d.ts +3 -10
  39. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  40. package/dist/components/FormFieldRenderer.js +1 -1
  41. package/dist/components/FormLayout.d.ts +1 -9
  42. package/dist/components/FormLayout.d.ts.map +1 -1
  43. package/dist/components/controlled/complex/ControlledAddressField.d.ts +8 -0
  44. package/dist/components/controlled/complex/ControlledAddressField.d.ts.map +1 -0
  45. package/dist/components/controlled/complex/ControlledAddressField.js +1 -0
  46. package/dist/components/controlled/complex/ControlledDateField.d.ts +8 -0
  47. package/dist/components/controlled/complex/ControlledDateField.d.ts.map +1 -0
  48. package/dist/components/controlled/complex/ControlledDateField.js +1 -0
  49. package/dist/components/controlled/complex/ControlledGeoPointField.d.ts +8 -0
  50. package/dist/components/controlled/complex/ControlledGeoPointField.d.ts.map +1 -0
  51. package/dist/components/controlled/complex/ControlledGeoPointField.js +1 -0
  52. package/dist/components/controlled/complex/ControlledMapField.d.ts +8 -0
  53. package/dist/components/controlled/complex/ControlledMapField.d.ts.map +1 -0
  54. package/dist/components/controlled/complex/ControlledMapField.js +1 -0
  55. package/dist/components/controlled/complex/ControlledMultiInputField.d.ts +8 -0
  56. package/dist/components/controlled/complex/ControlledMultiInputField.d.ts.map +1 -0
  57. package/dist/components/controlled/complex/ControlledMultiInputField.js +1 -0
  58. package/dist/components/controlled/complex/ControlledRichTextField.d.ts +8 -0
  59. package/dist/components/controlled/complex/ControlledRichTextField.d.ts.map +1 -0
  60. package/dist/components/controlled/complex/ControlledRichTextField.js +1 -0
  61. package/dist/components/controlled/complex/ControlledTimestampField.d.ts +8 -0
  62. package/dist/components/controlled/complex/ControlledTimestampField.d.ts.map +1 -0
  63. package/dist/components/controlled/complex/ControlledTimestampField.js +1 -0
  64. package/dist/components/controlled/complex/index.d.ts +8 -0
  65. package/dist/components/controlled/complex/index.d.ts.map +1 -0
  66. package/dist/components/controlled/complex/index.js +1 -0
  67. package/dist/components/controlled/file/ControlledDocumentField.d.ts +8 -0
  68. package/dist/components/controlled/file/ControlledDocumentField.d.ts.map +1 -0
  69. package/dist/components/controlled/file/ControlledDocumentField.js +1 -0
  70. package/dist/components/controlled/file/ControlledFileField.d.ts +8 -0
  71. package/dist/components/controlled/file/ControlledFileField.d.ts.map +1 -0
  72. package/dist/components/controlled/file/ControlledFileField.js +1 -0
  73. package/dist/components/controlled/file/ControlledImageField.d.ts +8 -0
  74. package/dist/components/controlled/file/ControlledImageField.d.ts.map +1 -0
  75. package/dist/components/controlled/file/ControlledImageField.js +1 -0
  76. package/dist/components/controlled/file/ControlledMultiDocumentField.d.ts +8 -0
  77. package/dist/components/controlled/file/ControlledMultiDocumentField.d.ts.map +1 -0
  78. package/dist/components/controlled/file/ControlledMultiDocumentField.js +1 -0
  79. package/dist/components/controlled/file/ControlledMultiFileField.d.ts +8 -0
  80. package/dist/components/controlled/file/ControlledMultiFileField.d.ts.map +1 -0
  81. package/dist/components/controlled/file/ControlledMultiFileField.js +1 -0
  82. package/dist/components/controlled/file/ControlledMultiImageField.d.ts +8 -0
  83. package/dist/components/controlled/file/ControlledMultiImageField.d.ts.map +1 -0
  84. package/dist/components/controlled/file/ControlledMultiImageField.js +1 -0
  85. package/dist/components/controlled/file/index.d.ts +7 -0
  86. package/dist/components/controlled/file/index.d.ts.map +1 -0
  87. package/dist/components/controlled/file/index.js +1 -0
  88. package/dist/components/controlled/index.d.ts +12 -0
  89. package/dist/components/controlled/index.d.ts.map +1 -0
  90. package/dist/components/controlled/index.js +1 -0
  91. package/dist/components/controlled/input/ControlledCheckboxField.d.ts +8 -0
  92. package/dist/components/controlled/input/ControlledCheckboxField.d.ts.map +1 -0
  93. package/dist/components/controlled/input/ControlledCheckboxField.js +1 -0
  94. package/dist/components/controlled/input/ControlledNumberField.d.ts +8 -0
  95. package/dist/components/controlled/input/ControlledNumberField.d.ts.map +1 -0
  96. package/dist/components/controlled/input/ControlledNumberField.js +1 -0
  97. package/dist/components/controlled/input/ControlledPasswordField.d.ts +8 -0
  98. package/dist/components/controlled/input/ControlledPasswordField.d.ts.map +1 -0
  99. package/dist/components/controlled/input/ControlledPasswordField.js +1 -0
  100. package/dist/components/controlled/input/ControlledPhoneField.d.ts +8 -0
  101. package/dist/components/controlled/input/ControlledPhoneField.d.ts.map +1 -0
  102. package/dist/components/controlled/input/ControlledPhoneField.js +1 -0
  103. package/dist/components/controlled/input/ControlledRangeField.d.ts +8 -0
  104. package/dist/components/controlled/input/ControlledRangeField.d.ts.map +1 -0
  105. package/dist/components/controlled/input/ControlledRangeField.js +1 -0
  106. package/dist/components/controlled/input/ControlledSwitchField.d.ts +8 -0
  107. package/dist/components/controlled/input/ControlledSwitchField.d.ts.map +1 -0
  108. package/dist/components/controlled/input/ControlledSwitchField.js +1 -0
  109. package/dist/components/controlled/input/ControlledTextField.d.ts +8 -0
  110. package/dist/components/controlled/input/ControlledTextField.d.ts.map +1 -0
  111. package/dist/components/controlled/input/ControlledTextField.js +1 -0
  112. package/dist/components/controlled/input/ControlledTextareaField.d.ts +8 -0
  113. package/dist/components/controlled/input/ControlledTextareaField.d.ts.map +1 -0
  114. package/dist/components/controlled/input/ControlledTextareaField.js +1 -0
  115. package/dist/components/controlled/input/index.d.ts +9 -0
  116. package/dist/components/controlled/input/index.d.ts.map +1 -0
  117. package/dist/components/controlled/input/index.js +1 -0
  118. package/dist/components/controlled/select/ControlledComboboxField.d.ts +9 -0
  119. package/dist/components/controlled/select/ControlledComboboxField.d.ts.map +1 -0
  120. package/dist/components/controlled/select/ControlledComboboxField.js +1 -0
  121. package/dist/components/controlled/select/ControlledDropdownField.d.ts +9 -0
  122. package/dist/components/controlled/select/ControlledDropdownField.d.ts.map +1 -0
  123. package/dist/components/controlled/select/ControlledDropdownField.js +1 -0
  124. package/dist/components/controlled/select/ControlledMultiDropdownField.d.ts +9 -0
  125. package/dist/components/controlled/select/ControlledMultiDropdownField.d.ts.map +1 -0
  126. package/dist/components/controlled/select/ControlledMultiDropdownField.js +1 -0
  127. package/dist/components/controlled/select/ControlledRadioField.d.ts +9 -0
  128. package/dist/components/controlled/select/ControlledRadioField.d.ts.map +1 -0
  129. package/dist/components/controlled/select/ControlledRadioField.js +1 -0
  130. package/dist/components/controlled/select/index.d.ts +5 -0
  131. package/dist/components/controlled/select/index.d.ts.map +1 -0
  132. package/dist/components/controlled/select/index.js +1 -0
  133. package/dist/components/controlled/types.d.ts +23 -0
  134. package/dist/components/controlled/types.d.ts.map +1 -0
  135. package/dist/components/controlled/types.js +1 -0
  136. package/dist/components/form/fields/AddressFieldComponent.d.ts.map +1 -1
  137. package/dist/components/form/fields/AddressFieldComponent.js +1 -1
  138. package/dist/components/form/fields/AvatarFieldComponent.d.ts +2 -2
  139. package/dist/components/form/fields/BadgeFieldComponent.d.ts +2 -2
  140. package/dist/components/form/fields/ButtonFieldComponent.d.ts +1 -9
  141. package/dist/components/form/fields/ButtonFieldComponent.d.ts.map +1 -1
  142. package/dist/components/form/fields/ButtonFieldComponent.js +1 -1
  143. package/dist/components/form/fields/ComboboxComponent.d.ts.map +1 -1
  144. package/dist/components/form/fields/CurrencyFieldComponent.d.ts +1 -9
  145. package/dist/components/form/fields/CurrencyFieldComponent.d.ts.map +1 -1
  146. package/dist/components/form/fields/CurrencyFieldComponent.js +1 -1
  147. package/dist/components/form/fields/DateFieldComponent.d.ts.map +1 -1
  148. package/dist/components/form/fields/DateFieldComponent.js +1 -1
  149. package/dist/components/form/fields/DocumentFieldComponent.d.ts +47 -0
  150. package/dist/components/form/fields/DocumentFieldComponent.d.ts.map +1 -0
  151. package/dist/components/form/fields/DocumentFieldComponent.js +1 -0
  152. package/dist/components/form/fields/DropdownComponent.d.ts.map +1 -1
  153. package/dist/components/form/fields/DropdownComponent.js +1 -1
  154. package/dist/components/form/fields/FileFieldComponent.d.ts +31 -15
  155. package/dist/components/form/fields/FileFieldComponent.d.ts.map +1 -1
  156. package/dist/components/form/fields/FileFieldComponent.js +1 -1
  157. package/dist/components/form/fields/GeoPointFieldComponent.d.ts.map +1 -1
  158. package/dist/components/form/fields/GeoPointFieldComponent.js +1 -1
  159. package/dist/components/form/fields/HiddenFieldComponent.d.ts +1 -1
  160. package/dist/components/form/fields/HiddenFieldComponent.d.ts.map +1 -1
  161. package/dist/components/form/fields/HiddenFieldComponent.js +1 -1
  162. package/dist/components/form/fields/ImageFieldComponent.d.ts +8 -14
  163. package/dist/components/form/fields/ImageFieldComponent.d.ts.map +1 -1
  164. package/dist/components/form/fields/ImageFieldComponent.js +1 -1
  165. package/dist/components/form/fields/MapFieldComponent.d.ts.map +1 -1
  166. package/dist/components/form/fields/MapFieldComponent.js +1 -1
  167. package/dist/components/form/fields/MultiDropdownComponent.js +1 -1
  168. package/dist/components/form/fields/MultiInputTextFieldComponent.d.ts +1 -9
  169. package/dist/components/form/fields/MultiInputTextFieldComponent.d.ts.map +1 -1
  170. package/dist/components/form/fields/MultiInputTextFieldComponent.js +1 -1
  171. package/dist/components/form/fields/NumberFieldComponent.d.ts +2 -0
  172. package/dist/components/form/fields/NumberFieldComponent.d.ts.map +1 -1
  173. package/dist/components/form/fields/NumberFieldComponent.js +1 -1
  174. package/dist/components/form/fields/PasswordFieldComponent.d.ts +1 -9
  175. package/dist/components/form/fields/PasswordFieldComponent.d.ts.map +1 -1
  176. package/dist/components/form/fields/PhoneNumberComponent.d.ts +1 -9
  177. package/dist/components/form/fields/PhoneNumberComponent.d.ts.map +1 -1
  178. package/dist/components/form/fields/PhoneNumberComponent.js +1 -1
  179. package/dist/components/form/fields/RadioFieldComponent.d.ts +1 -9
  180. package/dist/components/form/fields/RadioFieldComponent.d.ts.map +1 -1
  181. package/dist/components/form/fields/ReferenceFieldComponent.d.ts +33 -12
  182. package/dist/components/form/fields/ReferenceFieldComponent.d.ts.map +1 -1
  183. package/dist/components/form/fields/ReferenceFieldComponent.js +1 -1
  184. package/dist/components/form/fields/RichTextComponent.d.ts +32 -0
  185. package/dist/components/form/fields/RichTextComponent.d.ts.map +1 -0
  186. package/dist/components/form/fields/RichTextComponent.js +1 -0
  187. package/dist/components/form/fields/SwitchFieldComponent.d.ts.map +1 -1
  188. package/dist/components/form/fields/TextAreaComponent.d.ts +1 -9
  189. package/dist/components/form/fields/TextAreaComponent.d.ts.map +1 -1
  190. package/dist/components/form/fields/TextAreaComponent.js +1 -1
  191. package/dist/components/form/fields/TextFieldComponent.d.ts +1 -9
  192. package/dist/components/form/fields/TextFieldComponent.d.ts.map +1 -1
  193. package/dist/components/form/fields/index.d.ts +4 -2
  194. package/dist/components/form/fields/index.d.ts.map +1 -1
  195. package/dist/components/form/fields/index.js +1 -1
  196. package/dist/components/form/fields/internal/TiptapEditor.d.ts +13 -0
  197. package/dist/components/form/fields/internal/TiptapEditor.d.ts.map +1 -0
  198. package/dist/components/form/fields/internal/TiptapEditor.js +52 -0
  199. package/dist/components/form/index.d.ts +10 -0
  200. package/dist/components/form/index.d.ts.map +1 -0
  201. package/dist/components/form/index.js +1 -0
  202. package/dist/components/form/internal/ImageViewerDialog.d.ts +1 -1
  203. package/dist/components/form/internal/ImageViewerDialog.d.ts.map +1 -1
  204. package/dist/components/index.d.ts +8 -2
  205. package/dist/components/index.d.ts.map +1 -1
  206. package/dist/components/index.js +1 -1
  207. package/dist/contexts/UploadContext.d.ts +16 -0
  208. package/dist/contexts/UploadContext.d.ts.map +1 -0
  209. package/dist/contexts/UploadContext.js +1 -0
  210. package/dist/contexts/index.d.ts +3 -0
  211. package/dist/contexts/index.d.ts.map +1 -0
  212. package/dist/contexts/index.js +1 -0
  213. package/dist/forms/hooks/index.d.ts +2 -0
  214. package/dist/forms/hooks/index.d.ts.map +1 -1
  215. package/dist/forms/hooks/index.js +1 -1
  216. package/dist/forms/hooks/useController.d.ts +29 -0
  217. package/dist/forms/hooks/useController.d.ts.map +1 -0
  218. package/dist/forms/hooks/useController.js +1 -0
  219. package/dist/forms/hooks/useEntityField.d.ts.map +1 -1
  220. package/dist/forms/hooks/useEntityField.js +1 -1
  221. package/dist/forms/hooks/useEntityForm.d.ts +8 -76
  222. package/dist/forms/hooks/useEntityForm.d.ts.map +1 -1
  223. package/dist/forms/hooks/useEntityForm.js +1 -1
  224. package/dist/forms/index.d.ts +6 -4
  225. package/dist/forms/index.d.ts.map +1 -1
  226. package/dist/forms/index.js +1 -1
  227. package/dist/forms/types.d.ts +31 -5
  228. package/dist/forms/types.d.ts.map +1 -1
  229. package/dist/forms/utils/getFieldsForOperation.d.ts +5 -5
  230. package/dist/forms/utils/getFieldsForOperation.d.ts.map +1 -1
  231. package/dist/forms/utils/getFieldsForOperation.js +1 -1
  232. package/dist/forms/utils/index.d.ts +9 -5
  233. package/dist/forms/utils/index.d.ts.map +1 -1
  234. package/dist/forms/utils/index.js +1 -1
  235. package/dist/forms/utils/isFieldEditable.d.ts +0 -8
  236. package/dist/forms/utils/isFieldEditable.d.ts.map +1 -1
  237. package/dist/forms/utils/optionHelpers.d.ts +54 -0
  238. package/dist/forms/utils/optionHelpers.d.ts.map +1 -0
  239. package/dist/forms/utils/optionHelpers.js +1 -0
  240. package/dist/forms/utils/translateFieldLabel.d.ts +70 -0
  241. package/dist/forms/utils/translateFieldLabel.d.ts.map +1 -0
  242. package/dist/forms/utils/translateFieldLabel.js +1 -0
  243. package/dist/forms/utils/validateEntity.d.ts +5 -2
  244. package/dist/forms/utils/validateEntity.d.ts.map +1 -1
  245. package/dist/forms/utils/validateEntity.js +1 -1
  246. package/dist/hooks/index.d.ts +3 -0
  247. package/dist/hooks/index.d.ts.map +1 -0
  248. package/dist/hooks/index.js +1 -0
  249. package/dist/hooks/useFileUpload.d.ts +67 -0
  250. package/dist/hooks/useFileUpload.d.ts.map +1 -0
  251. package/dist/hooks/useFileUpload.js +1 -0
  252. package/dist/index.d.ts +15 -5
  253. package/dist/index.d.ts.map +1 -1
  254. package/dist/index.js +1 -1
  255. package/dist/stores/FormStore.d.ts +78 -0
  256. package/dist/stores/FormStore.d.ts.map +1 -0
  257. package/dist/stores/FormStore.js +1 -0
  258. package/dist/stores/UploadStore.d.ts +105 -0
  259. package/dist/stores/UploadStore.d.ts.map +1 -0
  260. package/dist/stores/UploadStore.js +1 -0
  261. package/dist/stores/index.d.ts +11 -0
  262. package/dist/stores/index.d.ts.map +1 -0
  263. package/dist/stores/index.js +1 -0
  264. package/dist/tsconfig.tsbuildinfo +1 -1
  265. package/dist/useCrud.d.ts +32 -74
  266. package/dist/useCrud.d.ts.map +1 -1
  267. package/dist/useCrud.js +1 -1
  268. package/dist/useCrudCardList.d.ts +62 -0
  269. package/dist/useCrudCardList.d.ts.map +1 -0
  270. package/dist/useCrudCardList.js +1 -0
  271. package/dist/useCrudList.d.ts +61 -0
  272. package/dist/useCrudList.d.ts.map +1 -0
  273. package/dist/useCrudList.js +1 -0
  274. package/dist/utils/fileStorage.d.ts +58 -0
  275. package/dist/utils/fileStorage.d.ts.map +1 -0
  276. package/dist/utils/fileStorage.js +1 -0
  277. package/dist/utils/imageProcessing.d.ts +1 -1
  278. package/dist/utils/imageProcessing.d.ts.map +1 -1
  279. package/dist/utils/imageProcessing.js +1 -1
  280. package/dist/utils/imageStorage.d.ts +1 -10
  281. package/dist/utils/imageStorage.d.ts.map +1 -1
  282. package/dist/utils/imageStorage.js +1 -1
  283. package/dist/utils/mergeWithOptimistic.d.ts +27 -0
  284. package/dist/utils/mergeWithOptimistic.d.ts.map +1 -0
  285. package/dist/utils/mergeWithOptimistic.js +1 -0
  286. package/dist/utils/uploadValidation.d.ts +37 -0
  287. package/dist/utils/uploadValidation.d.ts.map +1 -0
  288. package/dist/utils/uploadValidation.js +1 -0
  289. package/package.json +22 -5
  290. package/dist/components/ControlledFields.d.ts +0 -49
  291. package/dist/components/ControlledFields.d.ts.map +0 -1
  292. package/dist/components/ControlledFields.js +0 -1
  293. package/dist/context/FormUploadContext.d.ts +0 -36
  294. package/dist/context/FormUploadContext.d.ts.map +0 -1
  295. package/dist/context/FormUploadContext.js +0 -1
  296. package/dist/context/index.d.ts +0 -2
  297. package/dist/context/index.d.ts.map +0 -1
  298. package/dist/context/index.js +0 -1
  299. package/dist/forms/utils/createEntitySchema.d.ts +0 -53
  300. package/dist/forms/utils/createEntitySchema.d.ts.map +0 -1
  301. package/dist/forms/utils/createEntitySchema.js +0 -1
  302. package/dist/forms/utils/normalizeToFieldConfig.d.ts +0 -47
  303. package/dist/forms/utils/normalizeToFieldConfig.d.ts.map +0 -1
  304. package/dist/forms/utils/normalizeToFieldConfig.js +0 -1
@@ -3,87 +3,19 @@ import type { UseEntityFormOptions, EntityFormReturn } from '../types';
3
3
  /**
4
4
  * Creates a type-safe form instance from an entity definition.
5
5
  *
6
- * Automatically configures React Hook Form with:
7
- * - Pre-filtered fields based on operation and visibility
8
- * - Editability computed per-field based on viewer role
9
- * - Type-safe form values inferred from entity
6
+ * Simple, predictable behavior:
7
+ * - Edit mode: defaultValues (DB object) is used as-is
8
+ * - Create mode: starts empty, optional auto-save to localStorage
9
+ *
10
+ * When formId is provided:
11
+ * - Tracks form status (uploading/validating/submitting)
12
+ * - Orchestrates file uploads before validation
13
+ * - Provides cleanup function for unmount
10
14
  *
11
15
  * @template E - Entity type from defineEntity()
12
16
  * @param entity - Entity definition from defineEntity()
13
17
  * @param options - Form configuration options
14
18
  * @returns Form instance with React Hook Form API plus entity-aware extensions
15
- *
16
- * @example
17
- * ```tsx
18
- * import { useEntityForm } from '@donotdev/crud/forms';
19
- * import { productEntity } from './entities/product';
20
- *
21
- * function ProductForm({ existingProduct, onSuccess }) {
22
- * const form = useEntityForm(productEntity, {
23
- * operation: existingProduct ? 'edit' : 'create',
24
- * defaultValues: existingProduct,
25
- * viewerRole: 'admin'
26
- * });
27
- *
28
- * const onSubmit = async (data) => {
29
- * await saveProduct(data);
30
- * onSuccess();
31
- * };
32
- *
33
- * return (
34
- * <form onSubmit={form.handleSubmit(onSubmit)}>
35
- * {form.fields.map(({ name, config, editable }) => (
36
- * editable ? (
37
- * <input
38
- * key={name}
39
- * {...form.register(name)}
40
- * placeholder={config.label}
41
- * />
42
- * ) : (
43
- * <span key={name}>{form.getValues(name)}</span>
44
- * )
45
- * ))}
46
- * <button type="submit" disabled={form.formState.isSubmitting}>
47
- * {form.operation === 'create' ? 'Create' : 'Update'}
48
- * </button>
49
- * </form>
50
- * );
51
- * }
52
- * ```
53
- *
54
- * @example
55
- * ```tsx
56
- * // With custom UI components
57
- * import { useEntityForm } from '@donotdev/crud/forms';
58
- * import { Input, Select, DatePicker } from './ui';
59
- *
60
- * function CustomForm() {
61
- * const form = useEntityForm(orderEntity, { operation: 'create' });
62
- *
63
- * // Custom 2-column layout
64
- * return (
65
- * <form onSubmit={form.handleSubmit(onSubmit)}>
66
- * <div className="grid grid-cols-2 gap-4">
67
- * <Input label="Customer" {...form.register('customer')} />
68
- * <DatePicker label="Date" {...form.register('orderDate')} />
69
- * </div>
70
- * <Select
71
- * label="Status"
72
- * options={form.fields.find(f => f.name === 'status')?.config.validation?.options}
73
- * {...form.register('status')}
74
- * />
75
- * </form>
76
- * );
77
- * }
78
- * ```
79
- *
80
- * @see {@link Entity} for entity definition structure
81
- * @see {@link EntityFormReturn} for return type
82
- * @see {@link getFieldsForOperation} for field filtering logic
83
- *
84
- * @version 0.0.1
85
- * @since 0.0.1
86
- * @author AMBROISE PARK Consulting
87
19
  */
88
20
  export declare function useEntityForm<E extends Entity>(entity: E, options?: UseEntityFormOptions<E>): EntityFormReturn<E>;
89
21
  //# sourceMappingURL=useEntityForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityForm.d.ts","sourceRoot":"","sources":["../../../src/forms/hooks/useEntityForm.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAEjB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC5C,MAAM,EAAE,CAAC,EACT,OAAO,GAAE,oBAAoB,CAAC,CAAC,CAAM,GACpC,gBAAgB,CAAC,CAAC,CAAC,CA4LrB"}
1
+ {"version":3,"file":"useEntityForm.d.ts","sourceRoot":"","sources":["../../../src/forms/hooks/useEntityForm.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAQ7C,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EAEjB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC5C,MAAM,EAAE,CAAC,EACT,OAAO,GAAE,oBAAoB,CAAC,CAAC,CAAM,GACpC,gBAAgB,CAAC,CAAC,CAAC,CAiarB"}
@@ -1 +1 @@
1
- "use client";import{useMemo as o,useEffect as g,useRef as h}from"react";import{useForm as k}from"react-hook-form";import{useLocalStorage as x}from"@donotdev/core";import{useAuth as H}from"@donotdev/auth";import{valibotResolver as w}from"@hookform/resolvers/valibot";import{createEntitySchema as y,getFieldsForOperation as K}from"../utils";function U(t,E={}){let v;try{v=H("userRole")}catch{}const{operation:L,defaultValues:r,viewerRole:m=v||"admin",mode:O="onSubmit",t:j,autoSave:s=!1}=E,e=L??(r?"edit":"create"),S=o(()=>y(t,"create"),[t]),R=o(()=>y(t,"draft"),[t]),T=o(()=>w(S),[S]),V=o(()=>w(R),[R]),A=o(()=>async(a,n,i)=>(a?.status==="draft"||r?.status==="draft"?V:T)(a,n,i),[T,V,r]),u=k({defaultValues:r,mode:O,resolver:A}),C=o(()=>`${t.name.toLowerCase()}-form-draft`,[t.name]),{value:d,setValue:D,removeValue:F}=x(C,{defaultValue:null,syncAcrossTabs:!0}),f=h(!1);g(()=>{!s||e!=="create"||r||f.current||(d&&u.reset(d),f.current=!0)},[s,e,r,d,u]);const p=h(!1),l=h(null);g(()=>{if(!s||e!=="create")return;const a=u.watch(n=>{p.current||!f.current||(l.current&&clearTimeout(l.current),l.current=setTimeout(()=>{Object.values(n).some(c=>c!=null&&c!=="")&&D(n)},3e3))});return()=>{a.unsubscribe(),l.current&&clearTimeout(l.current)}},[s,e,u,D]);const b=u.handleSubmit,M=o(()=>!s||e!=="create"?b:((a,n)=>b(async(i,c)=>{p.current=!0;try{await a(i,c),F()}finally{p.current=!1}},n)),[b,s,e,F]),P=o(()=>K(t,{operation:e,viewerRole:m,availableFields:e==="edit"&&r?Object.keys(r):void 0}),[t,e,m,r]);return{...u,handleSubmit:M,fields:P,operation:e,entity:t,t:j??(a=>a),viewerRole:m}}export{U as useEntityForm};
1
+ "use client";import{valibotResolver as B}from"@hookform/resolvers/valibot";import{useMemo as l,useEffect as O,useRef as g,useCallback as w}from"react";import{useForm as ee,useWatch as te}from"react-hook-form";import{useLocalStorage as re,BACKEND_GENERATED_FIELD_NAMES as se}from"@donotdev/core";import{createSchemas as oe}from"@donotdev/schemas";import{useFormStore as V,useFormStatus as ne,useUploadProgress as ae}from"../../stores";import{useUploadStore as L}from"../../stores/UploadStore";import{checkForBlobUrls as x}from"../../utils/uploadValidation";import{getFieldsForOperation as ue}from"../utils";function ve(i,N={}){const{formId:e,operation:_,defaultValues:a,viewerRole:F="admin",mode:C="onBlur",t:J,autoSave:m=!1}=N,n=_??(a?"edit":"create"),K=ne(e??""),W=ae(e??""),b=l(()=>oe(i),[i.name]),P=l(()=>B(b.create),[b.create]),U=l(()=>B(b.draft),[b.draft]),q=l(()=>async(t,o,s)=>((t?.status??a?.status)==="draft"?U:P)(t,o,s),[P,U,a?.status]),p=l(()=>{if(!a)return a;const t={...a};return Object.entries(i.fields).forEach(([o,s])=>{if(s.type==="switch"){const r=t[o];if(r==null){const S=s.options?.fieldSpecific;t[o]=S?.uncheckedValue??!1}}}),t},[a,i.fields]),u=ee({defaultValues:p,mode:C,resolver:q,shouldUnregister:!1,shouldFocusError:!0}),v=g(null);O(()=>{if(n==="edit"&&p){const t=p.id??null;t&&t!==v.current?(u.reset(p),v.current=t):!t&&v.current===null&&(u.reset(p),v.current="initialized")}},[n,p,u]);const G=l(()=>`${i.name.toLowerCase()}-form-draft`,[i.name]),{value:D,setValue:j,removeValue:k}=re(G,{defaultValue:null,syncAcrossTabs:!0}),R=g(!1);O(()=>{!m||n!=="create"||a||R.current||(D&&u.reset(D),R.current=!0)},[m,n,a,D,u]);const c=te({control:u.control}),E=g(!1),h=g(null),y=g(void 0),I=g(!0);O(()=>{if(I.current){I.current=!1,y.current=c?JSON.stringify(c):void 0;return}if(!m||n!=="create"||E.current||!R.current)return;const t=c?JSON.stringify(c):void 0;if(y.current!==t)return y.current=t,h.current&&clearTimeout(h.current),h.current=setTimeout(()=>{if(!c)return;Object.values(c).some(s=>s!=null&&s!=="")&&j(c)},3e3),()=>{h.current&&clearTimeout(h.current)}},[c,m,n,j]);const M=w(async()=>{if(!e)return!0;const t=L.getState(),o=V.getState();if(!t.hasPendingUploads(e))return!0;try{o.setUploading(e,0),await t.uploadAll(e),await new Promise(d=>setTimeout(d,50));let s=u.getValues(),r=x(s),S=0;const f=5;for(;r.length>0&&S<f;)S++,await new Promise(d=>setTimeout(d,100)),s=u.getValues(),r=x(s);if(r.length>0){const d=`Upload incomplete: files still pending at ${r.join(", ")}`;return o.setError(e,d),!1}return!0}catch(s){const r=s instanceof Error?s.message:"File upload failed";return V.getState().setError(e,r),!1}},[e,u]),A=w(t=>n!=="create"?t:Object.fromEntries(Object.entries(t).filter(([o])=>!se.includes(o))),[n]),$=w(t=>{if(typeof window>"u")return;const o=Object.keys(t).find(r=>r!=="root"&&t[r]);if(!o)return;const s=document.querySelector(`input[name="${o}"][aria-invalid="true"], textarea[name="${o}"][aria-invalid="true"], select[name="${o}"][aria-invalid="true"]`);s&&(s.scrollIntoView({behavior:"smooth",block:"center"}),s.focus())},[]),z=u.handleSubmit,H=l(()=>((t,o)=>async s=>{s?.preventDefault?.();const r=e?V.getState():null;e&&r&&r.startSubmit(e),E.current=!0;try{if(!await M()){E.current=!1;return}e&&r&&r.setValidating(e),await z(async(f,d)=>{e&&r&&r.setSubmitting(e);const Y=A(f);try{await t(Y,d),m&&n==="create"&&k(),e&&r&&r.setSuccess(e)}catch(T){const Z=T instanceof Error?T.message:"Submission failed";throw e&&r&&r.setError(e,Z),T}},f=>{e&&r&&r.setError(e,"Validation failed"),$(f),o?.(f)})(s)}finally{E.current=!1}}),[z,e,M,A,$,m,n,k]),Q=w(()=>{e&&(V.getState().cleanup(e),L.getState().cleanup(e))},[e]),X=l(()=>ue(i,{operation:n,viewerRole:F,availableFields:n==="edit"&&a?Object.keys(a):void 0}),[i,n,F,a]);return{...u,handleSubmit:H,fields:X,operation:n,entity:i,t:J??(t=>t),viewerRole:F,formId:e,formStatus:e?K:"idle",uploadProgress:e?W:0,cleanup:Q}}export{ve as useEntityForm};
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Import from '@donotdev/crud/forms' to access form building blocks:
6
6
  * - Hooks: useEntityForm, useEntityField
7
- * - Utilities: getFieldsForOperation, createEntitySchema, validateEntity
7
+ * - Utilities: getFieldsForOperation, validateEntity
8
8
  * - Types: InferEntityData, EntityFormReturn, etc.
9
9
  *
10
10
  * @example
@@ -31,7 +31,9 @@
31
31
  */
32
32
  export { useEntityForm } from './hooks/useEntityForm';
33
33
  export { useEntityField } from './hooks/useEntityField';
34
- export { isFieldEditable, normalizeToFieldConfig, getFieldsForOperation, createEntitySchema, validateEntity, } from './utils';
35
- export type { ViewerRole, RenderableField, GetFieldsForOperationOptions, EntityFieldsInput, SchemaOperation, ValidationIssue, ValidationResult, } from './utils';
36
- export type { InferEntityData, InferEntityInput, InferEntityOutput, UseEntityFormOptions, EntityFormReturn, EntityFieldReturn, Entity, EntityField, FieldConfig, FieldType, Visibility, Editable, ValidationRules, dndevSchema, } from './types';
34
+ export { useController } from './hooks/useController';
35
+ export type { UseControllerProps, UseControllerReturn, ControllerRenderProps, ControllerFieldState, } from './hooks/useController';
36
+ export { isFieldEditable, getFieldsForOperation, validateEntity, translateFieldLabel, translateLabel, yearOptions, rangeOptions, } from './utils';
37
+ export type { ViewerRole, RenderableField, GetFieldsForOperationOptions, EntityFieldsInput, SchemaOperation, ValidationIssue, ValidationResult, SelectOption, } from './utils';
38
+ export type { InferEntityData, InferEntityInput, InferEntityOutput, UseEntityFormOptions, EntityFormReturn, EntityFieldReturn, Entity, EntityField, FieldType, Visibility, Editable, ValidationRules, dndevSchema, } from './types';
37
39
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forms/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,GACf,MAAM,SAAS,CAAC;AAGjB,YAAY,EAEV,UAAU,EACV,eAAe,EACf,4BAA4B,EAC5B,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAEV,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EAEjB,MAAM,EACN,WAAW,EACX,WAAW,EACX,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,GACZ,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forms/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,mBAAmB,EACnB,cAAc,EAEd,WAAW,EACX,YAAY,GACb,MAAM,SAAS,CAAC;AAGjB,YAAY,EAEV,UAAU,EACV,eAAe,EACf,4BAA4B,EAC5B,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,YAAY,EAEV,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EAEjB,MAAM,EACN,WAAW,EACX,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,GACZ,MAAM,SAAS,CAAC"}
@@ -1 +1 @@
1
- import{useEntityForm as i}from"./hooks/useEntityForm";import{useEntityField as r}from"./hooks/useEntityField";import{isFieldEditable as l,normalizeToFieldConfig as n,getFieldsForOperation as d,createEntitySchema as m,validateEntity as F}from"./utils";export{m as createEntitySchema,d as getFieldsForOperation,l as isFieldEditable,n as normalizeToFieldConfig,r as useEntityField,i as useEntityForm,F as validateEntity};
1
+ import{useEntityForm as r}from"./hooks/useEntityForm";import{useEntityField as i}from"./hooks/useEntityField";import{useController as l}from"./hooks/useController";import{isFieldEditable as s,getFieldsForOperation as p,validateEntity as d,translateFieldLabel as F,translateLabel as m,yearOptions as f,rangeOptions as x}from"./utils";export{p as getFieldsForOperation,s as isFieldEditable,x as rangeOptions,F as translateFieldLabel,m as translateLabel,l as useController,i as useEntityField,r as useEntityForm,d as validateEntity,f as yearOptions};
@@ -6,10 +6,11 @@
6
6
  * @since 0.0.1
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
9
- import type { UseFormReturn, ControllerRenderProps, FieldPath } from 'react-hook-form';
10
- import type { Entity, EntityField, FieldConfig, FieldType, FieldTypeToValue, Visibility, Editable, ValidationRules, dndevSchema } from '@donotdev/core';
9
+ import type { Entity, EntityField, FieldType, FieldTypeToValue, Visibility, Editable, ValidationRules, dndevSchema } from '@donotdev/core';
10
+ import type { FormStatus } from '../stores/FormStore';
11
11
  import type { RenderableField, ViewerRole } from './utils';
12
- export type { Entity, EntityField, FieldConfig, FieldType, Visibility, Editable, ValidationRules, dndevSchema, RenderableField, ViewerRole, };
12
+ import type { UseFormReturn, ControllerRenderProps, FieldPath } from 'react-hook-form';
13
+ export type { Entity, EntityField, FieldType, Visibility, Editable, ValidationRules, dndevSchema, RenderableField, ViewerRole, };
13
14
  /**
14
15
  * Infers the data type from an entity definition.
15
16
  *
@@ -41,7 +42,7 @@ export type { Entity, EntityField, FieldConfig, FieldType, Visibility, Editable,
41
42
  export type InferEntityData<E extends Entity> = {
42
43
  [K in keyof E['fields']]: E['fields'][K] extends {
43
44
  type: infer T;
44
- } ? T extends FieldType ? FieldTypeToValue[T] : unknown : unknown;
45
+ } ? T extends FieldType ? T extends keyof FieldTypeToValue ? FieldTypeToValue[T] : unknown : unknown : unknown;
45
46
  };
46
47
  /**
47
48
  * Infers form input type (values before validation).
@@ -75,6 +76,12 @@ export type InferEntityOutput<E extends Entity> = InferEntityData<E>;
75
76
  * @author AMBROISE PARK Consulting
76
77
  */
77
78
  export interface UseEntityFormOptions<E extends Entity> {
79
+ /**
80
+ * Form ID for tracking form/upload state.
81
+ * Required for deferred file uploads and form status tracking.
82
+ * Generate with useId() in the parent component.
83
+ */
84
+ formId?: string;
78
85
  /**
79
86
  * Form operation type.
80
87
  * - 'create': Excludes technical fields, all other fields editable
@@ -145,6 +152,25 @@ export interface EntityFormReturn<E extends Entity> extends UseFormReturn<InferE
145
152
  * Current viewer role.
146
153
  */
147
154
  viewerRole: ViewerRole;
155
+ /**
156
+ * Form ID for state tracking.
157
+ * Undefined if not provided in options.
158
+ */
159
+ formId: string | undefined;
160
+ /**
161
+ * Current form status from FormStore.
162
+ * Tracks: idle → uploading → validating → submitting → success/error
163
+ */
164
+ formStatus: FormStatus;
165
+ /**
166
+ * Upload progress 0-100 when status is 'uploading'.
167
+ */
168
+ uploadProgress: number;
169
+ /**
170
+ * Cleanup function to call on unmount.
171
+ * Cleans up FormStore and UploadStore state for this form.
172
+ */
173
+ cleanup: () => void;
148
174
  }
149
175
  /**
150
176
  * Return type for useEntityField hook.
@@ -172,7 +198,7 @@ export interface EntityFieldReturn<E extends Entity, K extends keyof InferEntity
172
198
  /**
173
199
  * Normalized field configuration.
174
200
  */
175
- config: FieldConfig;
201
+ config: EntityField;
176
202
  /**
177
203
  * Whether field is editable (based on role, operation, config).
178
204
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/forms/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/forms/types.ts"],"names":[],"mappings":"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"}
@@ -6,16 +6,16 @@
6
6
  * @since 0.0.1
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
9
- import type { Entity, EntityField, FieldConfig, FieldType } from '@donotdev/core';
9
+ import type { Entity, EntityField, FieldType } from '@donotdev/core';
10
10
  /** Entity fields input - supports Entity, Entity['fields'], or plain Record */
11
- export type EntityFieldsInput = Entity | Entity['fields'] | Record<string, EntityField<FieldType> | FieldConfig<FieldType>>;
12
- import { type ViewerRole } from './isFieldEditable';
11
+ export type EntityFieldsInput = Entity | Entity['fields'] | Record<string, EntityField<FieldType>>;
12
+ import type { ViewerRole } from './isFieldEditable';
13
13
  /** Field with computed editability for rendering */
14
14
  export interface RenderableField<T extends FieldType = FieldType> {
15
15
  /** Field name/key */
16
16
  name: string;
17
- /** Normalized field configuration */
18
- config: FieldConfig<T>;
17
+ /** Field configuration */
18
+ config: EntityField<T>;
19
19
  /** Whether field is editable (input vs read-only) */
20
20
  editable: boolean;
21
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getFieldsForOperation.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/getFieldsForOperation.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,MAAM,EACN,WAAW,EACX,WAAW,EACX,SAAS,EACV,MAAM,gBAAgB,CAAC;AAExB,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,MAAM,CAAC,QAAQ,CAAC,GAChB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;AAGpE,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAErE,oDAAoD;AACpD,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IAC9D,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,kCAAkC;AAClC,MAAM,WAAW,4BAA4B;IAC3C,0BAA0B;IAC1B,SAAS,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC7B,yCAAyC;IACzC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,4BAA4B,GACpC,eAAe,EAAE,CAyDnB"}
1
+ {"version":3,"file":"getFieldsForOperation.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/getFieldsForOperation.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAErE,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,MAAM,CAAC,QAAQ,CAAC,GAChB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;AAI3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,oDAAoD;AACpD,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IAC9D,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,kCAAkC;AAClC,MAAM,WAAW,4BAA4B;IAC3C,0BAA0B;IAC1B,SAAS,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC7B,yCAAyC;IACzC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,4BAA4B,GACpC,eAAe,EAAE,CAoDnB"}
@@ -1 +1 @@
1
- import{normalizeToFieldConfig as f}from"./normalizeToFieldConfig";import{isFieldEditable as u}from"./isFieldEditable";function F(e,s){const{operation:r,viewerRole:d="admin",availableFields:t}=s,a=e&&typeof e=="object"&&"fields"in e&&"name"in e?e.fields:e;return Object.entries(a).map(([i,c])=>{const n=f(i,c),l=n.visibility||"user";if(r==="create"){if(l==="technical"||l==="hidden")return null}else if(l==="hidden"||t&&!t.includes(i))return null;let o=u(n.editable,d,r);return r==="edit"&&l==="technical"&&n.editable===void 0&&(o=!1),{name:i,config:n,editable:o}}).filter(i=>i!==null)}export{F as getFieldsForOperation};
1
+ import{isFieldEditable as b}from"./isFieldEditable";function p(e,c){const{operation:l,viewerRole:f="admin",availableFields:o}=c,a=e&&typeof e=="object"&&"fields"in e&&"name"in e?e.fields:e,r=Object.entries(a),t=[];for(const[s,u]of r){const i=u,n=i.visibility||"user";if(l==="create"){if(n==="technical"||n==="hidden")continue}else if(n==="hidden"||o&&!o.includes(s))continue;let d=b(i.editable,f,l);l==="edit"&&n==="technical"&&i.editable===void 0&&(d=!1),t.push({name:s,config:i,editable:d})}return t}export{p as getFieldsForOperation};
@@ -6,9 +6,13 @@
6
6
  * @since 0.0.1
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
9
- export { isFieldEditable, type ViewerRole } from './isFieldEditable';
10
- export { normalizeToFieldConfig } from './normalizeToFieldConfig';
11
- export { getFieldsForOperation, type RenderableField, type GetFieldsForOperationOptions, type EntityFieldsInput, } from './getFieldsForOperation';
12
- export { createEntitySchema, type SchemaOperation } from './createEntitySchema';
13
- export { validateEntity, type ValidationIssue, type ValidationResult, } from './validateEntity';
9
+ export { isFieldEditable } from './isFieldEditable';
10
+ export type { ViewerRole } from './isFieldEditable';
11
+ export { getFieldsForOperation } from './getFieldsForOperation';
12
+ export type { RenderableField, GetFieldsForOperationOptions, EntityFieldsInput, } from './getFieldsForOperation';
13
+ export { validateEntity } from './validateEntity';
14
+ export type { ValidationIssue, ValidationResult, SchemaOperation, } from './validateEntity';
15
+ export { translateFieldLabel, translateLabel } from './translateFieldLabel';
16
+ export { yearOptions, rangeOptions } from './optionHelpers';
17
+ export type { SelectOption } from './optionHelpers';
14
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EACL,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EACV,eAAe,EACf,4BAA4B,EAC5B,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1 +1 @@
1
- import{isFieldEditable as r}from"./isFieldEditable";import{normalizeToFieldConfig as i}from"./normalizeToFieldConfig";import{getFieldsForOperation as m}from"./getFieldsForOperation";import{createEntitySchema as l}from"./createEntitySchema";import{validateEntity as d}from"./validateEntity";export{l as createEntitySchema,m as getFieldsForOperation,r as isFieldEditable,i as normalizeToFieldConfig,d as validateEntity};
1
+ import{isFieldEditable as r}from"./isFieldEditable";import{getFieldsForOperation as a}from"./getFieldsForOperation";import{validateEntity as l}from"./validateEntity";import{translateFieldLabel as n,translateLabel as s}from"./translateFieldLabel";import{yearOptions as f,rangeOptions as m}from"./optionHelpers";export{a as getFieldsForOperation,r as isFieldEditable,m as rangeOptions,n as translateFieldLabel,s as translateLabel,l as validateEntity,f as yearOptions};
@@ -1,11 +1,3 @@
1
- /**
2
- * @fileoverview Field editability utility
3
- * @description Determines if a field is editable based on editable config, viewer role, and operation.
4
- *
5
- * @version 0.0.1
6
- * @since 0.0.1
7
- * @author AMBROISE PARK Consulting
8
- */
9
1
  import type { Editable } from '@donotdev/core';
10
2
  /** Viewer role type - used for editability checks */
11
3
  export type ViewerRole = 'public' | 'guest' | 'user' | 'admin' | 'super';
@@ -1 +1 @@
1
- {"version":3,"file":"isFieldEditable.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/isFieldEditable.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,qDAAqD;AACrD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAC9B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,QAAQ,GAAG,MAAM,GAC3B,OAAO,CAcT"}
1
+ {"version":3,"file":"isFieldEditable.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/isFieldEditable.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qDAAqD;AACrD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAC9B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,QAAQ,GAAG,MAAM,GAC3B,OAAO,CAcT"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @fileoverview Option generation helpers for select fields
3
+ * @description Simple utilities to generate options arrays for select/dropdown fields.
4
+ *
5
+ * @version 0.0.1
6
+ * @since 0.0.1
7
+ * @author AMBROISE PARK Consulting
8
+ */
9
+ /** Standard option format for select fields */
10
+ export interface SelectOption {
11
+ value: string;
12
+ label: string;
13
+ }
14
+ /**
15
+ * Generates year options for a select field.
16
+ *
17
+ * @param startYear - First year in the range
18
+ * @param endYear - Last year in the range (defaults to current year)
19
+ * @param descending - Whether to sort descending (newest first, default: true)
20
+ * @returns Array of options with value and label
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // In entity definition
25
+ * year: {
26
+ * type: 'select',
27
+ * validation: {
28
+ * required: true,
29
+ * options: yearOptions(1995) // 2026, 2025, 2024, ... 1995
30
+ * }
31
+ * }
32
+ * ```
33
+ */
34
+ export declare function yearOptions(startYear: number, endYear?: number, descending?: boolean): SelectOption[];
35
+ /**
36
+ * Generates numeric range options for a select field.
37
+ *
38
+ * @param start - First number in the range
39
+ * @param end - Last number in the range
40
+ * @param step - Increment between numbers (default: 1)
41
+ * @param descending - Whether to sort descending (default: false)
42
+ * @returns Array of options with value and label
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * // Quantities 1-10
47
+ * options: rangeOptions(1, 10)
48
+ *
49
+ * // Percentages 0-100 by 10
50
+ * options: rangeOptions(0, 100, 10)
51
+ * ```
52
+ */
53
+ export declare function rangeOptions(start: number, end: number, step?: number, descending?: boolean): SelectOption[];
54
+ //# sourceMappingURL=optionHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optionHelpers.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/optionHelpers.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAiC,EAC1C,UAAU,GAAE,OAAc,GACzB,YAAY,EAAE,CAchB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,MAAU,EAChB,UAAU,GAAE,OAAe,GAC1B,YAAY,EAAE,CAchB"}
@@ -0,0 +1 @@
1
+ function o(n,t=new Date().getFullYear(),i=!0){const r=[];if(i)for(let e=t;e>=n;e--)r.push({value:String(e),label:String(e)});else for(let e=n;e<=t;e++)r.push({value:String(e),label:String(e)});return r}function u(n,t,i=1,r=!1){const e=[];if(r)for(let l=t;l>=n;l-=i)e.push({value:String(l),label:String(l)});else for(let l=n;l<=t;l+=i)e.push({value:String(l),label:String(l)});return e}export{u as rangeOptions,o as yearOptions};
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Field label translation utility
3
+ * @description Centralized helper for translating field labels with namespace support.
4
+ * Handles namespace:key syntax, config.label fallback, and fields.${fieldName} pattern.
5
+ *
6
+ * @version 0.0.1
7
+ * @since 0.0.1
8
+ * @author AMBROISE PARK Consulting
9
+ */
10
+ import type { EntityField, FieldType } from '@donotdev/core';
11
+ /**
12
+ * Translates a label string with namespace support.
13
+ * Used for translating option labels, field labels, or any label string.
14
+ *
15
+ * Supports namespace:key syntax (e.g., "common:actions.save")
16
+ *
17
+ * @param label - Label string to translate (may include namespace:key syntax)
18
+ * @param t - Translation function from useTranslation hook
19
+ * @returns Translated label string
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * translateLabel('common:status', t); // Translates "status" from "common" namespace
24
+ * translateLabel('make', t); // Translates "make" in current namespace
25
+ * ```
26
+ *
27
+ * @version 0.0.1
28
+ * @since 0.0.1
29
+ * @author AMBROISE PARK Consulting
30
+ */
31
+ export declare function translateLabel(label: string, t: (key: string, options?: Record<string, any>) => string): string;
32
+ /**
33
+ * Translates a field label using the provided translation function.
34
+ *
35
+ * Supports multiple label formats:
36
+ * - Namespace syntax: `"namespace:key"` → translates `key` in `namespace`
37
+ * - Direct label: `"label"` → translates `label` in current namespace
38
+ * - Field name fallback: uses field name if no label in config
39
+ *
40
+ * @param fieldName - Field name (used as fallback)
41
+ * @param config - Field configuration (may contain label)
42
+ * @param t - Translation function from useTranslation hook
43
+ * @returns Translated label string
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * import { translateFieldLabel } from '@donotdev/crud/forms';
48
+ * import { useTranslation } from '@donotdev/core';
49
+ *
50
+ * const { t } = useTranslation('entity-car');
51
+ * const label = translateFieldLabel('make', carEntity.fields.make, t);
52
+ * // Returns: translated "make" from entity-car namespace
53
+ * ```
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * // With namespace syntax in config.label
58
+ * const label = translateFieldLabel('status', {
59
+ * label: 'common:status',
60
+ * type: 'select'
61
+ * }, t);
62
+ * // Returns: translated "status" from "common" namespace
63
+ * ```
64
+ *
65
+ * @version 0.0.1
66
+ * @since 0.0.1
67
+ * @author AMBROISE PARK Consulting
68
+ */
69
+ export declare function translateFieldLabel<T extends FieldType = FieldType>(fieldName: string, config: EntityField<T> | undefined, t: (key: string, options?: Record<string, any>) => string): string;
70
+ //# sourceMappingURL=translateFieldLabel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateFieldLabel.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/translateFieldLabel.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,MAAM,GACxD,MAAM,CAWR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,EACjE,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,EAClC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,MAAM,GACxD,MAAM,CAGR"}
@@ -0,0 +1 @@
1
+ function o(t,n){if(typeof t=="string"&&t.includes(":")){const e=t.split(":"),r=e[1]??t,s=e[0];return n(r,{ns:s})}return n(t)}function c(t,n,e){const r=n?.label||t;return o(r,e)}export{c as translateFieldLabel,o as translateLabel};
@@ -1,5 +1,8 @@
1
1
  import type { Entity } from '@donotdev/core';
2
- import { type SchemaOperation } from './createEntitySchema';
2
+ /**
3
+ * Validation operation type
4
+ */
5
+ export type SchemaOperation = 'create' | 'draft' | 'update' | 'full';
3
6
  /**
4
7
  * Validation issue structure
5
8
  */
@@ -30,7 +33,7 @@ export interface ValidationResult<T> {
30
33
  * @template E - Entity type from defineEntity()
31
34
  * @param entity - Entity definition from defineEntity()
32
35
  * @param data - Data to validate
33
- * @param operation - Validation context ('create' or 'update')
36
+ * @param operation - Validation context ('create', 'draft', 'update', or 'full')
34
37
  * @returns Validation result with typed issues
35
38
  *
36
39
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"validateEntity.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/validateEntity.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,oCAAoC;IACpC,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAC7C,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,eAA0B,GACpC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsB3C"}
1
+ {"version":3,"file":"validateEntity.d.ts","sourceRoot":"","sources":["../../../src/forms/utils/validateEntity.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAG7C;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,oCAAoC;IACpC,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAC7C,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,eAA0B,GACpC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgC3C"}
@@ -1 +1 @@
1
- import*as o from"valibot";import{createEntitySchema as i}from"./createEntitySchema";function p(t,a,c="create"){const r=i(t,c),s=o.safeParse(r,a);return s.success?{success:!0,data:s.output}:{success:!1,issues:s.issues.map(e=>({path:e.path?.map(u=>u.key).join(".")||"",message:e.message}))}}export{p as validateEntity};
1
+ import*as o from"valibot";import{createSchemas as p}from"@donotdev/schemas";function h(a,c,r="create"){const s=p(a),u={create:s.create,draft:s.draft,update:s.update,full:s.get}[r],e=o.safeParse(u,c);return e.success?{success:!0,data:e.output}:{success:!1,issues:e.issues.map(t=>({path:t.path?.map(m=>m.key).join(".")||"",message:t.message}))}}export{h as validateEntity};
@@ -0,0 +1,3 @@
1
+ export { useFileUpload } from './useFileUpload';
2
+ export type { FileMetadata, UseFileUploadOptions } from './useFileUpload';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1 @@
1
+ import{useFileUpload as l}from"./useFileUpload";export{l as useFileUpload};
@@ -0,0 +1,67 @@
1
+ import type { Picture } from '@donotdev/types';
2
+ /** Metadata for a file in the upload queue */
3
+ export interface FileMetadata {
4
+ /** Unique ID for React keys */
5
+ id: string;
6
+ /** Original file object (for new uploads) */
7
+ file: File;
8
+ /** Local preview URL (blob: for new, https: for existing) */
9
+ previewURL: string;
10
+ /** Upload progress 0-100 (null = not started) */
11
+ progress: number | null;
12
+ /** Uploaded result (null = pending) */
13
+ uploaded: Picture | null;
14
+ /** Error message if upload failed */
15
+ error: string | null;
16
+ }
17
+ export interface UseFileUploadOptions {
18
+ /** Field name for UploadStore registration */
19
+ name: string;
20
+ /** Current value from form */
21
+ value: Picture | Picture[] | null | undefined;
22
+ /** Change handler to update form */
23
+ onChange: (value: Picture | Picture[] | null) => void;
24
+ /** Allow multiple files */
25
+ multiple?: boolean;
26
+ /** Max number of files (multiple mode) */
27
+ maxFiles?: number;
28
+ /** Max file size in bytes (default: 10MB) */
29
+ maxSize?: number;
30
+ /** Accepted MIME types (e.g., ['image/*'], ['application/pdf']) */
31
+ accept?: string[];
32
+ /** Storage path prefix */
33
+ storagePath?: string;
34
+ /** Upload function - injected to avoid coupling to specific storage */
35
+ uploadFn?: (file: File, onProgress: (progress: number) => void) => Promise<Picture>;
36
+ }
37
+ /**
38
+ * useFileUpload - Unified hook for file uploads
39
+ *
40
+ * Features:
41
+ * - Local preview before upload
42
+ * - Deferred upload on form submit (when inside EntityFormRenderer)
43
+ * - Immediate upload when standalone (no UploadProvider context)
44
+ * - UploadStore integration
45
+ * - File validation
46
+ * - Progress tracking
47
+ * - Works with Image, File, Document field types
48
+ */
49
+ export declare function useFileUpload({ name, value, onChange, multiple, maxFiles, maxSize, accept, storagePath, uploadFn, }: UseFileUploadOptions): {
50
+ /** Current files (pending + uploaded) */
51
+ files: FileMetadata[];
52
+ /** Add new files (from drop/paste/input) */
53
+ addFiles: (newFiles: File[]) => void;
54
+ /** Remove a file by ID */
55
+ removeFile: (id: string) => void;
56
+ /** Whether any files are pending upload */
57
+ hasPending: boolean;
58
+ /** Whether upload is in progress */
59
+ isUploading: boolean;
60
+ /** Overall progress 0-100 */
61
+ progress: number;
62
+ /** Form ID from context (undefined if standalone) */
63
+ formId: string | undefined;
64
+ /** Whether uploads are deferred (true inside EntityFormRenderer, false standalone) */
65
+ isDeferred: boolean;
66
+ };
67
+ //# sourceMappingURL=useFileUpload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFileUpload.d.ts","sourceRoot":"","sources":["../../src/hooks/useFileUpload.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK/C,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,IAAI,EAAE,IAAI,CAAC;IACX,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uCAAuC;IACvC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,qCAAqC;IACrC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,oCAAoC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IACtD,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACrF;AA6DD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,QAAa,EACb,OAA0B,EAC1B,MAAW,EACX,WAAuB,EACvB,QAAQ,GACT,EAAE,oBAAoB;IA4YnB,yCAAyC;;IAEzC,4CAA4C;yBArGjC,IAAI,EAAE;IAuGjB,0BAA0B;qBA9BrB,MAAM;IAgCX,2CAA2C;;IAE3C,oCAAoC;;IAEpC,6BAA6B;;IAE7B,qDAAqD;;IAErD,sFAAsF;;EAGzF"}
@@ -0,0 +1 @@
1
+ "use client";import{useState as G,useCallback as R,useEffect as v,useRef as A,startTransition as H}from"react";import{handleError as j}from"@donotdev/core";import{useUploadContext as K}from"../contexts/UploadContext";import{useUploadStore as k}from"../stores/UploadStore";let B=0;function M(l){if(l){const d=l.split("/").pop()?.split("?")[0];if(d)return`file-${d}`}B+=1;const u=typeof performance<"u"?performance.now():Date.now(),g=Math.random().toString(36).slice(2,11);return`file-${B}-${u}-${g}`}function Q(l){return URL.createObjectURL(l)}function V(l){l.startsWith("blob:")&&URL.revokeObjectURL(l)}function X(l,u,g){return u.length>0&&!u.some(m=>{if(m.endsWith("/*")){const L=m.slice(0,-2);return l.type.startsWith(L)}return l.type===m})?{valid:!1,error:`File type ${l.type} not accepted`}:l.size>g?{valid:!1,error:`File exceeds ${(g/1048576).toFixed(0)}MB limit`}:{valid:!0}}function er({name:l,value:u,onChange:g,multiple:d=!1,maxFiles:m=10,maxSize:L=10*1024*1024,accept:x=[],storagePath:Y="uploads",uploadFn:U}){const h=K(),w=!!h,[f,c]=G([]),E=A(!1),P=A(null),F=A(u),$=A([]);v(()=>{if(E.current){E.current=!1;return}const e=u?JSON.stringify((Array.isArray(u)?u:[u]).map(s=>s.fullUrl).filter(Boolean).sort()):null;e!==P.current&&(P.current=e,F.current=u,H(()=>{if(u){const n=(Array.isArray(u)?u:[u]).filter(t=>t.fullUrl).map((t,r)=>({id:`${M(t.fullUrl)}-existing-${r}`,file:new File([],"existing"),previewURL:t.thumbUrl||t.fullUrl,progress:100,uploaded:t,error:null}));c(n)}else c([])}))},[u]),v(()=>{$.current=f},[f]),v(()=>()=>{$.current.forEach(e=>V(e.previewURL))},[]);const p=R((e,s=!1)=>{const t=(s?e.filter(i=>!i.error):e.filter(i=>i.uploaded&&!i.error)).map(i=>i.uploaded?i.uploaded:s&&w?{fullUrl:i.previewURL,thumbUrl:i.previewURL}:null).filter(i=>i!==null);let r;d?r=t.length>0?t:null:r=t[0]||null;const o=F.current;(()=>{if(!r&&!o)return!1;if(!r||!o)return!0;if(d&&Array.isArray(r)&&Array.isArray(o)){if(r.length!==o.length)return!0;const i=r.map(b=>b.fullUrl).sort().join(","),y=o.map(b=>b.fullUrl).sort().join(",");return i!==y}return!d&&!Array.isArray(r)&&!Array.isArray(o)?r.fullUrl!==o.fullUrl:!0})()&&(E.current=!0,F.current=r,g(r))},[d,g,w]),S=R(async()=>{if(!U)return;let e=[];if(c(n=>(e=n.filter(t=>!t.uploaded&&!t.error),e.length===0?n:n.map(t=>e.some(r=>r.id===t.id)?{...t,progress:0}:t))),e.length===0)return;const s=await Promise.allSettled(e.map(async n=>{try{const t=await U(n.file,r=>{c(o=>o.map(a=>a.id===n.id?{...a,progress:r}:a))});return{id:n.id,picture:t,error:null}}catch(t){const r=t instanceof Error?t.message:"Upload failed";return{id:n.id,picture:null,error:r}}}));c(n=>{const t=n.map(r=>{const o=s.find(a=>a.status==="fulfilled"&&a.value.id===r.id);if(o&&o.status==="fulfilled"){const a=o.value;return{...r,uploaded:a.picture,progress:a.picture?100:null,error:a.error}}return r});return p(t,!1),t})},[U,p]),C=A(S);C.current=S;const I=k(e=>e.registerUpload),N=k(e=>e.unregisterUpload);v(()=>{if(!(!h||!l))return I(h,l,async()=>{await C.current()},()=>$.current.some(e=>!e.uploaded&&!e.error)),()=>{N(h,l)}},[h,l,I,N]);const T=R(async e=>{if(U){c(s=>s.map(n=>n.id===e.id?{...n,progress:0}:n));try{const s=await U(e.file,n=>{c(t=>t.map(r=>r.id===e.id?{...r,progress:n}:r))});c(n=>{const t=n.map(r=>r.id===e.id?{...r,uploaded:s,progress:100,error:null}:r);return p(t,!1),t})}catch(s){const n=s instanceof Error?s.message:"Upload failed";c(t=>t.map(r=>r.id===e.id?{...r,error:n,progress:null}:r))}}},[U,p]),D=R(e=>{c(s=>{const t=(d?m:1)-s.length;if(t<=0)return j(new Error("Maximum files reached"),{userMessage:d?`Maximum ${m} files allowed`:"Only one file allowed",severity:"warning",showNotification:!0}),s;const r=e.slice(0,t),o=[];for(const i of r){const y=X(i,x,L);if(!y.valid){j(new Error(y.error),{userMessage:y.error,severity:"warning",showNotification:!0});continue}o.push({id:M(),file:i,previewURL:Q(i),progress:null,uploaded:null,error:null})}if(o.length===0)return s;const a=d?[...s,...o]:o;return w?setTimeout(()=>{p(a,!0)},0):o.forEach(i=>T(i)),a})},[d,m,x,L,w,T,p]),O=R(e=>{c(s=>{const n=s.find(r=>r.id===e);n&&V(n.previewURL);const t=s.filter(r=>r.id!==e);return p(t,!1),t})},[p]),W=f.some(e=>!e.uploaded&&!e.error),J=f.some(e=>e.progress!==null&&e.progress<100),q=f.length>0?f.reduce((e,s)=>e+(s.progress??0),0)/f.length:0;return{files:f,addFiles:D,removeFile:O,hasPending:W,isUploading:J,progress:q,formId:h,isDeferred:w}}export{er as useFileUpload};