@blueprint-ts/core 4.1.0-beta.2 → 4.1.0-beta.3

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 (509) hide show
  1. package/dist/bulkRequests/BulkRequestEvent.enum.d.ts +4 -0
  2. package/dist/bulkRequests/BulkRequestEvent.enum.js +5 -0
  3. package/dist/bulkRequests/BulkRequestSender.d.ts +31 -0
  4. package/dist/bulkRequests/BulkRequestSender.js +161 -0
  5. package/dist/bulkRequests/BulkRequestWrapper.d.ts +15 -0
  6. package/dist/bulkRequests/BulkRequestWrapper.js +50 -0
  7. package/dist/bulkRequests/index.d.ts +5 -0
  8. package/dist/bulkRequests/index.js +5 -0
  9. package/{src/laravel/pagination/contracts/PaginationResponseBodyContract.ts → dist/laravel/pagination/contracts/PaginationResponseBodyContract.d.ts} +4 -4
  10. package/dist/laravel/pagination/contracts/PaginationResponseBodyContract.js +1 -0
  11. package/dist/laravel/pagination/dataDrivers/RequestDriver.d.ts +10 -0
  12. package/dist/laravel/pagination/dataDrivers/RequestDriver.js +18 -0
  13. package/dist/laravel/pagination/index.d.ts +4 -0
  14. package/dist/laravel/pagination/index.js +2 -0
  15. package/dist/laravel/requests/JsonBaseRequest.d.ts +14 -0
  16. package/dist/laravel/requests/JsonBaseRequest.js +15 -0
  17. package/dist/laravel/requests/PaginationJsonBaseRequest.d.ts +8 -0
  18. package/dist/laravel/requests/PaginationJsonBaseRequest.js +13 -0
  19. package/dist/laravel/requests/index.d.ts +7 -0
  20. package/dist/laravel/requests/index.js +5 -0
  21. package/dist/laravel/requests/responses/JsonResponse.d.ts +5 -0
  22. package/dist/laravel/requests/responses/JsonResponse.js +6 -0
  23. package/dist/laravel/requests/responses/PaginationResponse.d.ts +7 -0
  24. package/dist/laravel/requests/responses/PaginationResponse.js +9 -0
  25. package/dist/pagination/BasePaginator.d.ts +19 -0
  26. package/dist/pagination/BasePaginator.js +65 -0
  27. package/dist/pagination/InfiniteScroller.d.ts +6 -0
  28. package/dist/pagination/InfiniteScroller.js +17 -0
  29. package/dist/pagination/PageAwarePaginator.d.ts +32 -0
  30. package/dist/pagination/PageAwarePaginator.js +86 -0
  31. package/dist/pagination/StatePaginator.d.ts +25 -0
  32. package/dist/pagination/StatePaginator.js +55 -0
  33. package/dist/pagination/contracts/BaseViewDriverContract.d.ts +6 -0
  34. package/dist/pagination/contracts/BaseViewDriverContract.js +1 -0
  35. package/{src/pagination/contracts/BaseViewDriverFactoryContract.ts → dist/pagination/contracts/BaseViewDriverFactoryContract.d.ts} +2 -3
  36. package/dist/pagination/contracts/BaseViewDriverFactoryContract.js +1 -0
  37. package/dist/pagination/contracts/PaginateableRequestContract.d.ts +4 -0
  38. package/dist/pagination/contracts/PaginateableRequestContract.js +1 -0
  39. package/dist/pagination/contracts/PaginationDataDriverContract.d.ts +4 -0
  40. package/dist/pagination/contracts/PaginationDataDriverContract.js +1 -0
  41. package/{src/pagination/contracts/PaginationResponseContract.ts → dist/pagination/contracts/PaginationResponseContract.d.ts} +3 -5
  42. package/dist/pagination/contracts/PaginationResponseContract.js +1 -0
  43. package/{src/pagination/contracts/PaginatorLoadDataOptions.ts → dist/pagination/contracts/PaginatorLoadDataOptions.d.ts} +2 -2
  44. package/dist/pagination/contracts/PaginatorLoadDataOptions.js +1 -0
  45. package/{src/pagination/contracts/StatePaginationDataDriverContract.ts → dist/pagination/contracts/StatePaginationDataDriverContract.d.ts} +2 -3
  46. package/dist/pagination/contracts/StatePaginationDataDriverContract.js +1 -0
  47. package/dist/pagination/contracts/ViewDriverContract.d.ts +9 -0
  48. package/dist/pagination/contracts/ViewDriverContract.js +1 -0
  49. package/dist/pagination/contracts/ViewDriverFactoryContract.d.ts +4 -0
  50. package/dist/pagination/contracts/ViewDriverFactoryContract.js +1 -0
  51. package/dist/pagination/dataDrivers/ArrayDriver.d.ts +9 -0
  52. package/dist/pagination/dataDrivers/ArrayDriver.js +20 -0
  53. package/dist/pagination/dtos/PaginationDataDto.d.ts +7 -0
  54. package/dist/pagination/dtos/PaginationDataDto.js +12 -0
  55. package/dist/pagination/dtos/StatePaginationDataDto.d.ts +7 -0
  56. package/dist/pagination/dtos/StatePaginationDataDto.js +13 -0
  57. package/dist/pagination/factories/VueBaseViewDriverFactory.d.ts +5 -0
  58. package/dist/pagination/factories/VueBaseViewDriverFactory.js +6 -0
  59. package/dist/pagination/factories/VuePaginationDriverFactory.d.ts +5 -0
  60. package/dist/pagination/factories/VuePaginationDriverFactory.js +6 -0
  61. package/dist/pagination/frontendDrivers/VueBaseViewDriver.d.ts +11 -0
  62. package/dist/pagination/frontendDrivers/VueBaseViewDriver.js +19 -0
  63. package/dist/pagination/frontendDrivers/VuePaginationDriver.d.ts +21 -0
  64. package/dist/pagination/frontendDrivers/VuePaginationDriver.js +41 -0
  65. package/dist/pagination/index.d.ts +22 -0
  66. package/dist/pagination/index.js +13 -0
  67. package/dist/persistenceDrivers/LocalStorageDriver.d.ts +9 -0
  68. package/dist/persistenceDrivers/LocalStorageDriver.js +18 -0
  69. package/dist/persistenceDrivers/NonPersistentDriver.d.ts +7 -0
  70. package/dist/persistenceDrivers/NonPersistentDriver.js +8 -0
  71. package/dist/persistenceDrivers/SessionStorageDriver.d.ts +9 -0
  72. package/dist/persistenceDrivers/SessionStorageDriver.js +18 -0
  73. package/dist/persistenceDrivers/index.d.ts +6 -0
  74. package/dist/persistenceDrivers/index.js +4 -0
  75. package/dist/persistenceDrivers/types/PersistenceDriver.d.ts +5 -0
  76. package/dist/persistenceDrivers/types/PersistenceDriver.js +1 -0
  77. package/dist/requests/BaseRequest.d.ts +62 -0
  78. package/dist/requests/BaseRequest.js +224 -0
  79. package/dist/requests/ErrorHandler.d.ts +11 -0
  80. package/dist/requests/ErrorHandler.js +127 -0
  81. package/dist/requests/RequestConcurrencyMode.enum.d.ts +6 -0
  82. package/dist/requests/RequestConcurrencyMode.enum.js +7 -0
  83. package/dist/requests/RequestErrorRouter.d.ts +38 -0
  84. package/dist/requests/RequestErrorRouter.js +38 -0
  85. package/dist/requests/RequestEvents.enum.d.ts +4 -0
  86. package/dist/requests/RequestEvents.enum.js +5 -0
  87. package/dist/requests/RequestMethod.enum.d.ts +8 -0
  88. package/dist/requests/RequestMethod.enum.js +9 -0
  89. package/dist/requests/bodies/BinaryBody.d.ts +10 -0
  90. package/dist/requests/bodies/BinaryBody.js +22 -0
  91. package/dist/requests/bodies/FormDataBody.d.ts +14 -0
  92. package/dist/requests/bodies/FormDataBody.js +60 -0
  93. package/dist/requests/bodies/JsonBody.d.ts +8 -0
  94. package/dist/requests/bodies/JsonBody.js +13 -0
  95. package/{src/requests/contracts/AbortableRequestContract.ts → dist/requests/contracts/AbortableRequestContract.d.ts} +1 -1
  96. package/dist/requests/contracts/AbortableRequestContract.js +1 -0
  97. package/dist/requests/contracts/BaseRequestContract.d.ts +23 -0
  98. package/dist/requests/contracts/BaseRequestContract.js +1 -0
  99. package/dist/requests/contracts/BodyContract.d.ts +6 -0
  100. package/dist/requests/contracts/BodyContract.js +1 -0
  101. package/dist/requests/contracts/BodyFactoryContract.d.ts +4 -0
  102. package/dist/requests/contracts/BodyFactoryContract.js +1 -0
  103. package/dist/requests/contracts/DriverConfigContract.d.ts +8 -0
  104. package/dist/requests/contracts/DriverConfigContract.js +1 -0
  105. package/dist/requests/contracts/HeadersContract.d.ts +7 -0
  106. package/dist/requests/contracts/HeadersContract.js +1 -0
  107. package/dist/requests/contracts/RequestDriverContract.d.ts +8 -0
  108. package/dist/requests/contracts/RequestDriverContract.js +1 -0
  109. package/dist/requests/contracts/RequestLoaderContract.d.ts +4 -0
  110. package/dist/requests/contracts/RequestLoaderContract.js +1 -0
  111. package/{src/requests/contracts/RequestLoaderFactoryContract.ts → dist/requests/contracts/RequestLoaderFactoryContract.d.ts} +2 -3
  112. package/dist/requests/contracts/RequestLoaderFactoryContract.js +1 -0
  113. package/dist/requests/contracts/ResponseContract.d.ts +5 -0
  114. package/dist/requests/contracts/ResponseContract.js +1 -0
  115. package/dist/requests/drivers/contracts/ResponseHandlerContract.d.ts +9 -0
  116. package/dist/requests/drivers/contracts/ResponseHandlerContract.js +1 -0
  117. package/dist/requests/drivers/fetch/FetchDriver.d.ts +26 -0
  118. package/dist/requests/drivers/fetch/FetchDriver.js +73 -0
  119. package/dist/requests/drivers/fetch/FetchResponse.d.ts +12 -0
  120. package/dist/requests/drivers/fetch/FetchResponse.js +38 -0
  121. package/dist/requests/drivers/xhr/XMLHttpRequestDriver.d.ts +13 -0
  122. package/dist/requests/drivers/xhr/XMLHttpRequestDriver.js +107 -0
  123. package/dist/requests/drivers/xhr/XMLHttpRequestResponse.d.ts +17 -0
  124. package/dist/requests/drivers/xhr/XMLHttpRequestResponse.js +84 -0
  125. package/dist/requests/exceptions/BadGatewayException.d.ts +3 -0
  126. package/dist/requests/exceptions/BadGatewayException.js +3 -0
  127. package/dist/requests/exceptions/BadRequestException.d.ts +3 -0
  128. package/dist/requests/exceptions/BadRequestException.js +3 -0
  129. package/dist/requests/exceptions/ConflictException.d.ts +3 -0
  130. package/dist/requests/exceptions/ConflictException.js +3 -0
  131. package/dist/requests/exceptions/ForbiddenException.d.ts +3 -0
  132. package/dist/requests/exceptions/ForbiddenException.js +3 -0
  133. package/dist/requests/exceptions/GatewayTimeoutException.d.ts +3 -0
  134. package/dist/requests/exceptions/GatewayTimeoutException.js +3 -0
  135. package/dist/requests/exceptions/GoneException.d.ts +3 -0
  136. package/dist/requests/exceptions/GoneException.js +3 -0
  137. package/dist/requests/exceptions/InvalidJsonException.d.ts +7 -0
  138. package/dist/requests/exceptions/InvalidJsonException.js +10 -0
  139. package/dist/requests/exceptions/LockedException.d.ts +3 -0
  140. package/dist/requests/exceptions/LockedException.js +3 -0
  141. package/dist/requests/exceptions/MethodNotAllowedException.d.ts +3 -0
  142. package/dist/requests/exceptions/MethodNotAllowedException.js +3 -0
  143. package/dist/requests/exceptions/NoResponseReceivedException.d.ts +3 -0
  144. package/{src/requests/exceptions/NoResponseReceivedException.ts → dist/requests/exceptions/NoResponseReceivedException.js} +3 -3
  145. package/dist/requests/exceptions/NotFoundException.d.ts +3 -0
  146. package/dist/requests/exceptions/NotFoundException.js +3 -0
  147. package/dist/requests/exceptions/NotImplementedException.d.ts +3 -0
  148. package/dist/requests/exceptions/NotImplementedException.js +3 -0
  149. package/dist/requests/exceptions/PageExpiredException.d.ts +3 -0
  150. package/dist/requests/exceptions/PageExpiredException.js +3 -0
  151. package/dist/requests/exceptions/PayloadTooLargeException.d.ts +3 -0
  152. package/dist/requests/exceptions/PayloadTooLargeException.js +3 -0
  153. package/dist/requests/exceptions/PreconditionFailedException.d.ts +3 -0
  154. package/dist/requests/exceptions/PreconditionFailedException.js +3 -0
  155. package/dist/requests/exceptions/RequestTimeoutException.d.ts +3 -0
  156. package/dist/requests/exceptions/RequestTimeoutException.js +3 -0
  157. package/dist/requests/exceptions/ResponseBodyException.d.ts +7 -0
  158. package/dist/requests/exceptions/ResponseBodyException.js +10 -0
  159. package/dist/requests/exceptions/ResponseException.d.ts +6 -0
  160. package/dist/requests/exceptions/ResponseException.js +9 -0
  161. package/dist/requests/exceptions/ServerErrorException.d.ts +3 -0
  162. package/dist/requests/exceptions/ServerErrorException.js +3 -0
  163. package/dist/requests/exceptions/ServiceUnavailableException.d.ts +3 -0
  164. package/dist/requests/exceptions/ServiceUnavailableException.js +3 -0
  165. package/dist/requests/exceptions/StaleResponseException.d.ts +5 -0
  166. package/dist/requests/exceptions/StaleResponseException.js +10 -0
  167. package/dist/requests/exceptions/TooManyRequestsException.d.ts +3 -0
  168. package/dist/requests/exceptions/TooManyRequestsException.js +3 -0
  169. package/dist/requests/exceptions/UnauthorizedException.d.ts +3 -0
  170. package/dist/requests/exceptions/UnauthorizedException.js +3 -0
  171. package/dist/requests/exceptions/UnsupportedMediaTypeException.d.ts +3 -0
  172. package/dist/requests/exceptions/UnsupportedMediaTypeException.js +3 -0
  173. package/dist/requests/exceptions/ValidationException.d.ts +3 -0
  174. package/dist/requests/exceptions/ValidationException.js +3 -0
  175. package/dist/requests/exceptions/index.d.ts +25 -0
  176. package/dist/requests/exceptions/index.js +25 -0
  177. package/dist/requests/factories/BinaryBodyFactory.d.ts +8 -0
  178. package/dist/requests/factories/BinaryBodyFactory.js +9 -0
  179. package/dist/requests/factories/FormDataFactory.d.ts +12 -0
  180. package/dist/requests/factories/FormDataFactory.js +6 -0
  181. package/dist/requests/factories/JsonBodyFactory.d.ts +5 -0
  182. package/dist/requests/factories/JsonBodyFactory.js +6 -0
  183. package/dist/requests/index.d.ts +31 -0
  184. package/dist/requests/index.js +19 -0
  185. package/dist/requests/responses/BaseResponse.d.ts +14 -0
  186. package/dist/requests/responses/BaseResponse.js +36 -0
  187. package/dist/requests/responses/BlobResponse.d.ts +7 -0
  188. package/dist/requests/responses/BlobResponse.js +16 -0
  189. package/dist/requests/responses/JsonResponse.d.ts +5 -0
  190. package/dist/requests/responses/JsonResponse.js +12 -0
  191. package/dist/requests/responses/PlainTextResponse.d.ts +5 -0
  192. package/dist/requests/responses/PlainTextResponse.js +12 -0
  193. package/{src/requests/types/RequestConcurrencyOptions.ts → dist/requests/types/RequestConcurrencyOptions.d.ts} +4 -5
  194. package/dist/requests/types/RequestConcurrencyOptions.js +1 -0
  195. package/dist/requests/types/RequestUploadProgress.d.ts +6 -0
  196. package/dist/requests/types/RequestUploadProgress.js +1 -0
  197. package/dist/support/DeferredPromise.d.ts +37 -0
  198. package/dist/support/DeferredPromise.js +55 -0
  199. package/dist/support/helpers.d.ts +5 -0
  200. package/dist/support/helpers.js +69 -0
  201. package/{src/support/index.ts → dist/support/index.d.ts} +3 -4
  202. package/dist/support/index.js +3 -0
  203. package/dist/vue/composables/useConfirmDialog.d.ts +20 -0
  204. package/dist/vue/composables/useConfirmDialog.js +52 -0
  205. package/dist/vue/composables/useGlobalCheckbox.d.ts +13 -0
  206. package/dist/vue/composables/useGlobalCheckbox.js +123 -0
  207. package/dist/vue/composables/useIsEmpty.d.ts +4 -0
  208. package/dist/vue/composables/useIsEmpty.js +27 -0
  209. package/dist/vue/composables/useIsOpen.d.ts +5 -0
  210. package/dist/vue/composables/useIsOpen.js +25 -0
  211. package/dist/vue/composables/useIsOpenFromVar.d.ts +6 -0
  212. package/dist/vue/composables/useIsOpenFromVar.js +45 -0
  213. package/dist/vue/composables/useModelWrapper.d.ts +9 -0
  214. package/dist/vue/composables/useModelWrapper.js +18 -0
  215. package/dist/vue/composables/useOnOpen.d.ts +7 -0
  216. package/dist/vue/composables/useOnOpen.js +25 -0
  217. package/{src/vue/contracts/ModelValueOptions.ts → dist/vue/contracts/ModelValueOptions.d.ts} +1 -1
  218. package/dist/vue/contracts/ModelValueOptions.js +1 -0
  219. package/dist/vue/contracts/ModelValueProps.d.ts +3 -0
  220. package/dist/vue/contracts/ModelValueProps.js +1 -0
  221. package/dist/vue/forms/BaseForm.d.ts +162 -0
  222. package/dist/vue/forms/BaseForm.js +997 -0
  223. package/dist/vue/forms/PropertyAwareArray.d.ts +53 -0
  224. package/dist/vue/forms/PropertyAwareArray.js +54 -0
  225. package/{src/vue/forms/index.ts → dist/vue/forms/index.d.ts} +9 -11
  226. package/dist/vue/forms/index.js +6 -0
  227. package/dist/vue/forms/types/PersistedForm.d.ts +6 -0
  228. package/dist/vue/forms/types/PersistedForm.js +1 -0
  229. package/dist/vue/forms/validation/ValidationMode.enum.d.ts +11 -0
  230. package/dist/vue/forms/validation/ValidationMode.enum.js +14 -0
  231. package/dist/vue/forms/validation/index.d.ts +12 -0
  232. package/dist/vue/forms/validation/index.js +9 -0
  233. package/dist/vue/forms/validation/rules/BaseRule.d.ts +5 -0
  234. package/dist/vue/forms/validation/rules/BaseRule.js +5 -0
  235. package/dist/vue/forms/validation/rules/ConfirmedRule.d.ts +10 -0
  236. package/dist/vue/forms/validation/rules/ConfirmedRule.js +26 -0
  237. package/dist/vue/forms/validation/rules/EmailRule.d.ts +7 -0
  238. package/dist/vue/forms/validation/rules/EmailRule.js +19 -0
  239. package/dist/vue/forms/validation/rules/JsonRule.d.ts +7 -0
  240. package/dist/vue/forms/validation/rules/JsonRule.js +25 -0
  241. package/dist/vue/forms/validation/rules/MinRule.d.ts +26 -0
  242. package/dist/vue/forms/validation/rules/MinRule.js +52 -0
  243. package/dist/vue/forms/validation/rules/RequiredRule.d.ts +7 -0
  244. package/dist/vue/forms/validation/rules/RequiredRule.js +16 -0
  245. package/dist/vue/forms/validation/rules/UrlRule.d.ts +7 -0
  246. package/dist/vue/forms/validation/rules/UrlRule.js +22 -0
  247. package/{src/vue/forms/validation/types/BidirectionalRule.ts → dist/vue/forms/validation/types/BidirectionalRule.d.ts} +4 -4
  248. package/dist/vue/forms/validation/types/BidirectionalRule.js +1 -0
  249. package/dist/vue/forms/validation/types/ValidationRules.d.ts +11 -0
  250. package/dist/vue/forms/validation/types/ValidationRules.js +1 -0
  251. package/dist/vue/index.d.ts +11 -0
  252. package/dist/vue/index.js +10 -0
  253. package/dist/vue/requests/factories/VueRequestLoaderFactory.d.ts +6 -0
  254. package/dist/vue/requests/factories/VueRequestLoaderFactory.js +6 -0
  255. package/{src/vue/requests/index.ts → dist/vue/requests/index.d.ts} +4 -5
  256. package/dist/vue/requests/index.js +4 -0
  257. package/dist/vue/requests/loaders/VueRequestBatchLoader.d.ts +12 -0
  258. package/dist/vue/requests/loaders/VueRequestBatchLoader.js +29 -0
  259. package/dist/vue/requests/loaders/VueRequestLoader.d.ts +8 -0
  260. package/dist/vue/requests/loaders/VueRequestLoader.js +12 -0
  261. package/dist/vue/router/routeResourceBinding/RouteResourceBoundView.d.ts +57 -0
  262. package/dist/vue/router/routeResourceBinding/RouteResourceBoundView.js +135 -0
  263. package/dist/vue/router/routeResourceBinding/RouteResourceRequestResolver.d.ts +6 -0
  264. package/dist/vue/router/routeResourceBinding/RouteResourceRequestResolver.js +20 -0
  265. package/dist/vue/router/routeResourceBinding/defineRoute.d.ts +23 -0
  266. package/dist/vue/router/routeResourceBinding/defineRoute.js +42 -0
  267. package/dist/vue/router/routeResourceBinding/index.d.ts +8 -0
  268. package/dist/vue/router/routeResourceBinding/index.js +6 -0
  269. package/dist/vue/router/routeResourceBinding/installRouteInjection.d.ts +14 -0
  270. package/dist/vue/router/routeResourceBinding/installRouteInjection.js +133 -0
  271. package/dist/vue/router/routeResourceBinding/types.d.ts +55 -0
  272. package/dist/vue/router/routeResourceBinding/types.js +1 -0
  273. package/dist/vue/router/routeResourceBinding/useRouteResource.d.ts +8 -0
  274. package/dist/vue/router/routeResourceBinding/useRouteResource.js +29 -0
  275. package/dist/vue/state/State.d.ts +75 -0
  276. package/dist/vue/state/State.js +267 -0
  277. package/dist/vue/state/index.d.ts +2 -0
  278. package/dist/vue/state/index.js +2 -0
  279. package/package.json +81 -23
  280. package/.editorconfig +0 -508
  281. package/.eslintrc.cjs +0 -15
  282. package/.prettierrc.json +0 -8
  283. package/CHANGELOG.md +0 -226
  284. package/docker-compose.yaml +0 -8
  285. package/docs/.vitepress/config.ts +0 -124
  286. package/docs/index.md +0 -13
  287. package/docs/laravel/pagination.md +0 -67
  288. package/docs/laravel/requests.md +0 -62
  289. package/docs/services/pagination/index.md +0 -46
  290. package/docs/services/pagination/infinite-scroller.md +0 -20
  291. package/docs/services/pagination/page-aware.md +0 -51
  292. package/docs/services/pagination/state-pagination.md +0 -77
  293. package/docs/services/pagination/updating-rows.md +0 -52
  294. package/docs/services/persistence/index.md +0 -46
  295. package/docs/services/requests/abort-requests.md +0 -29
  296. package/docs/services/requests/bulk-requests.md +0 -70
  297. package/docs/services/requests/concurrency.md +0 -58
  298. package/docs/services/requests/drivers.md +0 -115
  299. package/docs/services/requests/error-handling.md +0 -153
  300. package/docs/services/requests/events.md +0 -53
  301. package/docs/services/requests/file-uploads.md +0 -168
  302. package/docs/services/requests/getting-started.md +0 -201
  303. package/docs/services/requests/headers.md +0 -40
  304. package/docs/services/requests/loading.md +0 -63
  305. package/docs/services/requests/request-bodies.md +0 -89
  306. package/docs/services/requests/responses.md +0 -34
  307. package/docs/services/support/deferred-promise.md +0 -63
  308. package/docs/services/support/helpers.md +0 -77
  309. package/docs/services/support/index.md +0 -6
  310. package/docs/upgrading/v1-to-v2.md +0 -64
  311. package/docs/upgrading/v2-to-v3.md +0 -52
  312. package/docs/upgrading/v3-to-v4.md +0 -214
  313. package/docs/upgrading.md +0 -0
  314. package/docs/vue/composables/use-confirm-dialog.md +0 -96
  315. package/docs/vue/composables/use-global-checkbox.md +0 -73
  316. package/docs/vue/composables/use-is-empty.md +0 -26
  317. package/docs/vue/composables/use-is-open-from-var.md +0 -32
  318. package/docs/vue/composables/use-is-open.md +0 -28
  319. package/docs/vue/composables/use-model-wrapper.md +0 -29
  320. package/docs/vue/composables/use-on-open.md +0 -26
  321. package/docs/vue/forms/arrays.md +0 -102
  322. package/docs/vue/forms/errors.md +0 -52
  323. package/docs/vue/forms/index.md +0 -99
  324. package/docs/vue/forms/payloads.md +0 -99
  325. package/docs/vue/forms/persistence.md +0 -19
  326. package/docs/vue/forms/state-and-properties.md +0 -26
  327. package/docs/vue/forms/utilities.md +0 -27
  328. package/docs/vue/forms/validation.md +0 -189
  329. package/docs/vue/requests/loading.md +0 -51
  330. package/docs/vue/router/route-resource-binding.md +0 -240
  331. package/docs/vue/state.md +0 -309
  332. package/env.d.ts +0 -1
  333. package/eslint.config.js +0 -15
  334. package/release-tool.json +0 -26
  335. package/src/bulkRequests/BulkRequestEvent.enum.ts +0 -4
  336. package/src/bulkRequests/BulkRequestSender.ts +0 -196
  337. package/src/bulkRequests/BulkRequestWrapper.ts +0 -49
  338. package/src/bulkRequests/index.ts +0 -6
  339. package/src/laravel/pagination/dataDrivers/RequestDriver.ts +0 -30
  340. package/src/laravel/pagination/index.ts +0 -6
  341. package/src/laravel/requests/JsonBaseRequest.ts +0 -35
  342. package/src/laravel/requests/PaginationJsonBaseRequest.ts +0 -29
  343. package/src/laravel/requests/index.ts +0 -9
  344. package/src/laravel/requests/responses/JsonResponse.ts +0 -8
  345. package/src/laravel/requests/responses/PaginationResponse.ts +0 -16
  346. package/src/pagination/BasePaginator.ts +0 -94
  347. package/src/pagination/InfiniteScroller.ts +0 -22
  348. package/src/pagination/PageAwarePaginator.ts +0 -132
  349. package/src/pagination/StatePaginator.ts +0 -86
  350. package/src/pagination/contracts/BaseViewDriverContract.ts +0 -6
  351. package/src/pagination/contracts/PaginateableRequestContract.ts +0 -13
  352. package/src/pagination/contracts/PaginationDataDriverContract.ts +0 -5
  353. package/src/pagination/contracts/ViewDriverContract.ts +0 -10
  354. package/src/pagination/contracts/ViewDriverFactoryContract.ts +0 -5
  355. package/src/pagination/dataDrivers/ArrayDriver.ts +0 -28
  356. package/src/pagination/dtos/PaginationDataDto.ts +0 -14
  357. package/src/pagination/dtos/StatePaginationDataDto.ts +0 -19
  358. package/src/pagination/factories/VueBaseViewDriverFactory.ts +0 -9
  359. package/src/pagination/factories/VuePaginationDriverFactory.ts +0 -9
  360. package/src/pagination/frontendDrivers/VueBaseViewDriver.ts +0 -28
  361. package/src/pagination/frontendDrivers/VuePaginationDriver.ts +0 -61
  362. package/src/pagination/index.ts +0 -46
  363. package/src/persistenceDrivers/LocalStorageDriver.ts +0 -22
  364. package/src/persistenceDrivers/NonPersistentDriver.ts +0 -12
  365. package/src/persistenceDrivers/SessionStorageDriver.ts +0 -22
  366. package/src/persistenceDrivers/index.ts +0 -8
  367. package/src/persistenceDrivers/types/PersistenceDriver.ts +0 -5
  368. package/src/requests/BaseRequest.ts +0 -321
  369. package/src/requests/ErrorHandler.ts +0 -144
  370. package/src/requests/RequestConcurrencyMode.enum.ts +0 -6
  371. package/src/requests/RequestErrorRouter.ts +0 -89
  372. package/src/requests/RequestEvents.enum.ts +0 -4
  373. package/src/requests/RequestMethod.enum.ts +0 -8
  374. package/src/requests/bodies/BinaryBody.ts +0 -31
  375. package/src/requests/bodies/FormDataBody.ts +0 -81
  376. package/src/requests/bodies/JsonBody.ts +0 -16
  377. package/src/requests/contracts/BaseRequestContract.ts +0 -39
  378. package/src/requests/contracts/BodyContract.ts +0 -9
  379. package/src/requests/contracts/BodyFactoryContract.ts +0 -5
  380. package/src/requests/contracts/DriverConfigContract.ts +0 -9
  381. package/src/requests/contracts/HeadersContract.ts +0 -9
  382. package/src/requests/contracts/RequestDriverContract.ts +0 -15
  383. package/src/requests/contracts/RequestLoaderContract.ts +0 -5
  384. package/src/requests/contracts/ResponseContract.ts +0 -7
  385. package/src/requests/drivers/contracts/ResponseHandlerContract.ts +0 -10
  386. package/src/requests/drivers/fetch/FetchDriver.ts +0 -115
  387. package/src/requests/drivers/fetch/FetchResponse.ts +0 -30
  388. package/src/requests/drivers/xhr/XMLHttpRequestDriver.ts +0 -138
  389. package/src/requests/drivers/xhr/XMLHttpRequestResponse.ts +0 -95
  390. package/src/requests/exceptions/BadGatewayException.ts +0 -3
  391. package/src/requests/exceptions/BadRequestException.ts +0 -3
  392. package/src/requests/exceptions/ConflictException.ts +0 -3
  393. package/src/requests/exceptions/ForbiddenException.ts +0 -3
  394. package/src/requests/exceptions/GatewayTimeoutException.ts +0 -3
  395. package/src/requests/exceptions/GoneException.ts +0 -3
  396. package/src/requests/exceptions/InvalidJsonException.ts +0 -15
  397. package/src/requests/exceptions/LockedException.ts +0 -3
  398. package/src/requests/exceptions/MethodNotAllowedException.ts +0 -3
  399. package/src/requests/exceptions/NotFoundException.ts +0 -3
  400. package/src/requests/exceptions/NotImplementedException.ts +0 -3
  401. package/src/requests/exceptions/PageExpiredException.ts +0 -3
  402. package/src/requests/exceptions/PayloadTooLargeException.ts +0 -3
  403. package/src/requests/exceptions/PreconditionFailedException.ts +0 -3
  404. package/src/requests/exceptions/RequestTimeoutException.ts +0 -3
  405. package/src/requests/exceptions/ResponseBodyException.ts +0 -15
  406. package/src/requests/exceptions/ResponseException.ts +0 -11
  407. package/src/requests/exceptions/ServerErrorException.ts +0 -3
  408. package/src/requests/exceptions/ServiceUnavailableException.ts +0 -3
  409. package/src/requests/exceptions/StaleResponseException.ts +0 -13
  410. package/src/requests/exceptions/TooManyRequestsException.ts +0 -3
  411. package/src/requests/exceptions/UnauthorizedException.ts +0 -3
  412. package/src/requests/exceptions/UnsupportedMediaTypeException.ts +0 -3
  413. package/src/requests/exceptions/ValidationException.ts +0 -3
  414. package/src/requests/exceptions/index.ts +0 -51
  415. package/src/requests/factories/BinaryBodyFactory.ts +0 -13
  416. package/src/requests/factories/FormDataFactory.ts +0 -17
  417. package/src/requests/factories/JsonBodyFactory.ts +0 -9
  418. package/src/requests/index.ts +0 -68
  419. package/src/requests/responses/BaseResponse.ts +0 -41
  420. package/src/requests/responses/BlobResponse.ts +0 -19
  421. package/src/requests/responses/JsonResponse.ts +0 -15
  422. package/src/requests/responses/PlainTextResponse.ts +0 -15
  423. package/src/requests/types/RequestUploadProgress.ts +0 -6
  424. package/src/support/DeferredPromise.ts +0 -67
  425. package/src/support/helpers.ts +0 -78
  426. package/src/vue/composables/useConfirmDialog.ts +0 -63
  427. package/src/vue/composables/useGlobalCheckbox.ts +0 -145
  428. package/src/vue/composables/useIsEmpty.ts +0 -34
  429. package/src/vue/composables/useIsOpen.ts +0 -37
  430. package/src/vue/composables/useIsOpenFromVar.ts +0 -61
  431. package/src/vue/composables/useModelWrapper.ts +0 -27
  432. package/src/vue/composables/useOnOpen.ts +0 -34
  433. package/src/vue/contracts/ModelValueProps.ts +0 -3
  434. package/src/vue/forms/BaseForm.ts +0 -1192
  435. package/src/vue/forms/PropertyAwareArray.ts +0 -81
  436. package/src/vue/forms/types/PersistedForm.ts +0 -6
  437. package/src/vue/forms/validation/ValidationMode.enum.ts +0 -14
  438. package/src/vue/forms/validation/index.ts +0 -15
  439. package/src/vue/forms/validation/rules/BaseRule.ts +0 -7
  440. package/src/vue/forms/validation/rules/ConfirmedRule.ts +0 -39
  441. package/src/vue/forms/validation/rules/EmailRule.ts +0 -23
  442. package/src/vue/forms/validation/rules/JsonRule.ts +0 -28
  443. package/src/vue/forms/validation/rules/MinRule.ts +0 -61
  444. package/src/vue/forms/validation/rules/RequiredRule.ts +0 -19
  445. package/src/vue/forms/validation/rules/UrlRule.ts +0 -24
  446. package/src/vue/forms/validation/types/ValidationRules.ts +0 -15
  447. package/src/vue/index.ts +0 -14
  448. package/src/vue/requests/factories/VueRequestLoaderFactory.ts +0 -10
  449. package/src/vue/requests/loaders/VueRequestBatchLoader.ts +0 -35
  450. package/src/vue/requests/loaders/VueRequestLoader.ts +0 -18
  451. package/src/vue/router/routeResourceBinding/RouteResourceBoundView.ts +0 -145
  452. package/src/vue/router/routeResourceBinding/RouteResourceRequestResolver.ts +0 -11
  453. package/src/vue/router/routeResourceBinding/defineRoute.ts +0 -59
  454. package/src/vue/router/routeResourceBinding/index.ts +0 -11
  455. package/src/vue/router/routeResourceBinding/installRouteInjection.ts +0 -164
  456. package/src/vue/router/routeResourceBinding/types.ts +0 -53
  457. package/src/vue/router/routeResourceBinding/useRouteResource.ts +0 -24
  458. package/src/vue/state/State.ts +0 -380
  459. package/src/vue/state/index.ts +0 -3
  460. package/tests/service/bulkRequests/BulkRequestSender.test.ts +0 -76
  461. package/tests/service/bulkRequests/BulkRequestWrapper.test.ts +0 -51
  462. package/tests/service/helpers/mergeDeep.test.ts +0 -53
  463. package/tests/service/laravel/pagination/dataDrivers/RequestDriver.test.ts +0 -84
  464. package/tests/service/laravel/requests/JsonBaseRequest.test.ts +0 -43
  465. package/tests/service/laravel/requests/PaginationJsonBaseRequest.test.ts +0 -58
  466. package/tests/service/laravel/requests/responses/JsonResponse.test.ts +0 -59
  467. package/tests/service/laravel/requests/responses/PaginationResponse.test.ts +0 -127
  468. package/tests/service/pagination/BasePaginator.test.ts +0 -100
  469. package/tests/service/pagination/InfiniteScroller.test.ts +0 -101
  470. package/tests/service/pagination/PageAwarePaginator.test.ts +0 -133
  471. package/tests/service/pagination/StatePaginator.test.ts +0 -76
  472. package/tests/service/pagination/VueViewDrivers.test.ts +0 -46
  473. package/tests/service/pagination/dtos/PaginationDataDto.test.ts +0 -35
  474. package/tests/service/pagination/dtos/StatePaginationDataDto.test.ts +0 -14
  475. package/tests/service/pagination/factories/VuePaginationDriverFactory.test.ts +0 -32
  476. package/tests/service/pagination/frontendDrivers/VuePaginationDriver.test.ts +0 -66
  477. package/tests/service/persistenceDrivers/PersistenceDrivers.test.ts +0 -56
  478. package/tests/service/requests/BaseRequest.test.ts +0 -250
  479. package/tests/service/requests/BodiesAndFactories.test.ts +0 -52
  480. package/tests/service/requests/Enums.test.ts +0 -20
  481. package/tests/service/requests/ErrorHandler.test.ts +0 -188
  482. package/tests/service/requests/FormDataBody.test.ts +0 -63
  483. package/tests/service/requests/RequestErrorRouter.test.ts +0 -44
  484. package/tests/service/requests/Responses.test.ts +0 -83
  485. package/tests/service/requests/exceptions/Exceptions.test.ts +0 -43
  486. package/tests/service/requests/fetch/FetchDriver.test.ts +0 -94
  487. package/tests/service/requests/fetch/FetchResponse.test.ts +0 -21
  488. package/tests/service/requests/xhr/XMLHttpRequestDriver.test.ts +0 -197
  489. package/tests/service/support/DeferredPromise.test.ts +0 -40
  490. package/tests/service/support/helpers.test.ts +0 -37
  491. package/tests/vue/composables/useConfirmDialog.test.ts +0 -77
  492. package/tests/vue/composables/useGlobalCheckbox.test.ts +0 -126
  493. package/tests/vue/composables/useIsEmpty.test.ts +0 -18
  494. package/tests/vue/composables/useIsOpen.test.ts +0 -25
  495. package/tests/vue/composables/useIsOpenFromVar.test.ts +0 -22
  496. package/tests/vue/composables/useModelWrapper.test.ts +0 -30
  497. package/tests/vue/composables/useOnOpen.test.ts +0 -26
  498. package/tests/vue/forms/BaseForm.behavior.test.ts +0 -98
  499. package/tests/vue/forms/BaseForm.transformers.test.ts +0 -109
  500. package/tests/vue/forms/PropertyAwareArray.test.ts +0 -30
  501. package/tests/vue/forms/validation/ValidationRules.test.ts +0 -79
  502. package/tests/vue/requests/VueRequestLoaders.test.ts +0 -48
  503. package/tests/vue/router/routeResourceBinding/RouteResourceBoundView.test.ts +0 -344
  504. package/tests/vue/router/routeResourceBinding/RouteResourceUtils.test.ts +0 -70
  505. package/tests/vue/router/routeResourceBinding/installRouteInjection.test.ts +0 -450
  506. package/tests/vue/state/State.test.ts +0 -151
  507. package/tsconfig.json +0 -114
  508. package/vite.config.ts +0 -34
  509. package/vitest.config.ts +0 -23
@@ -1,1192 +0,0 @@
1
- import { reactive, computed, toRaw, type ComputedRef, type WritableComputedRef, watch } from 'vue'
2
- import { camelCase, upperFirst, cloneDeep, isEqual } from 'lodash-es'
3
- import isEqualWith from 'lodash-es/isEqualWith'
4
- import { type PersistedForm } from './types/PersistedForm'
5
- import { NonPersistentDriver } from '../../persistenceDrivers/NonPersistentDriver'
6
- import { type PersistenceDriver } from '../../persistenceDrivers/types/PersistenceDriver'
7
- import { PropertyAwareArray } from './PropertyAwareArray'
8
- import { ValidationMode, type ValidationRules } from './validation'
9
-
10
- type DirtyObject = Record<string, boolean>
11
- type DirtyArray = Array<boolean | DirtyObject>
12
- type DirtyState = boolean | DirtyObject | DirtyArray
13
- type DirtyMap<FormBody extends object> = Record<keyof FormBody, DirtyState>
14
-
15
- type ErrorMessages = string[]
16
- interface ErrorObject {
17
- [key: string]: FieldErrors
18
- }
19
- type ErrorArray = Array<ErrorObject>
20
- type FieldErrors = ErrorMessages | ErrorObject | ErrorArray
21
- type ErrorBag = Record<string, FieldErrors>
22
-
23
- type FieldProperty<T> = {
24
- model: WritableComputedRef<T>
25
- errors: ErrorMessages
26
- dirty: boolean
27
- touched: boolean
28
- }
29
-
30
- type PropertyAwareToRaw<T> =
31
- T extends Array<infer U>
32
- ? Array<PropertyAwareToRaw<U>>
33
- : T extends { model: { value: infer V } }
34
- ? V
35
- : T extends object
36
- ? { [K in keyof T]: PropertyAwareToRaw<T[K]> }
37
- : T
38
-
39
- type FormKey<FormBody extends object> = Extract<keyof FormBody, string>
40
- type RequestKey<RequestBody extends object> = Extract<keyof RequestBody, string>
41
- type ArrayItem<T> = T extends Array<infer Item> ? Item : never
42
- type PropertyAwareInput<T> = T extends PropertyAwareArray<infer Item> ? Array<Item> | PropertyAwareArray<Item> : T
43
-
44
- type FormProperties<FormBody extends object> = {
45
- [K in keyof FormBody]: FormBody[K] extends PropertyAwareArray<infer Item>
46
- ? Array<Item extends object ? { [P in keyof Item]: FieldProperty<Item[P]> } : { value: FieldProperty<Item> }>
47
- : FieldProperty<FormBody[K]>
48
- }
49
-
50
- function isRecord(value: unknown): value is Record<string, unknown> {
51
- return !!value && typeof value === 'object' && !Array.isArray(value)
52
- }
53
-
54
- function isErrorMessages(value: unknown): value is ErrorMessages {
55
- return Array.isArray(value) && (value.length === 0 || typeof value[0] === 'string')
56
- }
57
-
58
- function isErrorArray(value: unknown): value is ErrorArray {
59
- return Array.isArray(value) && value.length > 0 && isRecord(value[0])
60
- }
61
-
62
- function isErrorObject(value: unknown): value is ErrorObject {
63
- return isRecord(value)
64
- }
65
-
66
- export function propertyAwareToRaw<T>(propertyAwareObject: T): PropertyAwareToRaw<T> {
67
- if (Array.isArray(propertyAwareObject)) {
68
- return propertyAwareObject.map((item) => propertyAwareToRaw(item)) as PropertyAwareToRaw<T>
69
- }
70
-
71
- if (!isRecord(propertyAwareObject)) {
72
- return propertyAwareObject as PropertyAwareToRaw<T>
73
- }
74
-
75
- const result: Record<string, unknown> = {}
76
- const record = propertyAwareObject
77
-
78
- for (const key in record) {
79
- if (!Object.prototype.hasOwnProperty.call(record, key) || key.startsWith('_')) {
80
- continue
81
- }
82
-
83
- const value = record[key]
84
- const modelValue = isRecord(value) ? (value as { model?: { value?: unknown } }).model?.value : undefined
85
-
86
- if (modelValue !== undefined) {
87
- result[key] = modelValue
88
- continue
89
- }
90
-
91
- if (value && typeof value === 'object') {
92
- result[key] = propertyAwareToRaw(value)
93
- continue
94
- }
95
-
96
- result[key] = value
97
- }
98
-
99
- return result as PropertyAwareToRaw<T>
100
- }
101
-
102
- /** Helper: shallow-merge source object into target. */
103
- function shallowMerge<T extends object, U extends object>(target: T, source: U): T & U {
104
- Object.assign(target, source)
105
- return target as T & U
106
- }
107
-
108
- /** Helper: if both values are arrays, update each element if possible, otherwise replace. */
109
- function deepMergeArrays<T>(target: T[], source: T[]): T[] {
110
- if (target.length !== source.length) {
111
- return source
112
- }
113
- return target.map((t, i) => {
114
- const s = source[i]
115
- if (s === undefined) {
116
- return t
117
- }
118
- if (t && typeof t === 'object' && s && typeof s === 'object') {
119
- return shallowMerge({ ...t }, s)
120
- }
121
- return s
122
- })
123
- }
124
-
125
- /**
126
- * Helper: Given the defaults and a state object (or original),
127
- * for every key where the default is a PropertyAwareArray, rewrap the value if needed.
128
- */
129
- function restorePropertyAwareArrays<FormBody>(defaults: FormBody, state: FormBody): void {
130
- for (const key in defaults) {
131
- const defVal = defaults[key]
132
- if (defVal instanceof PropertyAwareArray) {
133
- if (!(state[key] instanceof PropertyAwareArray)) {
134
- const values = Array.isArray(state[key]) ? Array.from(state[key]) : []
135
- state[key] = new PropertyAwareArray(values) as FormBody[typeof key]
136
- }
137
- }
138
- }
139
- }
140
-
141
- /**
142
- * Compare values while treating PropertyAwareArray as its underlying array.
143
- * This avoids false negatives when comparing persisted state to defaults.
144
- */
145
- function propertyAwareDeepEqual<T>(a: T, b: T): boolean {
146
- const getInner = (val: unknown) => {
147
- if (val instanceof PropertyAwareArray) {
148
- return val
149
- }
150
- return val
151
- }
152
-
153
- return isEqualWith(a, b, (aValue, bValue) => {
154
- const normA = getInner(aValue)
155
- const normB = getInner(bValue)
156
- if (normA !== aValue || normB !== bValue) {
157
- return isEqual(normA, normB)
158
- }
159
- return undefined // use default comparison
160
- })
161
- }
162
-
163
- /**
164
- * A generic base class for forms.
165
- *
166
- * @template RequestBody - The final payload shape (what is sent to the server).
167
- * @template FormBody - The raw form data shape (before mutators are applied).
168
- *
169
- * (We assume that for every key in RequestBody there is a corresponding key in FormBody.)
170
- */
171
- export abstract class BaseForm<RequestBody extends object, FormBody extends object> {
172
- protected readonly state: FormBody
173
- private readonly dirty: DirtyMap<FormBody>
174
- private readonly touched: Record<keyof FormBody, boolean>
175
- private readonly original: FormBody
176
- private readonly _model: { [K in keyof FormBody]: WritableComputedRef<FormBody[K]> }
177
- private _errors: ErrorBag = reactive<ErrorBag>({})
178
- private _hasErrors: ComputedRef<boolean>
179
- protected append: string[] = []
180
- protected ignore: string[] = []
181
- protected errorMap: { [serverKey: string]: string | string[] } = {}
182
-
183
- protected rules: ValidationRules<FormBody> = {}
184
-
185
- private fieldDependencies: Map<keyof FormBody, Set<keyof FormBody>> = new Map()
186
-
187
- /**
188
- * Returns the persistence driver to use.
189
- * The default is a NonPersistentDriver.
190
- * Child classes can override this method to return a different driver.
191
- */
192
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
193
- protected getPersistenceDriver(_suffix: string | undefined): PersistenceDriver {
194
- return new NonPersistentDriver()
195
- }
196
-
197
- /**
198
- * Helper: recursively computes the dirty state for a value based on the original.
199
- * For plain arrays we compare the entire array (a single flag), not each element.
200
- */
201
- private computeDirtyState<T>(current: T, original: T): DirtyState {
202
- if (Array.isArray(current) && Array.isArray(original)) {
203
- return current.length !== original.length || !isEqual(current, original)
204
- } else if (current && typeof current === 'object' && original && typeof original === 'object') {
205
- const dirty: Record<string, boolean> = {}
206
- for (const key in current) {
207
- if (Object.prototype.hasOwnProperty.call(current, key)) {
208
- dirty[key] = !isEqual(current[key], original[key])
209
- }
210
- }
211
- return dirty
212
- }
213
- return !isEqual(current, original)
214
- }
215
-
216
- private initDirtyTouched(defaults: FormBody): {
217
- dirty: DirtyMap<FormBody>
218
- touched: Record<keyof FormBody, boolean>
219
- } {
220
- const initDirty: Partial<DirtyMap<FormBody>> = {}
221
- const initTouched: Partial<Record<keyof FormBody, boolean>> = {}
222
-
223
- for (const key in defaults) {
224
- const value = defaults[key]
225
- if (value instanceof PropertyAwareArray) {
226
- initDirty[key as keyof FormBody] = Array.from(value).map((item) => {
227
- if (item && typeof item === 'object') {
228
- const obj: Record<string, boolean> = {}
229
- for (const k in item) {
230
- if (Object.prototype.hasOwnProperty.call(item, k)) {
231
- obj[k] = false
232
- }
233
- }
234
- return obj
235
- }
236
- return false
237
- })
238
- } else {
239
- initDirty[key as keyof FormBody] = false
240
- }
241
-
242
- initTouched[key as keyof FormBody] = false
243
- }
244
-
245
- return {
246
- dirty: reactive(initDirty) as DirtyMap<FormBody>,
247
- touched: reactive(initTouched) as Record<keyof FormBody, boolean>
248
- }
249
- }
250
-
251
- private replacePropertyAwareArray<K extends keyof FormBody>(key: K, values: Array<ArrayItem<FormBody[K]>>): void {
252
- const current = this.state[key]
253
- if (current instanceof PropertyAwareArray) {
254
- current.length = 0
255
- values.forEach((item) => current.push(item))
256
- return
257
- }
258
-
259
- this.state[key] = new PropertyAwareArray(values) as FormBody[K]
260
- }
261
-
262
- private persistState(driver?: PersistenceDriver): void {
263
- if (this.options?.persist === false) {
264
- return
265
- }
266
-
267
- const persistDriver = driver ?? this.getPersistenceDriver(this.options?.persistSuffix)
268
- persistDriver.set(this.constructor.name, {
269
- state: toRaw(this.state),
270
- original: toRaw(this.original),
271
- dirty: toRaw(this.dirty),
272
- touched: toRaw(this.touched)
273
- } as PersistedForm<FormBody>)
274
- }
275
-
276
- private markFieldUpdated(key: keyof FormBody, driver?: PersistenceDriver): void {
277
- this.touched[key] = true
278
- this.validateField(key)
279
- this.validateDependentFields(key)
280
- this.persistState(driver)
281
- }
282
-
283
- private updateField<K extends keyof FormBody>(key: K, value: FormBody[K], driver?: PersistenceDriver): void {
284
- this.state[key] = value
285
- this.dirty[key] = this.computeDirtyState(value, this.original[key])
286
- this.markFieldUpdated(key, driver)
287
- }
288
-
289
- /**
290
- * Build a map of field dependencies based on the rules
291
- * This identifies which fields need to be revalidated when another field changes
292
- */
293
- private buildFieldDependencies(): void {
294
- for (const field in this.rules) {
295
- if (Object.prototype.hasOwnProperty.call(this.rules, field)) {
296
- const fieldRules = this.rules[field as keyof FormBody]?.rules || []
297
-
298
- for (const rule of fieldRules) {
299
- for (const dependencyField of rule.dependsOn) {
300
- if (!this.fieldDependencies.has(dependencyField as keyof FormBody)) {
301
- this.fieldDependencies.set(dependencyField as keyof FormBody, new Set())
302
- }
303
-
304
- this.fieldDependencies.get(dependencyField as keyof FormBody)?.add(field as keyof FormBody)
305
- }
306
-
307
- const bidirectionalFields = rule.getBidirectionalFields?.()
308
- if (bidirectionalFields && bidirectionalFields.length > 0) {
309
- for (const bidirectionalField of bidirectionalFields) {
310
- if (!this.fieldDependencies.has(field as keyof FormBody)) {
311
- this.fieldDependencies.set(field as keyof FormBody, new Set())
312
- }
313
-
314
- this.fieldDependencies.get(field as keyof FormBody)?.add(bidirectionalField)
315
- }
316
- }
317
- }
318
- }
319
- }
320
- }
321
-
322
- /**
323
- * Validate fields that depend on the changed field
324
- */
325
- private validateDependentFields(changedField: keyof FormBody): void {
326
- const dependentFields = this.fieldDependencies.get(changedField)
327
-
328
- if (dependentFields) {
329
- const fieldsToValidate = new Set<keyof FormBody>(dependentFields)
330
-
331
- for (const field of dependentFields) {
332
- const fieldDeps = this.fieldDependencies.get(field)
333
- if (fieldDeps && fieldDeps.has(changedField)) {
334
- fieldsToValidate.add(field)
335
- fieldsToValidate.add(changedField)
336
- }
337
- }
338
-
339
- for (const field of fieldsToValidate) {
340
- this.validateField(field, {
341
- isDependentChange: true,
342
- isSubmitting: false
343
- })
344
- }
345
- }
346
- }
347
-
348
- protected constructor(
349
- defaults: FormBody,
350
- protected options?: { persist?: boolean; persistSuffix?: string }
351
- ) {
352
- const persist = options?.persist !== false
353
- let initialData: FormBody
354
- const driver = this.getPersistenceDriver(options?.persistSuffix)
355
-
356
- if (persist) {
357
- const persisted = driver.get<PersistedForm<FormBody>>(this.constructor.name)
358
- if (persisted && propertyAwareDeepEqual(defaults, persisted.original)) {
359
- initialData = persisted.state
360
- this.original = cloneDeep(persisted.original)
361
- this.dirty = reactive(persisted.dirty) as DirtyMap<FormBody>
362
- this.touched = reactive(persisted.touched || {}) as Record<keyof FormBody, boolean>
363
- restorePropertyAwareArrays(defaults, initialData)
364
- restorePropertyAwareArrays(defaults, this.original)
365
- } else {
366
- console.log('Discarding persisted data for ' + this.constructor.name + " because it doesn't match the defaults.")
367
- initialData = defaults
368
- this.original = cloneDeep(defaults)
369
- const init = this.initDirtyTouched(defaults)
370
- this.dirty = init.dirty
371
- this.touched = init.touched
372
- driver.remove(this.constructor.name)
373
- }
374
- } else {
375
- initialData = defaults
376
- this.original = cloneDeep(defaults)
377
- const init = this.initDirtyTouched(defaults)
378
- this.dirty = init.dirty
379
- this.touched = init.touched
380
- }
381
-
382
- this.rules = this.defineRules()
383
-
384
- this.buildFieldDependencies()
385
-
386
- this.state = reactive(initialData) as FormBody
387
- this._model = {} as { [K in keyof FormBody]: WritableComputedRef<FormBody[K]> }
388
-
389
- for (const key in this.state) {
390
- const value = this.state[key]
391
- if (value instanceof PropertyAwareArray) {
392
- this._model[key as keyof FormBody] = computed({
393
- get: () => this.state[key],
394
- set: (newVal: PropertyAwareInput<FormBody[typeof key]>) => {
395
- const next = Array.isArray(newVal) ? Array.from(newVal) : []
396
- this.replacePropertyAwareArray(key as keyof FormBody, next)
397
- this.dirty[key as keyof FormBody] = next.map(() => false)
398
- this.markFieldUpdated(key as keyof FormBody, driver)
399
- }
400
- })
401
- } else {
402
- this._model[key as keyof FormBody] = computed({
403
- get: () => this.state[key],
404
- set: (value: FormBody[typeof key]) => {
405
- this.updateField(key as keyof FormBody, value, driver)
406
- }
407
- })
408
- }
409
- }
410
-
411
- for (const key in this.state) {
412
- const value = this.state[key]
413
- if (Array.isArray(value) && !(value instanceof PropertyAwareArray)) {
414
- watch(
415
- () => this.state[key],
416
- (newVal) => {
417
- this.dirty[key as keyof FormBody] = this.computeDirtyState(newVal, this.original[key])
418
- this.touched[key as keyof FormBody] = true
419
- },
420
- { deep: true }
421
- )
422
- }
423
- }
424
-
425
- this._hasErrors = computed(() => {
426
- for (const field in this._errors) {
427
- if (Object.prototype.hasOwnProperty.call(this._errors, field)) {
428
- const fieldErrors = this._errors[field]
429
-
430
- if (Array.isArray(fieldErrors) && fieldErrors.length > 0) {
431
- return true
432
- }
433
-
434
- if (fieldErrors && typeof fieldErrors === 'object') {
435
- if (Array.isArray(fieldErrors)) {
436
- for (const item of fieldErrors) {
437
- if (item && typeof item === 'object' && Object.keys(item).length > 0) {
438
- return true
439
- }
440
- }
441
- } else if (Object.keys(fieldErrors).length > 0) {
442
- return true
443
- }
444
- }
445
- }
446
- }
447
-
448
- return false
449
- })
450
-
451
- if (persist) {
452
- watch(
453
- () => this.state,
454
- () => this.persistState(driver),
455
- { deep: true, immediate: true }
456
- )
457
- }
458
-
459
- this.validate()
460
- }
461
-
462
- protected defineRules(): ValidationRules<FormBody> {
463
- return {}
464
- }
465
-
466
- private clearErrors(): void {
467
- for (const key in this._errors) {
468
- delete this._errors[key]
469
- }
470
- }
471
-
472
- private getOrCreateErrorArray(key: string): ErrorArray {
473
- const existing = this._errors[key]
474
- if (isErrorArray(existing)) {
475
- return existing
476
- }
477
-
478
- const next: ErrorArray = []
479
- this._errors[key] = next
480
- return next
481
- }
482
-
483
- private getOrCreateErrorObject(errors: ErrorArray, index: number): ErrorObject {
484
- const existing = errors[index]
485
- if (isErrorObject(existing)) {
486
- return existing
487
- }
488
-
489
- const next: ErrorObject = {}
490
- errors[index] = next
491
- return next
492
- }
493
-
494
- private getFieldErrors(field: string): ErrorMessages {
495
- const errors = this._errors[field]
496
- return isErrorMessages(errors) ? errors : []
497
- }
498
-
499
- private getOrCreateFieldErrors(field: string): ErrorMessages {
500
- const existing = this._errors[field]
501
- if (isErrorMessages(existing)) {
502
- return existing
503
- }
504
-
505
- const next: ErrorMessages = []
506
- this._errors[field] = next
507
- return next
508
- }
509
-
510
- private getArrayItemErrors(field: string, index: number): ErrorObject | undefined {
511
- const errors = this._errors[field]
512
- if (!isErrorArray(errors)) {
513
- return undefined
514
- }
515
- const item = errors[index]
516
- return isErrorObject(item) ? item : undefined
517
- }
518
-
519
- private getArrayItemFieldErrors(field: string, index: number, innerKey: string): ErrorMessages {
520
- const itemErrors = this.getArrayItemErrors(field, index)
521
- if (!itemErrors) {
522
- return []
523
- }
524
-
525
- const fieldErrors = itemErrors[innerKey]
526
- if (isErrorMessages(fieldErrors)) {
527
- return fieldErrors
528
- }
529
-
530
- if (isErrorObject(fieldErrors)) {
531
- const nestedErrors = fieldErrors['']
532
- return isErrorMessages(nestedErrors) ? nestedErrors : []
533
- }
534
-
535
- return []
536
- }
537
-
538
- private getArrayItemErrorMessages(field: string, index: number): ErrorMessages {
539
- const errors = this._errors[field]
540
- if (!Array.isArray(errors)) {
541
- return []
542
- }
543
- const item = errors[index]
544
- if (isErrorMessages(item)) {
545
- return item
546
- }
547
- if (isErrorObject(item)) {
548
- const nestedErrors = item['']
549
- return isErrorMessages(nestedErrors) ? nestedErrors : []
550
- }
551
- return []
552
- }
553
-
554
- private setArrayDirty(field: keyof FormBody, index: number, value: DirtyState): void {
555
- const dirtyState = this.dirty[field]
556
- if (Array.isArray(dirtyState)) {
557
- dirtyState[index] = this.normalizeItemDirtyState(value)
558
- }
559
- }
560
-
561
- /**
562
- * Collapse nested array dirty states into a single boolean/object for array entries.
563
- */
564
- private normalizeItemDirtyState(value: DirtyState): boolean | DirtyObject {
565
- if (!Array.isArray(value)) {
566
- return value
567
- }
568
-
569
- return value.some((entry) => {
570
- if (typeof entry === 'boolean') {
571
- return entry
572
- }
573
- if (isRecord(entry)) {
574
- return Object.values(entry).some((item) => item === true)
575
- }
576
- return false
577
- })
578
- }
579
-
580
- private getArrayItemDirty(field: keyof FormBody, index: number, innerKey: string): boolean {
581
- const dirtyState = this.dirty[field]
582
- if (!Array.isArray(dirtyState)) {
583
- return false
584
- }
585
-
586
- const entry = dirtyState[index]
587
- if (typeof entry === 'boolean') {
588
- return entry
589
- }
590
-
591
- if (isRecord(entry)) {
592
- return entry[innerKey] === true
593
- }
594
-
595
- return false
596
- }
597
-
598
- private getArrayItemDirtyValue(field: keyof FormBody, index: number): boolean {
599
- const dirtyState = this.dirty[field]
600
- if (!Array.isArray(dirtyState)) {
601
- return false
602
- }
603
-
604
- const entry = dirtyState[index]
605
- return typeof entry === 'boolean' ? entry : false
606
- }
607
-
608
- /**
609
- * Map server-side errors (including dot-notation paths) into the form error bag.
610
- */
611
- public fillErrors<ErrorInterface extends Record<string, FieldErrors>>(errorsData: ErrorInterface): void {
612
- this.clearErrors()
613
-
614
- for (const serverKey in errorsData) {
615
- if (Object.prototype.hasOwnProperty.call(errorsData, serverKey)) {
616
- const errorMessage = errorsData[serverKey]
617
- if (errorMessage === undefined) {
618
- continue
619
- }
620
-
621
- let targetKeys: string[] = [serverKey]
622
-
623
- const mapping = this.errorMap?.[serverKey]
624
- if (mapping) {
625
- targetKeys = Array.isArray(mapping) ? mapping : [mapping]
626
- }
627
-
628
- for (const targetKey of targetKeys) {
629
- const parts = targetKey.split('.')
630
- if (parts.length > 1) {
631
- const topKey = parts[0] ?? ''
632
- const indexPart = parts[1] ?? ''
633
- const index = Number.parseInt(indexPart, 10)
634
- if (!topKey || !Number.isFinite(index)) {
635
- this._errors[targetKey] = errorMessage
636
- continue
637
- }
638
- const errorSubKey = parts.slice(2).join('.')
639
-
640
- const errors = this.getOrCreateErrorArray(topKey)
641
- const errorObject = this.getOrCreateErrorObject(errors, index)
642
-
643
- if (errorSubKey.length === 0) {
644
- errorObject[''] = errorMessage
645
- } else {
646
- errorObject[errorSubKey] = errorMessage
647
- }
648
- } else {
649
- this._errors[targetKey] = errorMessage
650
- }
651
- }
652
- }
653
- }
654
- }
655
-
656
- /**
657
- * Mark a field as touched, which indicates user interaction
658
- * Optionally triggers validation
659
- * @param field The field to mark as touched
660
- */
661
- public touch(field: keyof FormBody): void {
662
- this.touched[field] = true
663
-
664
- const fieldConfig = this.rules[field]
665
- if (fieldConfig) {
666
- const mode = fieldConfig.options?.mode ?? ValidationMode.DEFAULT
667
-
668
- if (mode & ValidationMode.ON_TOUCH) {
669
- this.validateField(field, {
670
- isSubmitting: false,
671
- isDependentChange: false
672
- })
673
- }
674
- }
675
-
676
- if (this.options?.persist !== false) {
677
- this.persistState()
678
- }
679
- }
680
-
681
- /**
682
- * Check if a field has been touched (user interacted with it)
683
- * @param field The field to check
684
- * @returns boolean indicating if the field has been touched
685
- */
686
- public isTouched(field: keyof FormBody): boolean {
687
- return !!this.touched[field]
688
- }
689
-
690
- protected validateField(
691
- field: keyof FormBody,
692
- context: {
693
- isDirty?: boolean
694
- isSubmitting?: boolean
695
- isDependentChange?: boolean
696
- isTouched?: boolean
697
- } = {}
698
- ): void {
699
- const emptyErrors: ErrorMessages = []
700
- const errorKey = String(field)
701
- this._errors[errorKey] = emptyErrors
702
-
703
- const value = this.state[field]
704
-
705
- const fieldConfig = this.rules[field]
706
- if (!fieldConfig?.rules || fieldConfig.rules.length === 0) {
707
- return // No rules to validate
708
- }
709
-
710
- const mode = fieldConfig.options?.mode ?? ValidationMode.DEFAULT
711
-
712
- const isDirty = context.isDirty !== undefined ? context.isDirty : this.isDirty(field)
713
- const isTouched = context.isTouched !== undefined ? context.isTouched : this.isTouched(field)
714
-
715
- const shouldValidate =
716
- (context.isSubmitting && mode & ValidationMode.ON_SUBMIT) ||
717
- (isDirty && mode & ValidationMode.ON_DIRTY) ||
718
- (isTouched && mode & ValidationMode.ON_TOUCH) ||
719
- mode & ValidationMode.INSTANTLY ||
720
- (context.isDependentChange && mode & ValidationMode.ON_DEPENDENT_CHANGE)
721
-
722
- if (shouldValidate) {
723
- for (const rule of fieldConfig.rules) {
724
- const isValid = rule.validate(value, this.state)
725
- if (!isValid) {
726
- this.getOrCreateFieldErrors(errorKey).push(rule.getMessage())
727
- }
728
- }
729
- }
730
- }
731
-
732
- public validate(isSubmitting: boolean = false): boolean {
733
- let isValid = true
734
-
735
- for (const key in this._errors) {
736
- delete this._errors[key]
737
- }
738
-
739
- for (const field in this.rules) {
740
- if (Object.prototype.hasOwnProperty.call(this.rules, field)) {
741
- this.validateField(field as keyof FormBody, {
742
- isSubmitting,
743
- isDependentChange: false,
744
- isTouched: this.isTouched(field as keyof FormBody)
745
- })
746
-
747
- const fieldErrors = this._errors[String(field)]
748
- if (isErrorMessages(fieldErrors) && fieldErrors.length > 0) {
749
- isValid = false
750
- }
751
- }
752
- }
753
-
754
- return isValid
755
- }
756
-
757
- public fillState(data: Partial<FormBody>): void {
758
- const driver = this.getPersistenceDriver(this.options?.persistSuffix)
759
- for (const key of Object.keys(data) as Array<keyof FormBody>) {
760
- if (!Object.prototype.hasOwnProperty.call(data, key) || !(key in this.state)) {
761
- continue
762
- }
763
-
764
- const currentVal = this.state[key]
765
- const newVal = data[key] as FormBody[typeof key] | undefined
766
-
767
- if (currentVal instanceof PropertyAwareArray) {
768
- const values = newVal instanceof PropertyAwareArray || Array.isArray(newVal) ? Array.from(newVal) : []
769
- this.replacePropertyAwareArray(key, values)
770
-
771
- this.dirty[key] = values.map(() => false)
772
- this.touched[key] = true
773
- continue
774
- }
775
-
776
- if (Array.isArray(newVal) && Array.isArray(currentVal)) {
777
- const merged = newVal.length === currentVal.length ? deepMergeArrays(currentVal, newVal) : newVal
778
- this.state[key] = merged as FormBody[typeof key]
779
- this.dirty[key] = this.computeDirtyState(this.state[key], this.original[key])
780
- this.touched[key] = true
781
- continue
782
- }
783
-
784
- if (isRecord(newVal) && isRecord(currentVal)) {
785
- this.state[key] = shallowMerge({ ...currentVal }, newVal) as FormBody[typeof key]
786
- this.dirty[key] = this.computeDirtyState(this.state[key], this.original[key])
787
- this.touched[key] = true
788
- continue
789
- }
790
-
791
- this.state[key] = newVal as FormBody[typeof key]
792
- this.dirty[key] = this.computeDirtyState(this.state[key], this.original[key])
793
- this.touched[key] = true
794
- }
795
- this.persistState(driver)
796
-
797
- for (const key in data) {
798
- if (Object.prototype.hasOwnProperty.call(data, key) && key in this.state) {
799
- this.validateField(key as keyof FormBody)
800
- this.validateDependentFields(key as keyof FormBody)
801
- }
802
- }
803
- }
804
-
805
- private getValueGetter(name: string): ((value: unknown) => unknown) | undefined {
806
- const candidate = (this as Record<string, unknown>)[name]
807
- if (typeof candidate !== 'function') {
808
- return undefined
809
- }
810
- return (candidate as (value: unknown) => unknown).bind(this)
811
- }
812
-
813
- private getNoArgGetter(name: string): (() => unknown) | undefined {
814
- const candidate = (this as Record<string, unknown>)[name]
815
- if (typeof candidate !== 'function') {
816
- return undefined
817
- }
818
- return (candidate as () => unknown).bind(this)
819
- }
820
-
821
- private transformValue(value: unknown, parentKey?: string): unknown {
822
- if (value instanceof Date) {
823
- return value
824
- }
825
- if (typeof Blob !== 'undefined' && value instanceof Blob) {
826
- return value
827
- }
828
- if (value instanceof PropertyAwareArray) {
829
- return [...value].map((item) => this.transformValue(item, parentKey))
830
- }
831
- if (Array.isArray(value)) {
832
- return value.map((item) => this.transformValue(item, parentKey))
833
- } else if (isRecord(value)) {
834
- const result: Record<string, unknown> = {}
835
- for (const prop in value) {
836
- if (parentKey) {
837
- const compositeMethod = 'get' + upperFirst(parentKey) + upperFirst(camelCase(prop))
838
- const getter = this.getValueGetter(compositeMethod)
839
- if (getter) {
840
- const transformed = getter(value[prop])
841
- if (transformed !== undefined) {
842
- result[prop] = transformed
843
- }
844
- continue
845
- }
846
- }
847
- const transformed = this.transformValue(value[prop], parentKey)
848
- if (transformed !== undefined) {
849
- result[prop] = transformed
850
- }
851
- }
852
- return result
853
- }
854
- return value
855
- }
856
-
857
- /**
858
- * Build the request payload, applying field/composite/appended getters when present.
859
- */
860
- public buildPayload(): RequestBody {
861
- const payload = {} as RequestBody
862
- for (const key of Object.keys(this.state) as Array<FormKey<FormBody> & RequestKey<RequestBody>>) {
863
- if (this.ignore.includes(key)) {
864
- continue
865
- }
866
-
867
- const value = this.state[key]
868
-
869
- const getterName = 'get' + upperFirst(camelCase(key))
870
- const typedKey = key
871
- const getter = this.getValueGetter(getterName)
872
- if (getter) {
873
- const transformed = getter(value)
874
- if (transformed !== undefined) {
875
- payload[typedKey] = transformed as RequestBody[typeof typedKey]
876
- }
877
- } else {
878
- const transformed = this.transformValue(value, key)
879
- if (transformed !== undefined) {
880
- payload[typedKey] = transformed as RequestBody[typeof typedKey]
881
- }
882
- }
883
- }
884
-
885
- for (const fieldName of this.append) {
886
- if (Array.isArray(this.ignore) && this.ignore.includes(fieldName)) {
887
- console.warn(`Appended field '${fieldName}' is also in ignore list in ${this.constructor.name}. It will be skipped.`)
888
- continue
889
- }
890
-
891
- const getterName = 'get' + upperFirst(camelCase(fieldName))
892
- const getter = this.getNoArgGetter(getterName)
893
- if (getter) {
894
- const transformed = getter()
895
- if (transformed !== undefined) {
896
- payload[fieldName as keyof RequestBody] = transformed as RequestBody[keyof RequestBody]
897
- }
898
- } else {
899
- console.warn(`Getter method '${getterName}' not found for appended field '${fieldName}' in ${this.constructor.name}.`)
900
- }
901
- }
902
-
903
- return payload
904
- }
905
-
906
- public reset(): void {
907
- const driver = this.getPersistenceDriver(this.options?.persistSuffix)
908
- for (const key in this.state) {
909
- if (this.state[key] instanceof PropertyAwareArray) {
910
- const originalValue = this.original[key] as PropertyAwareArray
911
- const values = [...originalValue].map((item) => cloneDeep(item))
912
- const typedKey = key as keyof FormBody
913
- this.replacePropertyAwareArray(typedKey, values as Array<ArrayItem<FormBody[typeof typedKey]>>)
914
- this.dirty[typedKey] = values.map(() => false)
915
- this.touched[typedKey] = false
916
- } else if (Array.isArray(this.original[key])) {
917
- this.state[key] = cloneDeep(this.original[key])
918
- this.dirty[key as keyof FormBody] = this.computeDirtyState(this.state[key], this.original[key])
919
- this.touched[key as keyof FormBody] = false
920
- } else {
921
- this.state[key] = cloneDeep(this.original[key])
922
- this.dirty[key as keyof FormBody] = false
923
- this.touched[key as keyof FormBody] = false
924
- }
925
- }
926
- for (const key in this._errors) {
927
- delete this._errors[key]
928
- }
929
- this.persistState(driver)
930
-
931
- this.validate()
932
- }
933
-
934
- protected addToArrayProperty<K extends keyof FormBody>(property: K, newElement: ArrayItem<FormBody[K]>): void {
935
- const driver = this.getPersistenceDriver(this.options?.persistSuffix)
936
- const arr = this.state[property]
937
- if (arr instanceof PropertyAwareArray) {
938
- arr.push(newElement)
939
- this.touched[property] = true
940
- this.persistState(driver)
941
-
942
- return
943
- }
944
-
945
- if (!Array.isArray(arr)) {
946
- throw new Error(`Property "${String(property)}" is not an array.`)
947
- }
948
-
949
- arr.push(newElement)
950
- this.dirty[property] = this.computeDirtyState(arr, this.original[property])
951
- this.touched[property] = true
952
- this.persistState(driver)
953
-
954
- this.validateField(property)
955
- this.validateDependentFields(property)
956
- }
957
-
958
- protected removeArrayItem<K extends keyof FormBody>(arrayIndex: K, filter: (item: ArrayItem<FormBody[K]>) => boolean): void {
959
- const current = this.state[arrayIndex]
960
- if (current instanceof PropertyAwareArray) {
961
- const filtered = [...current].filter(filter)
962
- current.length = 0
963
- filtered.forEach((item) => current.push(item))
964
- } else if (Array.isArray(current)) {
965
- this.state[arrayIndex] = current.filter(filter) as FormBody[K]
966
- }
967
-
968
- this.touched[arrayIndex] = true
969
-
970
- this.validateField(arrayIndex)
971
- this.validateDependentFields(arrayIndex)
972
- }
973
-
974
- protected resetArrayCounter(arrayIndex: keyof FormBody, counterIndex: string): void {
975
- let count = 1
976
- const current = this.state[arrayIndex]
977
- if (current instanceof PropertyAwareArray) {
978
- ;[...current].forEach((item): void => {
979
- if (isRecord(item)) {
980
- item[counterIndex] = count
981
- count++
982
- }
983
- })
984
- } else if (Array.isArray(current)) {
985
- current.forEach((item): void => {
986
- if (isRecord(item)) {
987
- item[counterIndex] = count
988
- count++
989
- }
990
- })
991
- }
992
-
993
- this.touched[arrayIndex as keyof FormBody] = true
994
- }
995
-
996
- public get properties(): FormProperties<FormBody> {
997
- const props: Partial<FormProperties<FormBody>> = {}
998
- for (const key of Object.keys(this.state) as Array<FormKey<FormBody>>) {
999
- const value = this.state[key]
1000
- if (value instanceof PropertyAwareArray) {
1001
- const arrayProps = [...value].map((item, index) => {
1002
- if (isRecord(item)) {
1003
- const elementProps: Record<string, FieldProperty<unknown>> = {}
1004
- for (const innerKey of Object.keys(item)) {
1005
- elementProps[innerKey] = {
1006
- model: computed({
1007
- get: () => {
1008
- const current = value[index]
1009
- return isRecord(current) ? current[innerKey] : undefined
1010
- },
1011
- set: (newVal) => {
1012
- const current = value[index]
1013
- if (isRecord(current)) {
1014
- current[innerKey] = newVal
1015
- }
1016
- const updatedElement = value[index]
1017
- const originalElement = (this.original[key] as PropertyAwareArray)[index]
1018
- this.setArrayDirty(key, index, this.computeDirtyState(updatedElement, originalElement))
1019
- this.touched[key] = true
1020
-
1021
- this.validateField(key)
1022
- this.validateDependentFields(key)
1023
- }
1024
- }),
1025
- errors: this.getArrayItemFieldErrors(key, index, innerKey),
1026
- dirty: this.getArrayItemDirty(key, index, innerKey),
1027
- touched: this.touched[key] || false
1028
- }
1029
- }
1030
- return elementProps
1031
- }
1032
-
1033
- return {
1034
- value: {
1035
- model: computed({
1036
- get: () => value[index],
1037
- set: (newVal) => {
1038
- value[index] = newVal as ArrayItem<FormBody[typeof key]>
1039
- const updatedValue = value[index]
1040
- const originalValue = (this.original[key] as PropertyAwareArray)[index]
1041
- this.setArrayDirty(key, index, this.computeDirtyState(updatedValue, originalValue))
1042
- this.touched[key] = true
1043
-
1044
- this.validateField(key)
1045
- this.validateDependentFields(key)
1046
- }
1047
- }),
1048
- errors: this.getArrayItemErrorMessages(key, index),
1049
- dirty: this.getArrayItemDirtyValue(key, index),
1050
- touched: this.touched[key] || false
1051
- }
1052
- }
1053
- })
1054
-
1055
- props[key] = arrayProps as FormProperties<FormBody>[typeof key]
1056
- continue
1057
- }
1058
-
1059
- props[key] = {
1060
- model: this._model[key],
1061
- errors: this.getFieldErrors(key),
1062
- dirty: this.dirty[key] || false,
1063
- touched: this.touched[key] || false
1064
- } as FormProperties<FormBody>[typeof key]
1065
- }
1066
- return props as FormProperties<FormBody>
1067
- }
1068
-
1069
- /**
1070
- * Checks if the form or a specific field is dirty
1071
- * @param field Optional field name to check, if not provided checks the entire form
1072
- * @returns boolean indicating if the form or specified field is dirty
1073
- */
1074
- public isDirty(field?: keyof FormBody): boolean {
1075
- if (field !== undefined) {
1076
- const dirtyState = this.dirty[field]
1077
-
1078
- if (typeof dirtyState === 'boolean') {
1079
- return dirtyState
1080
- }
1081
-
1082
- if (Array.isArray(dirtyState)) {
1083
- return dirtyState.some((item) => {
1084
- if (typeof item === 'boolean') {
1085
- return item
1086
- }
1087
- if (item && typeof item === 'object') {
1088
- return Object.values(item).some((v) => v === true)
1089
- }
1090
- return false
1091
- })
1092
- }
1093
-
1094
- if (dirtyState && typeof dirtyState === 'object') {
1095
- return Object.values(dirtyState).some((v) => v === true)
1096
- }
1097
-
1098
- return false
1099
- }
1100
-
1101
- for (const key in this.dirty) {
1102
- const dirtyState = this.dirty[key as keyof FormBody]
1103
-
1104
- if (typeof dirtyState === 'boolean' && dirtyState) {
1105
- return true
1106
- }
1107
-
1108
- if (Array.isArray(dirtyState)) {
1109
- for (const item of dirtyState) {
1110
- if (typeof item === 'boolean' && item) {
1111
- return true
1112
- }
1113
- if (item && typeof item === 'object' && Object.values(item).some((v) => v === true)) {
1114
- return true
1115
- }
1116
- }
1117
- }
1118
-
1119
- if (dirtyState && typeof dirtyState === 'object' && Object.values(dirtyState).some((v) => v === true)) {
1120
- return true
1121
- }
1122
- }
1123
-
1124
- return false
1125
- }
1126
-
1127
- /**
1128
- * Returns whether the form has validation errors
1129
- * @returns boolean indicating if the form has errors
1130
- */
1131
- public hasErrors(): boolean {
1132
- return this._hasErrors.value
1133
- }
1134
-
1135
- /**
1136
- * Updates both the state and original value for a given property,
1137
- * keeping the field in a clean (not dirty) state.
1138
- * Supports all field types including PropertyAwareArray.
1139
- *
1140
- * @param key The property key to update
1141
- * @param value The new value to set
1142
- */
1143
- public syncValue<K extends keyof FormBody>(key: K, value: FormBody[K]): void {
1144
- const driver = this.getPersistenceDriver(this.options?.persistSuffix)
1145
- const currentVal = this.state[key]
1146
-
1147
- if (currentVal instanceof PropertyAwareArray) {
1148
- const arr = this.state[key] as PropertyAwareArray
1149
- const originalArr = this.original[key] as PropertyAwareArray
1150
-
1151
- arr.length = 0
1152
- originalArr.length = 0
1153
-
1154
- if (Array.isArray(value)) {
1155
- value.forEach((item) => {
1156
- arr.push(cloneDeep(item))
1157
- originalArr.push(cloneDeep(item))
1158
- })
1159
- } else if (value instanceof PropertyAwareArray) {
1160
- ;[...value].forEach((item) => {
1161
- arr.push(cloneDeep(item))
1162
- originalArr.push(cloneDeep(item))
1163
- })
1164
- }
1165
-
1166
- this.dirty[key] = Array.from(arr).map(() => false)
1167
- this.touched[key] = true
1168
- } else if (Array.isArray(currentVal)) {
1169
- this.state[key] = cloneDeep(value)
1170
- this.original[key] = cloneDeep(value)
1171
- this.dirty[key] = false
1172
- this.touched[key] = true
1173
- } else if (typeof currentVal === 'object' && currentVal !== null) {
1174
- this.state[key] = cloneDeep(value)
1175
- this.original[key] = cloneDeep(value)
1176
- this.dirty[key] = false
1177
- this.touched[key] = true
1178
- } else {
1179
- this.state[key] = value
1180
- this.original[key] = value
1181
- this.dirty[key] = false
1182
- this.touched[key] = true
1183
- }
1184
-
1185
- if (this.options?.persist !== false) {
1186
- this.persistState(driver)
1187
- }
1188
-
1189
- this.validateField(key)
1190
- this.validateDependentFields(key)
1191
- }
1192
- }