@donotdev/crud 0.0.31 → 0.1.1

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 (326) hide show
  1. package/LICENSE.md +3 -3
  2. package/dist/CrudService.d.ts +13 -4
  3. package/dist/CrudService.d.ts.map +1 -1
  4. package/dist/CrudService.js +2 -2
  5. package/dist/CrudStore.d.ts +1 -1
  6. package/dist/CrudStore.d.ts.map +1 -1
  7. package/dist/CrudStore.js +1 -1
  8. package/dist/FieldRegistry.d.ts +2 -12
  9. package/dist/FieldRegistry.d.ts.map +1 -1
  10. package/dist/FieldRegistry.js +1 -1
  11. package/dist/adapters/FunctionsAdapter.d.ts +3 -3
  12. package/dist/adapters/FunctionsAdapter.d.ts.map +1 -1
  13. package/dist/adapters/FunctionsAdapter.js +1 -1
  14. package/dist/adapters/index.d.ts +1 -1
  15. package/dist/builtinFieldTypes.d.ts +1 -1
  16. package/dist/components/CrudButton.d.ts +1 -0
  17. package/dist/components/CrudButton.d.ts.map +1 -1
  18. package/dist/components/CrudButton.js +1 -1
  19. package/dist/components/CrudCard.d.ts +1 -1
  20. package/dist/components/CrudCard.d.ts.map +1 -1
  21. package/dist/components/CrudCard.js +1 -1
  22. package/dist/components/DateFilter.js +1 -1
  23. package/dist/components/DisplayFieldRenderer.d.ts +2 -1
  24. package/dist/components/DisplayFieldRenderer.d.ts.map +1 -1
  25. package/dist/components/DisplayFieldRenderer.js +1 -1
  26. package/dist/components/DisplayThumbnail.d.ts +1 -9
  27. package/dist/components/DisplayThumbnail.d.ts.map +1 -1
  28. package/dist/components/DisplayThumbnail.js +1 -1
  29. package/dist/components/EntityFilters.d.ts +1 -0
  30. package/dist/components/EntityFilters.d.ts.map +1 -1
  31. package/dist/components/EntityFilters.js +1 -1
  32. package/dist/components/FormFieldRenderer.d.ts +1 -0
  33. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  34. package/dist/components/FormFieldRenderer.js +1 -1
  35. package/dist/components/FormLayout.d.ts +2 -1
  36. package/dist/components/FormLayout.d.ts.map +1 -1
  37. package/dist/components/FormLayout.js +1 -1
  38. package/dist/components/controlled/complex/ControlledAddressField.js +1 -1
  39. package/dist/components/controlled/complex/ControlledDateField.d.ts.map +1 -1
  40. package/dist/components/controlled/complex/ControlledDateField.js +1 -1
  41. package/dist/components/controlled/complex/ControlledFieldArrayField.js +1 -1
  42. package/dist/components/controlled/complex/ControlledGeoPointField.js +1 -1
  43. package/dist/components/controlled/complex/ControlledMapField.js +1 -1
  44. package/dist/components/controlled/complex/ControlledMultiInputField.js +1 -1
  45. package/dist/components/controlled/complex/ControlledRichTextField.js +1 -1
  46. package/dist/components/controlled/complex/ControlledTimestampField.d.ts.map +1 -1
  47. package/dist/components/controlled/complex/ControlledTimestampField.js +1 -1
  48. package/dist/components/controlled/complex/index.js +1 -1
  49. package/dist/components/controlled/file/ControlledDocumentField.js +1 -1
  50. package/dist/components/controlled/file/ControlledFileField.js +1 -1
  51. package/dist/components/controlled/file/ControlledImageField.js +1 -1
  52. package/dist/components/controlled/file/ControlledMultiDocumentField.js +1 -1
  53. package/dist/components/controlled/file/ControlledMultiFileField.js +1 -1
  54. package/dist/components/controlled/file/ControlledMultiImageField.js +1 -1
  55. package/dist/components/controlled/file/index.js +1 -1
  56. package/dist/components/controlled/index.js +1 -1
  57. package/dist/components/controlled/input/ControlledCheckboxField.js +1 -1
  58. package/dist/components/controlled/input/ControlledCurrencyField.js +1 -1
  59. package/dist/components/controlled/input/ControlledDurationField.js +1 -1
  60. package/dist/components/controlled/input/ControlledGdprConsentField.js +1 -1
  61. package/dist/components/controlled/input/ControlledNumberField.js +1 -1
  62. package/dist/components/controlled/input/ControlledPasswordField.js +1 -1
  63. package/dist/components/controlled/input/ControlledPhoneField.js +1 -1
  64. package/dist/components/controlled/input/ControlledPriceField.js +1 -1
  65. package/dist/components/controlled/input/ControlledRangeField.js +1 -1
  66. package/dist/components/controlled/input/ControlledRatingField.js +1 -1
  67. package/dist/components/controlled/input/ControlledSwitchField.js +1 -1
  68. package/dist/components/controlled/input/ControlledTextField.d.ts +5 -5
  69. package/dist/components/controlled/input/ControlledTextField.d.ts.map +1 -1
  70. package/dist/components/controlled/input/ControlledTextField.js +1 -1
  71. package/dist/components/controlled/input/ControlledTextareaField.js +1 -1
  72. package/dist/components/controlled/input/index.js +1 -1
  73. package/dist/components/controlled/select/ControlledComboboxField.js +1 -1
  74. package/dist/components/controlled/select/ControlledDropdownField.d.ts +2 -4
  75. package/dist/components/controlled/select/ControlledDropdownField.d.ts.map +1 -1
  76. package/dist/components/controlled/select/ControlledDropdownField.js +1 -1
  77. package/dist/components/controlled/select/ControlledMultiDropdownField.d.ts +2 -4
  78. package/dist/components/controlled/select/ControlledMultiDropdownField.d.ts.map +1 -1
  79. package/dist/components/controlled/select/ControlledMultiDropdownField.js +1 -1
  80. package/dist/components/controlled/select/ControlledRadioField.d.ts +2 -4
  81. package/dist/components/controlled/select/ControlledRadioField.d.ts.map +1 -1
  82. package/dist/components/controlled/select/ControlledRadioField.js +1 -1
  83. package/dist/components/controlled/select/ControlledReferenceField.js +1 -1
  84. package/dist/components/controlled/select/ControlledYearField.js +1 -1
  85. package/dist/components/controlled/select/index.js +1 -1
  86. package/dist/components/controlled/types.js +1 -1
  87. package/dist/components/fields/display/AvatarFieldDisplay.d.ts +1 -1
  88. package/dist/components/fields/display/AvatarFieldDisplay.js +1 -1
  89. package/dist/components/fields/display/BadgeFieldDisplay.d.ts +1 -1
  90. package/dist/components/fields/display/BadgeFieldDisplay.js +1 -1
  91. package/dist/components/fields/display/ButtonFieldDisplay.d.ts +2 -2
  92. package/dist/components/fields/display/ButtonFieldDisplay.js +1 -1
  93. package/dist/components/fields/display/CheckboxFieldDisplay.d.ts +1 -1
  94. package/dist/components/fields/display/CheckboxFieldDisplay.js +1 -1
  95. package/dist/components/fields/display/DateFieldDisplay.d.ts +1 -1
  96. package/dist/components/fields/display/DateFieldDisplay.d.ts.map +1 -1
  97. package/dist/components/fields/display/DateFieldDisplay.js +1 -1
  98. package/dist/components/fields/display/DropdownDisplay.d.ts +1 -1
  99. package/dist/components/fields/display/DropdownDisplay.js +1 -1
  100. package/dist/components/fields/display/FileFieldDisplay.d.ts +1 -1
  101. package/dist/components/fields/display/FileFieldDisplay.js +1 -1
  102. package/dist/components/fields/display/GeoPointFieldDisplay.d.ts +1 -1
  103. package/dist/components/fields/display/GeoPointFieldDisplay.js +1 -1
  104. package/dist/components/fields/display/HiddenFieldDisplay.d.ts +2 -2
  105. package/dist/components/fields/display/HiddenFieldDisplay.js +1 -1
  106. package/dist/components/fields/display/ImageFieldDisplay.d.ts +1 -1
  107. package/dist/components/fields/display/ImageFieldDisplay.js +1 -1
  108. package/dist/components/fields/display/LinkFieldDisplay.d.ts +1 -1
  109. package/dist/components/fields/display/LinkFieldDisplay.js +1 -1
  110. package/dist/components/fields/display/MapFieldDisplay.d.ts +1 -1
  111. package/dist/components/fields/display/MapFieldDisplay.js +1 -1
  112. package/dist/components/fields/display/MultiDropdownDisplay.d.ts +1 -1
  113. package/dist/components/fields/display/MultiDropdownDisplay.js +1 -1
  114. package/dist/components/fields/display/MultiInputTextFieldDisplay.d.ts +1 -1
  115. package/dist/components/fields/display/MultiInputTextFieldDisplay.js +1 -1
  116. package/dist/components/fields/display/NumberFieldDisplay.d.ts +1 -1
  117. package/dist/components/fields/display/NumberFieldDisplay.d.ts.map +1 -1
  118. package/dist/components/fields/display/NumberFieldDisplay.js +1 -1
  119. package/dist/components/fields/display/PasswordFieldDisplay.d.ts +1 -1
  120. package/dist/components/fields/display/PasswordFieldDisplay.js +1 -1
  121. package/dist/components/fields/display/PhoneNumberDisplay.d.ts +1 -1
  122. package/dist/components/fields/display/PhoneNumberDisplay.js +1 -1
  123. package/dist/components/fields/display/RadioFieldDisplay.d.ts +1 -1
  124. package/dist/components/fields/display/RadioFieldDisplay.js +1 -1
  125. package/dist/components/fields/display/RangeFieldDisplay.d.ts +1 -1
  126. package/dist/components/fields/display/RangeFieldDisplay.js +1 -1
  127. package/dist/components/fields/display/ReferenceFieldDisplay.d.ts +1 -1
  128. package/dist/components/fields/display/ReferenceFieldDisplay.js +1 -1
  129. package/dist/components/fields/display/RichTextDisplay.d.ts +1 -1
  130. package/dist/components/fields/display/RichTextDisplay.js +2 -2
  131. package/dist/components/fields/display/TextAreaDisplay.d.ts +1 -1
  132. package/dist/components/fields/display/TextAreaDisplay.js +1 -1
  133. package/dist/components/fields/display/TextFieldDisplay.d.ts +1 -1
  134. package/dist/components/fields/display/TextFieldDisplay.js +1 -1
  135. package/dist/components/fields/display/TimestampFieldDisplay.d.ts +1 -1
  136. package/dist/components/fields/display/TimestampFieldDisplay.d.ts.map +1 -1
  137. package/dist/components/fields/display/TimestampFieldDisplay.js +1 -1
  138. package/dist/components/fields/display/index.d.ts +1 -1
  139. package/dist/components/fields/display/index.js +1 -1
  140. package/dist/components/form/fields/AddressFieldComponent.js +1 -1
  141. package/dist/components/form/fields/AvatarFieldComponent.d.ts +2 -2
  142. package/dist/components/form/fields/AvatarFieldComponent.js +1 -1
  143. package/dist/components/form/fields/BadgeFieldComponent.d.ts +2 -2
  144. package/dist/components/form/fields/BadgeFieldComponent.js +1 -1
  145. package/dist/components/form/fields/ButtonFieldComponent.js +1 -1
  146. package/dist/components/form/fields/CheckboxFieldComponent.d.ts +1 -1
  147. package/dist/components/form/fields/CheckboxFieldComponent.js +1 -1
  148. package/dist/components/form/fields/ComboboxComponent.d.ts +1 -1
  149. package/dist/components/form/fields/ComboboxComponent.js +1 -1
  150. package/dist/components/form/fields/CurrencyFieldComponent.d.ts +1 -1
  151. package/dist/components/form/fields/CurrencyFieldComponent.d.ts.map +1 -1
  152. package/dist/components/form/fields/CurrencyFieldComponent.js +1 -1
  153. package/dist/components/form/fields/DateFieldComponent.d.ts +3 -3
  154. package/dist/components/form/fields/DateFieldComponent.d.ts.map +1 -1
  155. package/dist/components/form/fields/DateFieldComponent.js +1 -1
  156. package/dist/components/form/fields/DocumentFieldComponent.js +1 -1
  157. package/dist/components/form/fields/DropdownComponent.d.ts +1 -1
  158. package/dist/components/form/fields/DropdownComponent.js +1 -1
  159. package/dist/components/form/fields/DurationFieldComponent.js +1 -1
  160. package/dist/components/form/fields/FileFieldComponent.js +1 -1
  161. package/dist/components/form/fields/GdprConsentFieldComponent.d.ts +1 -1
  162. package/dist/components/form/fields/GdprConsentFieldComponent.js +1 -1
  163. package/dist/components/form/fields/GeoPointFieldComponent.d.ts +1 -1
  164. package/dist/components/form/fields/GeoPointFieldComponent.js +1 -1
  165. package/dist/components/form/fields/HiddenFieldComponent.d.ts +1 -1
  166. package/dist/components/form/fields/HiddenFieldComponent.js +1 -1
  167. package/dist/components/form/fields/ImageFieldComponent.d.ts.map +1 -1
  168. package/dist/components/form/fields/ImageFieldComponent.js +1 -1
  169. package/dist/components/form/fields/MapFieldComponent.js +1 -1
  170. package/dist/components/form/fields/MultiDropdownComponent.d.ts +1 -1
  171. package/dist/components/form/fields/MultiDropdownComponent.js +1 -1
  172. package/dist/components/form/fields/MultiInputTextFieldComponent.js +1 -1
  173. package/dist/components/form/fields/NumberFieldComponent.d.ts +1 -1
  174. package/dist/components/form/fields/NumberFieldComponent.js +1 -1
  175. package/dist/components/form/fields/PasswordFieldComponent.d.ts +1 -1
  176. package/dist/components/form/fields/PasswordFieldComponent.js +1 -1
  177. package/dist/components/form/fields/PhoneNumberComponent.d.ts +1 -1
  178. package/dist/components/form/fields/PhoneNumberComponent.js +1 -1
  179. package/dist/components/form/fields/PriceFieldComponent.js +1 -1
  180. package/dist/components/form/fields/RadioFieldComponent.js +1 -1
  181. package/dist/components/form/fields/RangeFieldComponent.d.ts +1 -1
  182. package/dist/components/form/fields/RangeFieldComponent.js +1 -1
  183. package/dist/components/form/fields/RatingFieldComponent.d.ts +1 -1
  184. package/dist/components/form/fields/RatingFieldComponent.js +1 -1
  185. package/dist/components/form/fields/ReferenceFieldComponent.js +1 -1
  186. package/dist/components/form/fields/RichTextComponent.d.ts +1 -1
  187. package/dist/components/form/fields/RichTextComponent.js +1 -1
  188. package/dist/components/form/fields/SwitchFieldComponent.d.ts +1 -1
  189. package/dist/components/form/fields/SwitchFieldComponent.js +1 -1
  190. package/dist/components/form/fields/TextAreaComponent.d.ts +1 -1
  191. package/dist/components/form/fields/TextAreaComponent.js +1 -1
  192. package/dist/components/form/fields/TextFieldComponent.d.ts +4 -4
  193. package/dist/components/form/fields/TextFieldComponent.d.ts.map +1 -1
  194. package/dist/components/form/fields/TextFieldComponent.js +1 -1
  195. package/dist/components/form/fields/TimestampFieldComponent.d.ts +2 -2
  196. package/dist/components/form/fields/TimestampFieldComponent.d.ts.map +1 -1
  197. package/dist/components/form/fields/TimestampFieldComponent.js +1 -1
  198. package/dist/components/form/fields/index.d.ts +1 -1
  199. package/dist/components/form/fields/index.js +1 -1
  200. package/dist/components/form/fields/internal/TiptapEditor.d.ts +1 -1
  201. package/dist/components/form/fields/internal/TiptapEditor.js +2 -2
  202. package/dist/components/form/fields/types.d.ts +1 -1
  203. package/dist/components/form/index.d.ts +1 -1
  204. package/dist/components/form/internal/ImageViewerDialog.js +1 -1
  205. package/dist/components/index.d.ts +1 -1
  206. package/dist/components/index.js +1 -1
  207. package/dist/contexts/UploadContext.d.ts +1 -0
  208. package/dist/contexts/UploadContext.d.ts.map +1 -1
  209. package/dist/contexts/UploadContext.js +1 -1
  210. package/dist/contexts/index.js +1 -1
  211. package/dist/fieldTypeRegistry.d.ts.map +1 -1
  212. package/dist/fieldTypeRegistry.js +1 -1
  213. package/dist/fieldTypeRegistry.store.d.ts.map +1 -1
  214. package/dist/fieldTypeRegistry.store.js +1 -1
  215. package/dist/fieldTypeRegistry.types.d.ts +4 -0
  216. package/dist/fieldTypeRegistry.types.d.ts.map +1 -1
  217. package/dist/forms/hooks/index.d.ts +1 -1
  218. package/dist/forms/hooks/index.js +1 -1
  219. package/dist/forms/hooks/useController.js +1 -1
  220. package/dist/forms/hooks/useEntityField.d.ts +1 -1
  221. package/dist/forms/hooks/useEntityField.js +1 -1
  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 +1 -1
  225. package/dist/forms/index.js +1 -1
  226. package/dist/forms/types.d.ts +12 -7
  227. package/dist/forms/types.d.ts.map +1 -1
  228. package/dist/forms/utils/buildInitialValues.d.ts.map +1 -1
  229. package/dist/forms/utils/buildInitialValues.js +1 -1
  230. package/dist/forms/utils/getFieldsForOperation.d.ts +2 -2
  231. package/dist/forms/utils/getFieldsForOperation.d.ts.map +1 -1
  232. package/dist/forms/utils/getFieldsForOperation.js +1 -1
  233. package/dist/forms/utils/index.d.ts +1 -1
  234. package/dist/forms/utils/index.js +1 -1
  235. package/dist/forms/utils/isFieldEditable.d.ts +8 -2
  236. package/dist/forms/utils/isFieldEditable.d.ts.map +1 -1
  237. package/dist/forms/utils/isFieldEditable.js +1 -1
  238. package/dist/forms/utils/translateFieldLabel.d.ts +3 -3
  239. package/dist/forms/utils/translateFieldLabel.js +1 -1
  240. package/dist/forms/utils/validateEntity.d.ts +1 -1
  241. package/dist/forms/utils/validateEntity.js +1 -1
  242. package/dist/hooks/index.d.ts +2 -0
  243. package/dist/hooks/index.d.ts.map +1 -1
  244. package/dist/hooks/index.js +1 -1
  245. package/dist/hooks/useCrudFilters.d.ts +2 -0
  246. package/dist/hooks/useCrudFilters.d.ts.map +1 -1
  247. package/dist/hooks/useCrudFilters.js +1 -1
  248. package/dist/hooks/useCrudPageSize.d.ts +29 -0
  249. package/dist/hooks/useCrudPageSize.d.ts.map +1 -0
  250. package/dist/hooks/useCrudPageSize.js +1 -0
  251. package/dist/hooks/useEntityFavorites.d.ts +2 -0
  252. package/dist/hooks/useEntityFavorites.d.ts.map +1 -1
  253. package/dist/hooks/useEntityFavorites.js +1 -1
  254. package/dist/hooks/useFieldConditions.js +1 -1
  255. package/dist/hooks/useFileUpload.d.ts.map +1 -1
  256. package/dist/hooks/useFileUpload.js +1 -1
  257. package/dist/hooks/useReferenceResolver.d.ts +1 -1
  258. package/dist/hooks/useReferenceResolver.d.ts.map +1 -1
  259. package/dist/hooks/useReferenceResolver.js +1 -1
  260. package/dist/hooks/useRelatedItems.d.ts +2 -0
  261. package/dist/hooks/useRelatedItems.d.ts.map +1 -1
  262. package/dist/hooks/useRelatedItems.js +1 -1
  263. package/dist/hooks/useUnsavedChangesWarning.js +1 -1
  264. package/dist/index.d.ts +4 -4
  265. package/dist/index.d.ts.map +1 -1
  266. package/dist/index.js +1 -1
  267. package/dist/registerBuiltinFieldTypes.d.ts.map +1 -1
  268. package/dist/registerBuiltinFieldTypes.js +1 -1
  269. package/dist/stores/FormStore.d.ts +2 -0
  270. package/dist/stores/FormStore.d.ts.map +1 -1
  271. package/dist/stores/FormStore.js +1 -1
  272. package/dist/stores/UploadStore.d.ts +9 -3
  273. package/dist/stores/UploadStore.d.ts.map +1 -1
  274. package/dist/stores/UploadStore.js +1 -1
  275. package/dist/stores/index.d.ts +1 -1
  276. package/dist/stores/index.js +1 -1
  277. package/dist/symbol-index.json +1 -0
  278. package/dist/tsconfig.tsbuildinfo +1 -1
  279. package/dist/types.d.ts +10 -4
  280. package/dist/types.d.ts.map +1 -1
  281. package/dist/types.js +1 -1
  282. package/dist/useBaseCrudList.js +1 -1
  283. package/dist/useCrud.d.ts +1 -0
  284. package/dist/useCrud.d.ts.map +1 -1
  285. package/dist/useCrud.js +1 -1
  286. package/dist/useCrudCardList.d.ts +5 -3
  287. package/dist/useCrudCardList.d.ts.map +1 -1
  288. package/dist/useCrudCardList.js +1 -1
  289. package/dist/useCrudList.d.ts +5 -3
  290. package/dist/useCrudList.d.ts.map +1 -1
  291. package/dist/useCrudList.js +1 -1
  292. package/dist/utils/clientListProcessing.d.ts +22 -3
  293. package/dist/utils/clientListProcessing.d.ts.map +1 -1
  294. package/dist/utils/clientListProcessing.js +1 -1
  295. package/dist/utils/collections.d.ts +6 -6
  296. package/dist/utils/collections.js +1 -1
  297. package/dist/utils/fileStorage.d.ts +2 -0
  298. package/dist/utils/fileStorage.d.ts.map +1 -1
  299. package/dist/utils/fileStorage.js +1 -1
  300. package/dist/utils/imageProcessing.d.ts +1 -1
  301. package/dist/utils/imageProcessing.d.ts.map +1 -1
  302. package/dist/utils/imageProcessing.js +1 -1
  303. package/dist/utils/imageStorage.d.ts +2 -0
  304. package/dist/utils/imageStorage.d.ts.map +1 -1
  305. package/dist/utils/imageStorage.js +1 -1
  306. package/dist/utils/imageUtils.d.ts +1 -1
  307. package/dist/utils/imageUtils.js +1 -1
  308. package/dist/utils/matchesFilter.d.ts.map +1 -1
  309. package/dist/utils/matchesFilter.js +1 -1
  310. package/dist/utils/mergeWithOptimistic.js +1 -1
  311. package/dist/utils/sanitizeHtml.d.ts +0 -5
  312. package/dist/utils/sanitizeHtml.d.ts.map +1 -1
  313. package/dist/utils/sanitizeHtml.js +1 -1
  314. package/dist/utils/scopeUtils.js +1 -1
  315. package/dist/utils/uploadValidation.d.ts +1 -1
  316. package/dist/utils/uploadValidation.js +1 -1
  317. package/dist/workflows/WorkflowPersistence.d.ts +1 -1
  318. package/dist/workflows/WorkflowPersistence.js +1 -1
  319. package/dist/workflows/defineWorkflow.d.ts +1 -1
  320. package/dist/workflows/index.d.ts +1 -1
  321. package/dist/workflows/index.js +1 -1
  322. package/dist/workflows/useEntityWorkflow.js +1 -1
  323. package/guidelines/COMPONENTS.md +234 -0
  324. package/guidelines/CRUD.md +340 -0
  325. package/guidelines/GOTCHAS.md +46 -0
  326. package/package.json +7 -4
@@ -1,7 +1,2 @@
1
- /**
2
- * Sanitize HTML using DOMPurify — handles all known XSS vectors including
3
- * malformed tags, event handlers, javascript: URIs, data: URIs, SVG payloads,
4
- * CSS injection, and HTML entity encoding bypasses.
5
- */
6
1
  export declare function sanitizeHtml(html: string): string;
7
2
  //# sourceMappingURL=sanitizeHtml.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizeHtml.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizeHtml.ts"],"names":[],"mappings":"AAaA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD"}
1
+ {"version":3,"file":"sanitizeHtml.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizeHtml.ts"],"names":[],"mappings":"AA6DA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD"}
@@ -1 +1 @@
1
- import t from"dompurify";function n(i){return t.sanitize(i)}export{n as sanitizeHtml};
1
+ import e from"dompurify";const r=["p","h1","h2","h3","h4","h5","h6","blockquote","pre","hr","ul","ol","li","a","strong","b","em","i","u","s","code","br","span","sub","sup","mark","table","thead","tbody","tr","th","td","img","div","figure","figcaption","details","summary"],i=["href","target","rel","src","alt","width","height","class","colspan","rowspan"],a=/<\/?(?:embed|source|track|area|wbr)[^>]*>/gi;function n(t){return e.sanitize(t,{ALLOWED_TAGS:r,ALLOWED_ATTR:i}).replace(a,"")}export{n as sanitizeHtml};
@@ -1 +1 @@
1
- import{getScopeValue as t,CRUD_OPERATORS as c}from"@donotdev/core";function s(r,e){if(!e)return r;const o=t(e.provider);if(!o)throw new Error(`[CRUD] Scope provider "${e.provider}" returned null. Cannot write scoped entity without a scope value. Ensure a scope is selected before creating scoped entities.`);return{...r,[e.field]:o}}function p(r,e){const o=r??{};if(!e||typeof e.field!="string")return o;const n=t(e.provider);if(!n)throw new Error(`[CRUD] Scope provider "${e.provider}" returned null. Cannot query scoped entity without a scope value. Ensure a scope is selected before querying scoped entities.`);const i={field:e.field,operator:c.EQ,value:n};return{...o,where:o.where?[...o.where,i]:[i]}}function u(r){return r?t(r.provider):null}export{u as getCurrentScopeValue,s as injectScope,p as injectScopeFilter};
1
+ import{getScopeValue as o,CRUD_OPERATORS as p}from"@donotdev/core";function c(t,e){if(!e)return t;const r=o(e.provider);if(!r)throw new Error(`[CRUD] Scope provider "${e.provider}" returned null. Cannot write scoped entity without a scope value. Ensure a scope is selected before creating scoped entities.`);return{...t,[e.field]:r}}function l(t,e){const r=t??{};if(!e||typeof e.field!="string")return r;const i=o(e.provider);if(!i)throw new Error(`[CRUD] Scope provider "${e.provider}" returned null. Cannot query scoped entity without a scope value. Ensure a scope is selected before querying scoped entities.`);const n={field:e.field,operator:p.EQ,value:i};return{...r,where:r.where?[...r.where,n]:[n]}}function s(t){return t?o(t.provider):null}export{s as getCurrentScopeValue,c as injectScope,l as injectScopeFilter};
@@ -3,7 +3,7 @@
3
3
  * @description Type-safe validation utilities to ensure no blob URLs reach the database.
4
4
  * Provides security checks for Picture objects and form data validation.
5
5
  *
6
- * @version 0.0.1
6
+ * @version 0.1.0
7
7
  * @since 0.0.1
8
8
  * @author AMBROISE PARK Consulting
9
9
  */
@@ -1 +1 @@
1
- "use client";function o(r){return!r||typeof r!="string"?!1:r.startsWith("https://")&&!r.startsWith("blob:")}function h(r){return!(!r||typeof r!="object"||!o(r.fullUrl)||r.thumbUrl&&!o(r.thumbUrl))}function i(r,l=""){const t=[];if(r==null)return t;if(typeof r=="string")return r.startsWith("blob:")&&t.push(l||"root"),t;if(typeof r!="object")return t;if(Array.isArray(r))r.forEach((e,s)=>{const n=l?`${l}[${s}]`:`[${s}]`;t.push(...i(e,n))});else{const e=r;if(e.fullUrl!==void 0&&e.thumbUrl!==void 0){const s=e.fullUrl,n=e.thumbUrl,u=typeof s=="string"&&!o(s),c=n&&typeof n=="string"&&!o(n);if(u||c){const f=l||"root";t.push(`${f}.fullUrl or ${f}.thumbUrl contains blob URL`)}}else Object.entries(e).forEach(([s,n])=>{const u=l?`${l}.${s}`:s;t.push(...i(n,u))})}return t}function b(r){return i(r).length>0}export{i as checkForBlobUrls,b as hasBlobUrls,o as isStorageUrl,h as validatePicture};
1
+ "use client";function s(r){return!r||typeof r!="string"?!1:r.startsWith("https://")&&!r.startsWith("blob:")}function c(r){return!(!r||typeof r!="object"||!s(r.fullUrl)||r.thumbUrl&&!s(r.thumbUrl))}function u(r,o=""){const t=[];if(r==null)return t;if(typeof r=="string")return r.startsWith("blob:")&&t.push(o||"root"),t;if(typeof r!="object")return t;if(Array.isArray(r))r.forEach((e,n)=>{const l=o?`${o}[${n}]`:`[${n}]`;t.push(...u(e,l))});else{const e=r;if(e.fullUrl!==void 0&&e.thumbUrl!==void 0){const n=e.fullUrl,l=e.thumbUrl,f=typeof n=="string"&&!s(n),b=l&&typeof l=="string"&&!s(l);if(f||b){const i=o||"root";t.push(`${i}.fullUrl or ${i}.thumbUrl contains blob URL`)}}else Object.entries(e).forEach(([n,l])=>{const f=o?`${o}.${n}`:n;t.push(...u(l,f))})}return t}function h(r){return u(r).length>0}export{u as checkForBlobUrls,h as hasBlobUrls,s as isStorageUrl,c as validatePicture};
@@ -2,7 +2,7 @@
2
2
  * @fileoverview Workflow persistence adapter
3
3
  * @description Saves and restores workflow progress to/from localStorage.
4
4
  *
5
- * @version 0.0.1
5
+ * @version 0.1.0
6
6
  * @since 0.0.1
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
@@ -1 +1 @@
1
- const a="dndev-workflow-";function r(t,o){try{const e=`${a}${t}`;localStorage.setItem(e,JSON.stringify(o))}catch{}}function c(t){try{const o=`${a}${t}`,e=localStorage.getItem(o);return e?JSON.parse(e):null}catch{return null}}function n(t){try{const o=`${a}${t}`;localStorage.removeItem(o)}catch{}}export{n as clearWorkflowState,c as loadWorkflowState,r as saveWorkflowState};
1
+ const r="dndev-workflow-";function c(t,o){try{const e=`${r}${t}`;localStorage.setItem(e,JSON.stringify(o))}catch{}}function n(t){try{const o=`${r}${t}`,e=localStorage.getItem(o);return e?JSON.parse(e):null}catch{return null}}function a(t){try{const o=`${r}${t}`;localStorage.removeItem(o)}catch{}}export{a as clearWorkflowState,n as loadWorkflowState,c as saveWorkflowState};
@@ -18,7 +18,7 @@
18
18
  * });
19
19
  * ```
20
20
  *
21
- * @version 0.0.1
21
+ * @version 0.1.0
22
22
  * @since 0.0.1
23
23
  * @author AMBROISE PARK Consulting
24
24
  */
@@ -2,7 +2,7 @@
2
2
  * @fileoverview Workflow engine exports
3
3
  * @description Multi-step entity workflow: defineWorkflow, useEntityWorkflow, persistence.
4
4
  *
5
- * @version 0.0.1
5
+ * @version 0.1.0
6
6
  * @since 0.0.1
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
@@ -1 +1 @@
1
- import{defineWorkflow as o}from"./defineWorkflow";import{useEntityWorkflow as a}from"./useEntityWorkflow";import{saveWorkflowState as t,loadWorkflowState as r,clearWorkflowState as e}from"./WorkflowPersistence";export{e as clearWorkflowState,o as defineWorkflow,r as loadWorkflowState,t as saveWorkflowState,a as useEntityWorkflow};
1
+ import{defineWorkflow as e}from"./defineWorkflow";import{useEntityWorkflow as f}from"./useEntityWorkflow";import{saveWorkflowState as a,loadWorkflowState as k,clearWorkflowState as w}from"./WorkflowPersistence";export{w as clearWorkflowState,e as defineWorkflow,k as loadWorkflowState,a as saveWorkflowState,f as useEntityWorkflow};
@@ -1 +1 @@
1
- "use client";import{useState as g,useCallback as p,useMemo as h,useEffect as L,useRef as M}from"react";import{evaluateCondition as R}from"@donotdev/core";import{saveWorkflowState as K,loadWorkflowState as j,clearWorkflowState as C}from"./WorkflowPersistence";function V(e,I={}){const{onComplete:m,onStepChange:f,defaultValues:y}=I,w=M(m);w.current=m;const[a,v]=g(()=>{if(e.persist){const t=j(e.persistKey??e.id);if(t)return t.stepData}if(y){const t={};for(const r of e.steps)if(r.entity&&r.fields){const o={};for(const i of r.fields)i in y&&(o[i]=y[i]);Object.keys(o).length>0&&(t[r.id]=o)}return t}return{}}),[s,S]=g(()=>{if(e.persist){const t=j(e.persistKey??e.id);if(t)return t.currentStepIndex}return 0}),[k,x]=g(!1),l=h(()=>{const t={};for(const[r,o]of Object.entries(a))for(const[i,c]of Object.entries(o))t[i]=c,t[`${r}.${i}`]=c;return t},[a]),n=h(()=>e.steps.filter(t=>t.conditions?.visible?R(t.conditions.visible,l):!0),[e.steps,l]),O=n[s]??n[0],b=s===0,d=s===n.length-1;L(()=>{e.persist&&K(e.persistKey??e.id,{currentStepIndex:s,stepData:a,savedAt:Date.now()})},[e.persist,e.persistKey,e.id,s,a]);const W=p(async t=>{const r=n[s];if(!r)return!1;if(t&&v(i=>({...i,[r.id]:{...i[r.id],...t}})),r.validation?.validate){const i={...l,...t??{}};if(r.validation.validate(i)!==!0)return!1}if(r.after){const i={};await r.after({data:t??a[r.id]??{},allData:{...l,...t??{}},next:{prefill:c=>{const u=n[s+1];u&&(i[u.id]=c)}}}),Object.keys(i).length>0&&v(c=>{const u={...c};for(const[D,G]of Object.entries(i))u[D]={...u[D],...G};return u})}if(d){x(!0);try{const i={...l,...t??{}},c=w.current??e.onComplete;return c&&await c(i),e.persist&&C(e.persistKey??e.id),!0}catch{return!1}finally{x(!1)}}const o=s+1;return S(o),f?.(s,o),!0},[n,s,l,a,d,e,f]),N=p(()=>{if(b)return;const t=s-1;S(t),f?.(s,t)},[s,b,f]),A=p(()=>{if(!n[s]?.allowSkip||d)return;const t=s+1;S(t),f?.(s,t)},[n,s,d,f]),E=p(t=>{t>=0&&t<n.length&&(f?.(s,t),S(t))},[n.length,s,f]),P=p(()=>{e.persist&&K(e.persistKey??e.id,{currentStepIndex:s,stepData:a,savedAt:Date.now()})},[e,s,a]),$=p(()=>{C(e.persistKey??e.id)},[e]),F=p((t,r)=>{v(o=>({...o,[t]:{...o[t],...r}}))},[]);return{currentStep:O,currentStepIndex:s,visibleSteps:n,stepData:a,allData:l,goNext:W,goPrevious:N,skipStep:A,goToStep:E,isFirst:b,isLast:d,isSubmitting:k,canGoNext:!k,persistNow:P,clearPersisted:$,prefillStep:F}}export{V as useEntityWorkflow};
1
+ "use client";import{useState as b,useCallback as p,useMemo as I,useEffect as G,useRef as L}from"react";import{evaluateCondition as M}from"@donotdev/core";import{saveWorkflowState as K,loadWorkflowState as j,clearWorkflowState as O}from"./WorkflowPersistence";function B(e,D={}){const{onComplete:k,onStepChange:u,defaultValues:y}=D,w=L(k);w.current=k;const[l,v]=b(()=>{if(e.persist){const t=j(e.persistKey??e.id);if(t)return t.stepData}if(y){const t={};for(const r of e.steps)if(r.entity&&r.fields){const o={};for(const i of r.fields)i in y&&(o[i]=y[i]);Object.keys(o).length>0&&(t[r.id]=o)}return t}return{}}),[s,m]=b(()=>{if(e.persist){const t=j(e.persistKey??e.id);if(t)return t.currentStepIndex}return 0}),[x,h]=b(!1),d=I(()=>{const t={};for(const[r,o]of Object.entries(l))for(const[i,a]of Object.entries(o))t[i]=a,t[`${r}.${i}`]=a;return t},[l]),n=I(()=>e.steps.filter(t=>t.conditions?.visible?M(t.conditions.visible,d):!0),[e.steps,d]),W=n[s]??n[0],S=s===0,c=s===n.length-1;G(()=>{e.persist&&K(e.persistKey??e.id,{currentStepIndex:s,stepData:l,savedAt:Date.now()})},[e.persist,e.persistKey,e.id,s,l]);const F=p(async t=>{const r=n[s];if(!r)return!1;if(t&&v(i=>({...i,[r.id]:{...i[r.id],...t}})),r.validation?.validate){const i={...d,...t??{}};if(r.validation.validate(i)!==!0)return!1}if(r.after){const i={};await r.after({data:t??l[r.id]??{},allData:{...d,...t??{}},next:{prefill:a=>{const f=n[s+1];f&&(i[f.id]=a)}}}),Object.keys(i).length>0&&v(a=>{const f={...a};for(const[C,$]of Object.entries(i))f[C]={...f[C],...$};return f})}if(c){h(!0);try{const i={...d,...t??{}},a=w.current??e.onComplete;return a&&await a(i),e.persist&&O(e.persistKey??e.id),!0}catch{return!1}finally{h(!1)}}const o=s+1;return m(o),u?.(s,o),!0},[n,s,d,l,c,e,u]),N=p(()=>{if(S)return;const t=s-1;m(t),u?.(s,t)},[s,S,u]),A=p(()=>{if(!n[s]?.allowSkip||c)return;const r=s+1;m(r),u?.(s,r)},[n,s,c,u]),E=p(t=>{t>=0&&t<n.length&&(u?.(s,t),m(t))},[n.length,s,u]),P=p(()=>{e.persist&&K(e.persistKey??e.id,{currentStepIndex:s,stepData:l,savedAt:Date.now()})},[e,s,l]),R=p(()=>{O(e.persistKey??e.id)},[e]),V=p((t,r)=>{v(o=>({...o,[t]:{...o[t],...r}}))},[]);return{currentStep:W,currentStepIndex:s,visibleSteps:n,stepData:l,allData:d,goNext:F,goPrevious:N,skipStep:A,goToStep:E,isFirst:S,isLast:c,isSubmitting:x,canGoNext:!x,persistNow:P,clearPersisted:R,prefillStep:V}}export{B as useEntityWorkflow};
@@ -0,0 +1,234 @@
1
+ # CRUD Components Reference
2
+
3
+ **Import:** `@donotdev/crud`
4
+
5
+ ---
6
+
7
+ ## Hooks
8
+
9
+ ### useCrud
10
+ Single document CRUD actions (add, update, delete, get, subscribe).
11
+
12
+ ```tsx
13
+ const { add, update, delete: remove, get, data, loading, error } = useCrud(carEntity);
14
+ await add({ name: 'Tesla', year: 2024 });
15
+ await remove('doc-id');
16
+ ```
17
+
18
+ ### useCrudList
19
+ Paginated list with automatic loading. For data tables.
20
+
21
+ ```tsx
22
+ const { items, loading, refresh } = useCrudList(productEntity);
23
+ ```
24
+
25
+ ### useCrudCardList
26
+ Card-based list with infinite scroll.
27
+
28
+ ```tsx
29
+ const { items, loading, refresh } = useCrudCardList(articleEntity);
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Form Components
35
+
36
+ ### EntityFormRenderer
37
+ Auto-render full entity form from definition.
38
+
39
+ ```tsx
40
+ <EntityFormRenderer
41
+ entity={productEntity}
42
+ operation="create"
43
+ onSubmit={handleSubmit}
44
+ />
45
+ ```
46
+
47
+ ### FormFieldRenderer
48
+ Render single field. Used inside custom forms.
49
+
50
+ ```tsx
51
+ <FormFieldRenderer field={field} control={form.control} />
52
+ ```
53
+
54
+ ### EntityList
55
+ Data table for entity collection.
56
+
57
+ ```tsx
58
+ <EntityList entity={userEntity} onRowClick={(user) => edit(user.id)} />
59
+ ```
60
+
61
+ ### EntityCardList
62
+ Card grid for entity collection.
63
+
64
+ ```tsx
65
+ <EntityCardList entity={productEntity} renderCard={(item) => <ProductCard {...item} />} />
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Form Building Blocks
71
+
72
+ For custom forms, use these low-level utilities:
73
+
74
+ ```tsx
75
+ import { useEntityForm, getFieldsForOperation, validateEntity } from '@donotdev/crud';
76
+
77
+ const { register, handleSubmit, fields, formState } = useEntityForm(productEntity, {
78
+ operation: 'create'
79
+ });
80
+ ```
81
+
82
+ | Export | Purpose |
83
+ |--------|---------|
84
+ | `useEntityForm` | React Hook Form wrapper for entities |
85
+ | `useEntityField` | Single field hook |
86
+ | `getFieldsForOperation` | Get editable fields for create/edit |
87
+ | `validateEntity` | Validate data against entity schema |
88
+ | `isFieldEditable` | Check if field is editable |
89
+
90
+ ---
91
+
92
+ ## Field Types (Built-in)
93
+
94
+ Field components are auto-rendered by `FormFieldRenderer`. You don't import them directly.
95
+
96
+ ### Text Inputs
97
+ - `text` - Single-line text input
98
+ - `email` - Email input with validation
99
+ - `tel` - Phone number input
100
+ - `url` - URL input
101
+ - `color` - Color picker
102
+ - `password` - Password input (masked)
103
+ - `textarea` - Multi-line text input
104
+ - `richtext` - Rich text editor
105
+
106
+ ### Numbers
107
+ - `number` - Numeric input
108
+ - `range` - Slider input
109
+ - `rating` - Star rating input (1-5, configurable max)
110
+
111
+ **Rating + comment (e.g. reviews):** Use two fields on the same entity - `rating` (type `rating`) for stars and `comment` (type `textarea`) for the text. The form renders them as separate rows; no composite field type needed.
112
+
113
+ ### Boolean
114
+ - `checkbox` - Checkbox input
115
+ - `boolean` - Alias for checkbox
116
+ - `switch` - Toggle switch
117
+
118
+ ### Dates & Time
119
+ - `date` - Date picker
120
+ - `datetime-local` - Date and time picker
121
+ - `time` - Time picker
122
+ - `week` - Week picker
123
+ - `month` - Month picker
124
+ - `timestamp` - Timestamp (Firestore Timestamp)
125
+
126
+ ### Selection
127
+ - `select` - Dropdown select
128
+ - `combobox` - Searchable dropdown
129
+ - `multiselect` - Multiple selection dropdown
130
+ - `radio` - Radio button group
131
+
132
+ ### Files & Media
133
+ - `file` - Single file upload
134
+ - `files` - Multiple file uploads
135
+ - `document` - Document upload (PDF, etc.)
136
+ - `documents` - Multiple document uploads
137
+ - `image` - Single image upload
138
+ - `images` - Multiple image uploads
139
+
140
+ ### Complex Types
141
+ - `geopoint` - Geographic coordinates (lat/lng)
142
+ - `address` - Address input with autocomplete
143
+ - `map` - Map picker
144
+ - `array` - Array of text inputs
145
+
146
+ ### Special
147
+ - `avatar` - Avatar image upload
148
+ - `badge` - Badge display
149
+ - `hidden` - Hidden field (not displayed)
150
+ - `submit` - Submit button (uncontrolled)
151
+ - `reset` - Reset button (uncontrolled)
152
+
153
+ To add custom field types:
154
+ ```tsx
155
+ import { useController, registerFieldType } from '@donotdev/crud';
156
+ import type { ControlledFieldProps } from '@donotdev/crud';
157
+
158
+ // Custom controlled component MUST use framework's useController (not react-hook-form's)
159
+ function ScoreField({
160
+ fieldConfig,
161
+ control,
162
+ errors,
163
+ t,
164
+ onChange
165
+ }: ControlledFieldProps) {
166
+ // REQUIRED: Use framework's useController - ensures type compatibility
167
+ const { field, fieldState } = useController({
168
+ name: fieldConfig.name,
169
+ control: control,
170
+ });
171
+
172
+ return (
173
+ <div>
174
+ <label>{t(fieldConfig.label)}</label>
175
+ {/* Use field.value and field.onChange */}
176
+ <input
177
+ type="number"
178
+ value={field.value ?? 0}
179
+ onChange={(e) => {
180
+ const value = Number(e.target.value);
181
+ field.onChange(value);
182
+ onChange?.(value);
183
+ }}
184
+ min={0}
185
+ max={10}
186
+ />
187
+ {fieldState?.error && (
188
+ <span className="error">{fieldState.error.message}</span>
189
+ )}
190
+ </div>
191
+ );
192
+ }
193
+
194
+ registerFieldType({
195
+ type: 'score',
196
+ controlledComponent: ScoreField,
197
+ });
198
+ ```
199
+
200
+ **Important:**
201
+ - Custom controlled components receive `control` prop, NOT `field` prop
202
+ - You must use **framework's `useController`** (from `@donotdev/crud`), NOT `react-hook-form`'s useController
203
+ - This ensures type compatibility - no type assertions needed
204
+
205
+ ---
206
+
207
+ ## Service & Store
208
+
209
+ Direct access (rarely needed):
210
+
211
+ ```tsx
212
+ import { getCrudService, useCrudStore } from '@donotdev/crud';
213
+
214
+ const service = getCrudService();
215
+ await service.query('products', { where: [['active', '==', true]] });
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Collection Utilities
221
+
222
+ ```tsx
223
+ import { loadDeterministicRange, upsertDeterministic, appendToCollection } from '@donotdev/crud';
224
+ ```
225
+
226
+ | Utility | Purpose |
227
+ |---------|---------|
228
+ | `loadDeterministicRange` | Paginated loading with deterministic IDs |
229
+ | `upsertDeterministic` | Insert or update with deterministic ID |
230
+ | `appendToCollection` | Add to collection end |
231
+
232
+ ---
233
+
234
+ **JSDoc in IDE** - Hover over any import for full props and examples.
@@ -0,0 +1,340 @@
1
+ # CRUD Operations
2
+
3
+ > **API details:** `lookup_symbol("symbolName")` via MCP for full props, return types, and examples from JSDoc.
4
+
5
+ ---
6
+
7
+ ## 1. Define Entity (SSOT)
8
+
9
+ The entity definition drives everything - forms, lists, validation, access, search, sort, backend.
10
+
11
+ ```typescript
12
+ import { defineEntity } from '@donotdev/core';
13
+
14
+ export const productEntity = defineEntity({
15
+ name: 'Product',
16
+ collection: 'products',
17
+ search: { fields: ['name', 'description'] },
18
+ defaultSort: { field: 'createdAt', direction: 'desc' },
19
+ fields: {
20
+ name: { name: 'name', label: 'name', type: 'text', visibility: 'guest', validation: { required: true } },
21
+ price: { name: 'price', label: 'price', type: 'price', visibility: 'guest', validation: { required: true } },
22
+ image: { name: 'image', label: 'image', type: 'image', visibility: 'guest' },
23
+ }
24
+ });
25
+ ```
26
+
27
+ **Auto-added fields:** `id`, `createdAt`, `updatedAt`, `createdById`, `updatedById`, `status`.
28
+
29
+ See `lookup_symbol("defineEntity")` for all options (scope, access, ownership, uniqueKeys, validation).
30
+
31
+ ### Status Field (auto-added)
32
+
33
+ The `status` field is auto-added by `defineEntity()` with sensible defaults:
34
+
35
+ | Property | Default | Can Override? |
36
+ |----------|---------|---------------|
37
+ | `type` | `'select'` | Yes |
38
+ | `visibility` | `'admin'` | Yes |
39
+ | `editable` | `'admin'` | Yes |
40
+ | `required` | `true` | Yes |
41
+
42
+ **Default options:** `draft`, `available`, `deleted` - always present, cannot be removed.
43
+ **Default value:** `available`.
44
+
45
+ If you don't define `status` in your fields at all, the full default is added automatically. If you define it, your properties are merged on top of defaults:
46
+
47
+ ```typescript
48
+ fields: {
49
+ // Minimal: just add custom options (merged after defaults)
50
+ status: {
51
+ validation: {
52
+ options: [
53
+ { value: 'shipped', label: 'Shipped' },
54
+ { value: 'returned', label: 'Returned' },
55
+ ],
56
+ },
57
+ },
58
+ // Result: [draft, available, deleted, shipped, returned]
59
+
60
+ // Full override: all properties respected
61
+ status: {
62
+ visibility: 'super',
63
+ editable: 'super',
64
+ validation: { options: [...] },
65
+ },
66
+ }
67
+ ```
68
+
69
+ > `draft` and `deleted` items are hidden from non-admin users (server-side filtering).
70
+
71
+ ---
72
+
73
+ ## 2. Provider Setup (once)
74
+
75
+ ```typescript
76
+ // config/providers.ts
77
+ import { configureProviders } from '@donotdev/core';
78
+ import { FirestoreAdapter } from '@donotdev/firebase'; // or SupabaseCrudAdapter
79
+
80
+ configureProviders({ crud: new FirestoreAdapter() });
81
+ ```
82
+
83
+ Import in `App.tsx`: `import './config/providers';`
84
+
85
+ ---
86
+
87
+ ## 3. Backend Functions
88
+
89
+ **Firebase:**
90
+ ```typescript
91
+ // functions/src/index.ts
92
+ import { initializeApp } from 'firebase-admin/app';
93
+ import { createCrudFunctions } from '@donotdev/functions/firebase';
94
+ import * as entities from 'entities';
95
+
96
+ initializeApp();
97
+ export const crud = createCrudFunctions(entities);
98
+ ```
99
+
100
+ **Supabase:**
101
+ ```typescript
102
+ // supabase/functions/crud/index.ts
103
+ import * as entities from '../_shared/entities.ts';
104
+ import { createSupabaseCrudFunctions } from '@donotdev/functions/supabase';
105
+
106
+ const { serve } = createSupabaseCrudFunctions(entities);
107
+ Deno.serve(serve);
108
+ ```
109
+
110
+ See the Firebase or Supabase guideline for full function setup.
111
+
112
+ ---
113
+
114
+ ## 4. Use Components
115
+
116
+ Drop components on a page. Entity drives the UI - no configuration needed.
117
+
118
+ ```tsx
119
+ <EntityList entity={productEntity} userRole={user?.role} />
120
+ <EntityCardList entity={productEntity} basePath="/shop" cols={[1, 2, 3, 4]} />
121
+ <EntityFormRenderer entity={productEntity} operation="create" onSubmit={handleSubmit} cancelPath="/products" />
122
+ <EntityDisplayRenderer entity={productEntity} id={id} />
123
+ ```
124
+
125
+ Use `lookup_symbol("ComponentName")` for full props.
126
+
127
+ ---
128
+
129
+ ## 5. Visibility & Access
130
+
131
+ ### Field Visibility (who sees what)
132
+
133
+ | Level | Who |
134
+ |-------|-----|
135
+ | `'guest'` | Everyone |
136
+ | `'user'` | Authenticated |
137
+ | `'admin'` | Admins |
138
+ | `'super'` | Super admins |
139
+ | `'technical'` | Admins only, read-only in forms |
140
+ | `'owner'` | Stakeholders only (see `ownership`) |
141
+ | `'hidden'` | Never |
142
+
143
+ ### Entity Access (who can CRUD)
144
+
145
+ ```typescript
146
+ access: { create: 'admin', read: 'guest', update: 'admin', delete: 'admin' }
147
+ ```
148
+
149
+ ### Ownership
150
+
151
+ For marketplace patterns. See `lookup_symbol("defineEntity")` -> `ownership`.
152
+
153
+ **Firebase:** Enforced by generated secure Firebase Functions (server-side).
154
+ **Supabase:** Enforced via RLS policies - generated by `dndev setup`.
155
+
156
+ ---
157
+
158
+ ## 6. Multi-Tenancy (Scope)
159
+
160
+ ```typescript
161
+ registerScopeProvider('company', () => companyStore.getState().currentCompanyId);
162
+
163
+ export const clientEntity = defineEntity({
164
+ scope: { field: 'companyId', provider: 'company' },
165
+ // ... (companyId auto-added, all CRUD ops auto-scoped)
166
+ });
167
+ ```
168
+
169
+ See `lookup_symbol("registerScopeProvider")`.
170
+
171
+ ---
172
+
173
+ ## 7. Data Fetching & Pagination
174
+
175
+ ### Default: Auto Mode (zero config)
176
+
177
+ ```tsx
178
+ <EntityList entity={productEntity} />
179
+ ```
180
+
181
+ That's it. The framework handles pagination automatically:
182
+
183
+ 1. **First fetch** - loads up to 1000 items client-side (instant search, sort, filter in the browser)
184
+ 2. **If total > 1000** - auto-switches to server pagination (fetches one page at a time via cursor)
185
+
186
+ You never need to configure pagination mode. It just works.
187
+
188
+ ### Forcing a Mode (rare)
189
+
190
+ | Mode | Behavior | When to force |
191
+ |------|----------|---------------|
192
+ | `pagination='auto'` (default) | Client-side up to 1000, auto-switches to server if more | Never - this is the default |
193
+ | `pagination='client'` | Always client-side, fetches all | You know the dataset is small and want instant filters |
194
+ | `pagination='server'` | Always server-side, cursor pagination | You know the dataset is huge and want minimal fetch |
195
+
196
+ ```tsx
197
+ // Force server pagination with custom page size
198
+ <EntityList entity={productEntity} pagination="server" pageSize={50} />
199
+ ```
200
+
201
+ ### What Changes When Auto-Switches to Server
202
+
203
+ | Feature | Client mode (< 1000) | Server mode (> 1000) |
204
+ |---------|----------------------|----------------------|
205
+ | Search | Instant (in-memory) | Re-fetches per query |
206
+ | Sort | Instant | Re-fetches |
207
+ | Filters | Instant | Re-fetches |
208
+ | Page navigation | Instant | Fetches next page |
209
+
210
+ Server mode fetches only `pageSize` items per request - not the whole collection.
211
+
212
+ ---
213
+
214
+ ## What's Available
215
+
216
+ ### Components (`@donotdev/ui`)
217
+
218
+ | Component | One-liner |
219
+ |-----------|-----------|
220
+ | `EntityList` | Table list with search, filters, pagination, routing |
221
+ | `EntityCardList` | Card grid with search, filters, favorites, routing |
222
+ | `EntityFormRenderer` | Auto-generated form from entity (create/edit) |
223
+ | `EntityDisplayRenderer` | Read-only detail view, auto-fetches by ID |
224
+ | `EntityRecommendations` | "You may also like" related items |
225
+
226
+ ### Templates (`@donotdev/templates`)
227
+
228
+ | Template | One-liner |
229
+ |----------|-----------|
230
+ | `ProductCardListTemplate` | Shop card grid with price, image, sale badges |
231
+ | `CarCardListTemplate` | Automotive listing with mileage, year |
232
+ | `CarDetailTemplate` | Car detail with gallery, specs, price |
233
+ | `InquiryFormTemplate` | Contact form (Customer + Inquiry, GDPR) |
234
+ | `InquiryAdminTemplate` | Admin dashboard for inquiries |
235
+ | `HomeTemplate` | Landing page |
236
+ | `LoginTemplate` | Auth login page |
237
+ | `DashboardTemplate` | Admin dashboard |
238
+ | `CheckoutTemplate` | Stripe checkout |
239
+ | `BillingSuccessTemplate` | Post-checkout success |
240
+ | `UserSubscriptionTemplate` | Manage subscription |
241
+
242
+ ### Hooks (`@donotdev/crud`)
243
+
244
+ | Hook | One-liner |
245
+ |------|-----------|
246
+ | `useCrud` | CRUD actions: `add`, `update`, `delete`, `get`, `set`, `query` |
247
+ | `useCrudList` | Real-time list with search, filters, sort applied |
248
+ | `useCrudCardList` | Same as `useCrudList`, optimized for public card views |
249
+ | `useCrudFilters` | Filter state per collection, auto-consumed by list hooks |
250
+ | `useEntityForm` | Form state for custom form layouts |
251
+ | `useEntityField` | Single-field control for custom form layouts |
252
+ | `useEntityFavorites` | Local favorites (localStorage) |
253
+ | `useRelatedItems` | Fetch related items by reference field |
254
+ | `useFileUpload` | File upload with progress tracking |
255
+ | `useUnsavedChangesWarning` | Warn before leaving with unsaved changes |
256
+
257
+ ### Utilities (`@donotdev/crud`)
258
+
259
+ | Utility | One-liner |
260
+ |---------|-----------|
261
+ | `formatValue` | Format any field value for display |
262
+ | `applyFilters` / `applySearch` / `applySort` | Processing pipeline (what `useCrudList` does internally) |
263
+ | `registerFieldType` | Register custom field type |
264
+ | `validateEntity` | Validate entity data against schemas |
265
+ | `isFieldEditable` / `getFieldsForOperation` | Field visibility helpers |
266
+
267
+ ### Routing (`@donotdev/ui`)
268
+
269
+ | Symbol | One-liner |
270
+ |--------|-----------|
271
+ | `useNavigate` | Programmatic navigation (Vite/Next.js auto-detected) |
272
+ | `useParams` | Read route params |
273
+ | `Link` | Declarative navigation |
274
+ | `AuthGuard` | Protect routes by auth + role |
275
+
276
+ **Convention:** `/${collection}` (list) - `/${collection}/new` (create) - `/${collection}/:id` (detail/edit)
277
+
278
+ ---
279
+
280
+ ## Built-in Field Types
281
+
282
+ | Category | Types |
283
+ |----------|-------|
284
+ | **Text** | `text`, `email`, `tel`, `url`, `color`, `password`, `textarea`, `richtext` |
285
+ | **Number** | `number`, `currency`, `price`, `range`, `year` |
286
+ | **Boolean** | `checkbox`, `boolean`, `switch` |
287
+ | **Date/Time** | `date`, `datetime-local`, `time`, `week`, `month`, `timestamp` |
288
+ | **Selection** | `select`, `combobox`, `multiselect`, `radio` |
289
+ | **Files** | `file`, `files`, `document`, `documents`, `image`, `images` |
290
+ | **Complex** | `geopoint`, `address`, `map`, `array` |
291
+ | **Special** | `avatar`, `badge`, `hidden`, `submit`, `reset` |
292
+
293
+ ---
294
+
295
+ ## Custom Field Types (escape hatch)
296
+
297
+ When built-in types don't fit, register your own with `registerFieldType`. One call wires form component + display formatter + filter.
298
+
299
+ ```typescript
300
+ import { registerFieldType, useController } from '@donotdev/crud';
301
+ import type { ControlledFieldProps } from '@donotdev/crud';
302
+
303
+ function StatusTierField({ fieldConfig, control, t }: ControlledFieldProps) {
304
+ const { field, fieldState } = useController({ name: fieldConfig.name, control });
305
+ return (
306
+ <select value={field.value ?? ''} onChange={(e) => field.onChange(e.target.value)}>
307
+ <option value="basic">Basic</option>
308
+ <option value="premium">Premium</option>
309
+ </select>
310
+ );
311
+ }
312
+
313
+ registerFieldType({
314
+ type: 'statusTier',
315
+ controlledComponent: StatusTierField,
316
+ displayFormatter: (value) => value ? String(value).charAt(0).toUpperCase() + String(value).slice(1) : '-',
317
+ filterable: true,
318
+ filterType: 'select',
319
+ });
320
+ ```
321
+
322
+ Then use in entity: `tier: { name: 'tier', label: 'tier', type: 'statusTier', visibility: 'guest' }`
323
+
324
+ See `lookup_symbol("registerFieldType")`, `lookup_symbol("ControlledFieldProps")`.
325
+
326
+ ---
327
+
328
+ ## i18n
329
+
330
+ **Namespace:** `entity-${entity.name.toLowerCase()}` (customizable via `namespace`).
331
+
332
+ ```json
333
+ { "fields": { "name": "Product Name", "price": "Price" }, "name": "Product" }
334
+ ```
335
+
336
+ Status labels: entity namespace -> `crud` namespace fallback.
337
+
338
+ ---
339
+
340
+ **Define entity -> register provider -> register functions -> drop components. Entity is the SSOT - everything flows from it.**