@effect-app/vue-components 4.0.0-beta.2 → 4.0.0-beta.200

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 (233) hide show
  1. package/README.md +36 -8
  2. package/dist/reset.css +52 -0
  3. package/dist/types/components/CommandButton.vue.d.ts +6 -4
  4. package/dist/types/components/OmegaForm/OmegaArray.vue.d.ts +1 -1
  5. package/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +2 -2
  6. package/dist/types/components/OmegaForm/OmegaErrorsInternal.vue.d.ts +1 -1
  7. package/dist/types/components/OmegaForm/OmegaFormInput.vue.d.ts +1 -1
  8. package/dist/types/components/OmegaForm/OmegaInput.vue.d.ts +1 -1
  9. package/dist/types/components/OmegaForm/OmegaInternalInput.vue.d.ts +2 -1
  10. package/dist/types/components/OmegaForm/OmegaWrapper.vue.d.ts +1 -1
  11. package/dist/types/components/OmegaForm/createUseFormWithCustomInput.d.ts +2 -2
  12. package/dist/types/components/OmegaForm/errors.d.ts +33 -0
  13. package/dist/types/components/OmegaForm/getOmegaStore.d.ts +1 -1
  14. package/dist/types/components/OmegaForm/hocs.d.ts +3 -0
  15. package/dist/types/components/OmegaForm/index.d.ts +13 -3
  16. package/dist/types/components/OmegaForm/inputs.d.ts +4 -0
  17. package/dist/types/components/OmegaForm/meta/checks.d.ts +4 -0
  18. package/dist/types/components/OmegaForm/meta/createMeta.d.ts +32 -0
  19. package/dist/types/components/OmegaForm/meta/defaults.d.ts +2 -0
  20. package/dist/types/components/OmegaForm/meta/redacted.d.ts +2 -0
  21. package/dist/types/components/OmegaForm/meta/types.d.ts +56 -0
  22. package/dist/types/components/OmegaForm/meta/walker.d.ts +18 -0
  23. package/dist/types/components/OmegaForm/persistency.d.ts +58 -0
  24. package/dist/types/components/OmegaForm/submit.d.ts +60 -0
  25. package/dist/types/components/OmegaForm/types.d.ts +281 -0
  26. package/dist/types/components/OmegaForm/useOmegaForm.d.ts +7 -215
  27. package/dist/types/components/OmegaForm/validation/localized.d.ts +10 -0
  28. package/dist/types/index.d.ts +0 -1
  29. package/dist/types/utils/index.d.ts +6 -7
  30. package/dist/vue-components.es.js +29 -44
  31. package/dist/vue-components10.es.js +5 -0
  32. package/dist/vue-components11.es.js +20 -0
  33. package/dist/vue-components12.es.js +49 -0
  34. package/dist/vue-components13.es.js +128 -0
  35. package/dist/vue-components14.es.js +65 -0
  36. package/dist/vue-components15.es.js +60 -0
  37. package/dist/vue-components16.es.js +22 -0
  38. package/dist/vue-components17.es.js +5 -0
  39. package/dist/vue-components18.es.js +80 -0
  40. package/dist/vue-components19.es.js +92 -0
  41. package/dist/vue-components2.es.js +11 -0
  42. package/dist/vue-components20.es.js +73 -0
  43. package/dist/vue-components21.es.js +12 -0
  44. package/dist/vue-components22.es.js +56 -0
  45. package/dist/vue-components23.es.js +5 -0
  46. package/dist/vue-components24.es.js +44 -0
  47. package/dist/vue-components25.es.js +5 -0
  48. package/dist/vue-components26.es.js +84 -0
  49. package/dist/vue-components28.es.js +8 -0
  50. package/dist/vue-components29.es.js +9 -0
  51. package/dist/vue-components3.es.js +86 -0
  52. package/dist/vue-components30.es.js +269 -0
  53. package/dist/vue-components32.es.js +8 -0
  54. package/dist/vue-components33.es.js +73 -0
  55. package/dist/vue-components34.es.js +5 -0
  56. package/dist/vue-components35.es.js +52 -0
  57. package/dist/vue-components36.es.js +5 -0
  58. package/dist/vue-components37.es.js +24 -0
  59. package/dist/vue-components38.es.js +5 -0
  60. package/dist/vue-components39.es.js +59 -0
  61. package/dist/vue-components4.es.js +5 -0
  62. package/dist/vue-components40.es.js +5 -0
  63. package/dist/vue-components41.es.js +12 -0
  64. package/dist/vue-components42.es.js +22 -0
  65. package/dist/vue-components44.es.js +9 -0
  66. package/dist/vue-components45.es.js +4 -0
  67. package/dist/vue-components46.es.js +38 -0
  68. package/dist/vue-components47.es.js +27 -0
  69. package/dist/vue-components48.es.js +28 -0
  70. package/dist/vue-components49.es.js +7 -0
  71. package/dist/vue-components5.es.js +24 -0
  72. package/dist/vue-components50.es.js +18 -0
  73. package/dist/vue-components51.es.js +36 -0
  74. package/dist/vue-components52.es.js +18 -0
  75. package/dist/vue-components53.es.js +21 -0
  76. package/dist/vue-components54.es.js +30 -0
  77. package/dist/vue-components55.es.js +7 -0
  78. package/dist/vue-components56.es.js +9 -0
  79. package/dist/vue-components57.es.js +38 -0
  80. package/dist/vue-components58.es.js +25 -0
  81. package/dist/vue-components59.es.js +128 -0
  82. package/dist/vue-components6.es.js +13 -0
  83. package/dist/vue-components60.es.js +24 -0
  84. package/dist/vue-components61.es.js +21 -0
  85. package/dist/vue-components62.es.js +9 -0
  86. package/dist/vue-components63.es.js +19 -0
  87. package/dist/vue-components64.es.js +5 -0
  88. package/dist/vue-components65.es.js +29 -0
  89. package/dist/vue-components66.es.js +5 -0
  90. package/dist/vue-components67.es.js +29 -0
  91. package/dist/vue-components68.es.js +6 -0
  92. package/dist/vue-components69.es.js +18 -0
  93. package/dist/vue-components7.es.js +13 -0
  94. package/dist/vue-components70.es.js +40 -0
  95. package/dist/vue-components71.es.js +81 -0
  96. package/dist/vue-components72.es.js +33 -0
  97. package/dist/vue-components73.es.js +19 -0
  98. package/dist/vue-components74.es.js +48 -0
  99. package/dist/vue-components8.es.js +35 -0
  100. package/dist/vue-components9.es.js +47 -0
  101. package/package.json +35 -31
  102. package/src/components/CommandButton.vue +55 -7
  103. package/src/components/OmegaForm/OmegaArray.vue +2 -4
  104. package/src/components/OmegaForm/OmegaAutoGen.vue +27 -31
  105. package/src/components/OmegaForm/OmegaErrorsInternal.vue +3 -4
  106. package/src/components/OmegaForm/OmegaFormInput.vue +1 -1
  107. package/src/components/OmegaForm/OmegaInput.vue +7 -36
  108. package/src/components/OmegaForm/OmegaInputVuetify.vue +5 -2
  109. package/src/components/OmegaForm/OmegaInternalInput.vue +21 -11
  110. package/src/components/OmegaForm/OmegaTaggedUnion.vue +2 -1
  111. package/src/components/OmegaForm/OmegaTaggedUnionInternal.vue +1 -1
  112. package/src/components/OmegaForm/OmegaWrapper.vue +1 -1
  113. package/src/components/OmegaForm/blockDialog.ts +18 -6
  114. package/src/components/OmegaForm/createUseFormWithCustomInput.ts +2 -1
  115. package/src/components/OmegaForm/errors.ts +136 -0
  116. package/src/components/OmegaForm/getOmegaStore.ts +1 -1
  117. package/src/components/OmegaForm/hocs.ts +19 -0
  118. package/src/components/OmegaForm/index.ts +16 -4
  119. package/src/components/OmegaForm/inputs.ts +22 -0
  120. package/src/components/OmegaForm/meta/checks.ts +81 -0
  121. package/src/components/OmegaForm/meta/createMeta.ts +138 -0
  122. package/src/components/OmegaForm/meta/defaults.ts +132 -0
  123. package/src/components/OmegaForm/meta/redacted.ts +66 -0
  124. package/src/components/OmegaForm/meta/types.ts +78 -0
  125. package/src/components/OmegaForm/meta/walker.ts +248 -0
  126. package/src/components/OmegaForm/persistency.ts +247 -0
  127. package/src/components/OmegaForm/submit.ts +128 -0
  128. package/src/components/OmegaForm/types.ts +751 -0
  129. package/src/components/OmegaForm/useOmegaForm.ts +58 -895
  130. package/src/components/OmegaForm/validation/localized.ts +202 -0
  131. package/src/index.ts +0 -1
  132. package/src/reset.css +52 -0
  133. package/src/utils/index.ts +9 -10
  134. package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +0 -157
  135. package/dist/types/constants/index.d.ts +0 -1
  136. package/dist/vue-components.es10.js +0 -237
  137. package/dist/vue-components.es100.js +0 -4
  138. package/dist/vue-components.es11.js +0 -32
  139. package/dist/vue-components.es12.js +0 -439
  140. package/dist/vue-components.es13.js +0 -49
  141. package/dist/vue-components.es14.js +0 -4
  142. package/dist/vue-components.es15.js +0 -4
  143. package/dist/vue-components.es16.js +0 -725
  144. package/dist/vue-components.es17.js +0 -143
  145. package/dist/vue-components.es18.js +0 -6
  146. package/dist/vue-components.es19.js +0 -13
  147. package/dist/vue-components.es2.js +0 -30
  148. package/dist/vue-components.es20.js +0 -5
  149. package/dist/vue-components.es21.js +0 -26
  150. package/dist/vue-components.es22.js +0 -6
  151. package/dist/vue-components.es23.js +0 -10
  152. package/dist/vue-components.es24.js +0 -57
  153. package/dist/vue-components.es25.js +0 -71
  154. package/dist/vue-components.es26.js +0 -8
  155. package/dist/vue-components.es27.js +0 -8
  156. package/dist/vue-components.es28.js +0 -5
  157. package/dist/vue-components.es29.js +0 -5
  158. package/dist/vue-components.es3.js +0 -16
  159. package/dist/vue-components.es30.js +0 -4
  160. package/dist/vue-components.es31.js +0 -4
  161. package/dist/vue-components.es32.js +0 -4
  162. package/dist/vue-components.es33.js +0 -4
  163. package/dist/vue-components.es34.js +0 -19
  164. package/dist/vue-components.es35.js +0 -13
  165. package/dist/vue-components.es36.js +0 -320
  166. package/dist/vue-components.es37.js +0 -563
  167. package/dist/vue-components.es38.js +0 -29
  168. package/dist/vue-components.es39.js +0 -54
  169. package/dist/vue-components.es4.js +0 -52
  170. package/dist/vue-components.es40.js +0 -66
  171. package/dist/vue-components.es41.js +0 -6
  172. package/dist/vue-components.es42.js +0 -6
  173. package/dist/vue-components.es43.js +0 -26
  174. package/dist/vue-components.es44.js +0 -77
  175. package/dist/vue-components.es45.js +0 -42
  176. package/dist/vue-components.es46.js +0 -316
  177. package/dist/vue-components.es47.js +0 -101
  178. package/dist/vue-components.es48.js +0 -33
  179. package/dist/vue-components.es49.js +0 -4
  180. package/dist/vue-components.es5.js +0 -52
  181. package/dist/vue-components.es50.js +0 -4
  182. package/dist/vue-components.es51.js +0 -4
  183. package/dist/vue-components.es52.js +0 -113
  184. package/dist/vue-components.es54.js +0 -9
  185. package/dist/vue-components.es55.js +0 -34
  186. package/dist/vue-components.es57.js +0 -194
  187. package/dist/vue-components.es59.js +0 -40
  188. package/dist/vue-components.es6.js +0 -69
  189. package/dist/vue-components.es60.js +0 -85
  190. package/dist/vue-components.es61.js +0 -43
  191. package/dist/vue-components.es62.js +0 -7
  192. package/dist/vue-components.es63.js +0 -6
  193. package/dist/vue-components.es64.js +0 -25
  194. package/dist/vue-components.es65.js +0 -7
  195. package/dist/vue-components.es66.js +0 -23
  196. package/dist/vue-components.es67.js +0 -32
  197. package/dist/vue-components.es68.js +0 -24
  198. package/dist/vue-components.es69.js +0 -14
  199. package/dist/vue-components.es7.js +0 -83
  200. package/dist/vue-components.es70.js +0 -7
  201. package/dist/vue-components.es71.js +0 -21
  202. package/dist/vue-components.es72.js +0 -11
  203. package/dist/vue-components.es73.js +0 -33
  204. package/dist/vue-components.es74.js +0 -50
  205. package/dist/vue-components.es75.js +0 -28
  206. package/dist/vue-components.es76.js +0 -103
  207. package/dist/vue-components.es77.js +0 -84
  208. package/dist/vue-components.es78.js +0 -23
  209. package/dist/vue-components.es79.js +0 -14
  210. package/dist/vue-components.es8.js +0 -63
  211. package/dist/vue-components.es80.js +0 -115
  212. package/dist/vue-components.es81.js +0 -5
  213. package/dist/vue-components.es82.js +0 -34
  214. package/dist/vue-components.es83.js +0 -4
  215. package/dist/vue-components.es84.js +0 -4
  216. package/dist/vue-components.es85.js +0 -18
  217. package/dist/vue-components.es86.js +0 -17
  218. package/dist/vue-components.es87.js +0 -72
  219. package/dist/vue-components.es88.js +0 -10
  220. package/dist/vue-components.es89.js +0 -4
  221. package/dist/vue-components.es9.js +0 -21
  222. package/dist/vue-components.es90.js +0 -17
  223. package/dist/vue-components.es91.js +0 -13
  224. package/dist/vue-components.es92.js +0 -67
  225. package/dist/vue-components.es93.js +0 -58
  226. package/dist/vue-components.es94.js +0 -19
  227. package/dist/vue-components.es95.js +0 -35
  228. package/dist/vue-components.es96.js +0 -31
  229. package/dist/vue-components.es97.js +0 -44
  230. package/dist/vue-components.es98.js +0 -4
  231. package/dist/vue-components.es99.js +0 -46
  232. package/src/components/OmegaForm/OmegaFormStuff.ts +0 -1174
  233. package/src/constants/index.ts +0 -1
@@ -1,678 +1,35 @@
1
1
  /* eslint-disable @typescript-eslint/consistent-type-imports */
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
3
 
4
- import * as api from "@opentelemetry/api"
5
- import { type DeepKeys, DeepValue, type FormAsyncValidateOrFn, type FormValidateOrFn, type StandardSchemaV1, StandardSchemaV1Issue, useForm, ValidationError, ValidationErrorMap } from "@tanstack/vue-form"
6
- import { runtimeFiberAsPromise, UnionToTuples } from "effect-app/utils"
7
- import * as Data from "effect/Data"
8
- import * as Effect from "effect/Effect"
9
- import * as Fiber from "effect/Fiber"
10
- import * as Option from "effect/Option"
11
- import * as Order from "effect/Order"
12
- import * as S from "effect/Schema"
13
- import { Component, computed, ComputedRef, ConcreteComponent, h, type InjectionKey, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from "vue"
14
- import { useIntl } from "../../utils"
15
- import { MergedInputProps } from "./InputProps"
4
+ import { type FormAsyncValidateOrFn, type FormValidateOrFn, revalidateLogic, type StandardSchemaV1, useForm } from "@tanstack/vue-form"
5
+ import { Context, S } from "effect-app"
6
+ import { type InjectionKey, watch } from "vue"
7
+ import { eHoc, makeFieldMap } from "./errors"
8
+ import { fHoc } from "./hocs"
9
+ import { generateMetaFromSchema } from "./meta/createMeta"
10
+ import { defaultsValueFromSchema } from "./meta/defaults"
11
+ import { toFormSchema } from "./meta/redacted"
16
12
  import OmegaArray from "./OmegaArray.vue"
17
13
  import OmegaAutoGen from "./OmegaAutoGen.vue"
18
14
  import OmegaErrorsInternal from "./OmegaErrorsInternal.vue"
19
- import { BaseProps, deepMerge, defaultsValueFromSchema, DefaultTypeProps, FieldPath, type FormProps, generateMetaFromSchema, type MetaRecord, type NestedKeyOf, OmegaArrayProps, OmegaAutoGenMeta, OmegaError, type OmegaFormApi, OmegaFormState } from "./OmegaFormStuff"
20
15
  import OmegaInput from "./OmegaInput.vue"
21
16
  import OmegaTaggedUnion from "./OmegaTaggedUnion.vue"
22
17
  import OmegaForm from "./OmegaWrapper.vue"
18
+ import { usePersistency } from "./persistency"
19
+ import { makeSubmitHandlers, wrapOnSubmit } from "./submit"
20
+ import type { DefaultTypeProps, FormProps, OF, OmegaConfig, OmegaFormApi, OmegaFormReturn } from "./types"
21
+ import { annotateLiteralUnionMessages, toLocalizedStandardSchemaV1 } from "./validation/localized"
23
22
 
24
- type keysRule<T> =
25
- | {
26
- keys?: NestedKeyOf<T>[]
27
- banKeys?: "You should only use one of banKeys or keys, not both, moron"
28
- }
29
- | {
30
- keys?: "You should only use one of banKeys or keys, not both, moron"
31
- banKeys?: NestedKeyOf<T>[]
32
- }
33
-
34
- export class FormErrors<From> extends Data.TaggedError("FormErrors")<{
35
- form: {
36
- // TODO: error shapes seem off, with `undefined` etc..
37
- errors: (Record<string, StandardSchemaV1Issue[]> | undefined)[]
38
- errorMap: ValidationErrorMap<
39
- undefined,
40
- undefined,
41
- Record<string, StandardSchemaV1Issue[]>,
42
- undefined,
43
- undefined,
44
- undefined,
45
- undefined,
46
- undefined,
47
- undefined,
48
- undefined
49
- >
50
- }
51
- fields: Record<DeepKeys<From>, {
52
- errors: ValidationError[]
53
- errorMap: ValidationErrorMap
54
- }>
55
- }> {}
56
-
57
- const fHoc = (form: OF<any, any>) => {
58
- return function FormHoc<P>(
59
- WrappedComponent: Component<P>
60
- ): ConcreteComponent<P> {
61
- return {
62
- render() {
63
- return h(WrappedComponent, {
64
- form,
65
- ...this.$attrs
66
- } as any, this.$slots)
67
- }
68
- }
69
- }
70
- }
71
-
72
- export const useErrorLabel = (form: OF<any, any>) => {
73
- const { formatMessage } = useIntl()
74
- const humanize = (str: string) => {
75
- return str
76
- .replace(/([A-Z])/g, " $1") // Add space before capital letters
77
- .replace(/^./, (char) => char.toUpperCase()) // Capitalize the first letter
78
- .trim() // Remove leading/trailing spaces
79
- }
80
- const fallback = (propsName: string) =>
81
- formatMessage
82
- ? formatMessage({ id: `general.fields.${propsName}`, defaultMessage: humanize(propsName) })
83
- : humanize(propsName)
84
- const i18n = (propsName: string) =>
85
- form.i18nNamespace
86
- ? formatMessage({ id: `${form.i18nNamespace}.fields.${propsName}`, defaultMessage: fallback(propsName) })
87
- : fallback(propsName)
88
-
89
- return i18n
90
- }
91
-
92
- const eHoc = (errorProps: {
93
- form: OF<any, any>
94
- fieldMap: Ref<Map<string, { id: string; label: string }>>
95
- }) => {
96
- return function FormHoc<P>(
97
- WrappedComponent: Component<P>
98
- ): ConcreteComponent<P> {
99
- return {
100
- setup() {
101
- const { fieldMap, form } = errorProps
102
- const generalErrors = form.useStore((state) => state.errors)
103
- const fieldMeta = form.useStore((state) => state.fieldMeta)
104
- const errorMap = form.useStore((state) => state.errorMap)
105
-
106
- const errorLabel = useErrorLabel(form)
107
-
108
- const errors = computed(() => {
109
- // Collect errors from fieldMeta (field-level errors for registered fields)
110
- const fieldErrors = Object
111
- .entries(fieldMeta.value)
112
- .reduce<OmegaError[]>((acc, [key, m]) => {
113
- const fieldErrors = (m as { errors?: Array<{ message?: string }> } | undefined)?.errors ?? []
114
- if (!fieldErrors.length) {
115
- return acc
116
- }
117
-
118
- const fieldInfo = fieldMap.value.get(key)
119
- if (!fieldInfo) {
120
- return acc
121
- }
122
-
123
- acc.push({
124
- label: fieldInfo.label,
125
- inputId: fieldInfo.id,
126
- errors: [fieldErrors[0]?.message].filter(Boolean) as string[]
127
- })
128
- return acc
129
- }, [])
130
-
131
- // Collect errors from errorMap.onSubmit ONLY for fields that are NOT registered
132
- // (registered fields already have their errors in fieldMeta)
133
- const submitErrors: OmegaError[] = []
134
- if (errorMap.value.onSubmit) {
135
- for (const [_, issues] of Object.entries(errorMap.value.onSubmit)) {
136
- if (Array.isArray(issues) && issues.length) {
137
- for (const issue of issues) {
138
- const issAny: any = issue
139
- if (issAny?.path && Array.isArray(issAny.path) && issAny.path.length) {
140
- // Use the path from the issue to identify the field
141
- const fieldPath = issAny.path.join(".")
142
- // Only add errors for fields that are NOT registered (not in fieldMap)
143
- // Registered fields will already have their errors from fieldMeta
144
- if (!fieldMap.value.has(fieldPath)) {
145
- submitErrors.push({
146
- label: errorLabel(fieldPath),
147
- inputId: fieldPath,
148
- errors: [issAny.message].filter(Boolean)
149
- })
150
- // Only show first error per field, so break after adding
151
- break
152
- }
153
- }
154
- }
155
- }
156
- }
157
- }
158
-
159
- // Combine both error sources (no need to check for duplicates since they're mutually exclusive)
160
- return [...fieldErrors, ...submitErrors]
161
- })
162
-
163
- return {
164
- generalErrors,
165
- errors
166
- }
167
- },
168
- render({ errors, generalErrors }: any) {
169
- return h(WrappedComponent, {
170
- errors,
171
- generalErrors,
172
- ...this.$attrs
173
- } as any, this.$slots)
174
- }
175
- }
176
- }
177
- }
178
-
179
- export type Policies = "local" | "session" | "querystring"
180
- export type defaultValuesPriorityUnion = "tanstack" | "persistency" | "schema"
181
-
182
- const includesPolicy = (arr: Policies[], policy: Policies) => {
183
- return arr.includes(policy)
184
- }
185
-
186
- export type OmegaConfig<T> = {
187
- i18nNamespace?: string
188
-
189
- persistency?: {
190
- /** Order of importance:
191
- * - "querystring": Highest priority when persisting
192
- * - "local" and then "session": Lower priority storage options
193
- */
194
- policies?: UnionToTuples<Policies>
195
- overrideDefaultValues?: "deprecated: use defaultValuesPriority"
196
- id?: string
197
- } & keysRule<T>
198
-
199
- ignorePreventCloseEvents?: boolean
200
-
201
- /**
202
- * Prevents browser window/tab exit when form has unsaved changes.
203
- * Shows native browser "Leave site?" dialog.
204
- *
205
- * @remarks
206
- * - Opt-in only: Must explicitly enable
207
- * - Independent from data persistence feature
208
- */
209
- preventWindowExit?: "prevent" | "prevent-and-reset" | "nope"
210
-
211
- input?: any
212
-
213
- /**
214
- * Default values order is: Tanstack default values passed as second parameter to useOmegaForm, then persistency
215
- * default values from querystring or local/session storage, then defaults from schema
216
- * You can customize the order and with omegaConfig.defaultValuesPriority
217
- * default value = ['tanstack', 'persistency', 'schema']
218
- */
219
- defaultValuesPriority?: UnionToTuples<defaultValuesPriorityUnion>
220
-
221
- defaultFromSchema?: "deprecated: use defaultValuesPriority"
222
- }
23
+ import { makeRunPromise } from "@effect-app/vue/runtime"
24
+ import { useIntl } from "../../utils"
223
25
 
224
- export interface OF<From, To> extends OmegaFormApi<From, To> {
225
- meta: MetaRecord<From>
226
- unionMeta: Record<string, MetaRecord<From>>
227
- clear: () => void
228
- i18nNamespace?: string
229
- ignorePreventCloseEvents?: boolean
230
- registerField: (
231
- field: ComputedRef<{
232
- name: string
233
- label: string
234
- id: string
235
- }>
236
- ) => void
237
- /** @experimental */
238
- handleSubmitEffect: {
239
- /**
240
- * when `checkErrors` is true, the Effect will fail with `FormErrors<From>` when there are validation errors
241
- * @experimental */
242
- (options: { checkErrors: true; meta?: Record<string, any> }): Effect.Effect<void, FormErrors<From>>
243
- /** @experimental */
244
- (options?: { meta?: Record<string, any> }): Effect.Effect<void>
245
- }
246
- }
26
+ export { useErrorLabel } from "./errors"
27
+ export { FormErrors } from "./submit"
28
+ export type { defaultValuesPriorityUnion, OF, OmegaConfig, OmegaFormReturn, Policies } from "./types"
247
29
 
248
30
  export const OmegaFormKey = Symbol("OmegaForm") as InjectionKey<OF<any, any>>
249
31
 
250
- type __VLS_PrettifyLocal<T> =
251
- & {
252
- [K in keyof T]: T[K]
253
- }
254
- & {}
255
-
256
- // Type aliases for Array component slots - using cached types for performance
257
- type CachedFieldApi<From, To, TypeProps = DefaultTypeProps> = import("@tanstack/vue-form").FieldApi<
258
- From,
259
- OmegaFormReturn<From, To, TypeProps>["_keys"],
260
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>,
261
- | import("@tanstack/vue-form").FieldValidateOrFn<
262
- From,
263
- OmegaFormReturn<From, To, TypeProps>["_keys"],
264
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
265
- >
266
- | undefined,
267
- | import("@tanstack/vue-form").FieldValidateOrFn<
268
- From,
269
- OmegaFormReturn<From, To, TypeProps>["_keys"],
270
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
271
- >
272
- | undefined,
273
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
274
- From,
275
- OmegaFormReturn<From, To, TypeProps>["_keys"],
276
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
277
- >
278
- | undefined,
279
- | import("@tanstack/vue-form").FieldValidateOrFn<
280
- From,
281
- OmegaFormReturn<From, To, TypeProps>["_keys"],
282
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
283
- >
284
- | undefined,
285
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
286
- From,
287
- OmegaFormReturn<From, To, TypeProps>["_keys"],
288
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
289
- >
290
- | undefined,
291
- | import("@tanstack/vue-form").FieldValidateOrFn<
292
- From,
293
- OmegaFormReturn<From, To, TypeProps>["_keys"],
294
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
295
- >
296
- | undefined,
297
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
298
- From,
299
- OmegaFormReturn<From, To, TypeProps>["_keys"],
300
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
301
- >
302
- | undefined,
303
- | import("@tanstack/vue-form").FieldValidateOrFn<
304
- From,
305
- OmegaFormReturn<From, To, TypeProps>["_keys"],
306
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
307
- >
308
- | undefined,
309
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
310
- From,
311
- OmegaFormReturn<From, To, TypeProps>["_keys"],
312
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
313
- >
314
- | undefined,
315
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
316
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
317
- import("@tanstack/vue-form").StandardSchemaV1<From, To>,
318
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
319
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined,
320
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
321
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined,
322
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
323
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined,
324
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined,
325
- Record<string, any> | undefined
326
- >
327
-
328
- type CachedFieldState<From, To, TypeProps = DefaultTypeProps> = import("@tanstack/vue-form").FieldState<
329
- From,
330
- OmegaFormReturn<From, To, TypeProps>["_keys"],
331
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>,
332
- | import("@tanstack/vue-form").FieldValidateOrFn<
333
- From,
334
- OmegaFormReturn<From, To, TypeProps>["_keys"],
335
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
336
- >
337
- | undefined,
338
- | import("@tanstack/vue-form").FieldValidateOrFn<
339
- From,
340
- OmegaFormReturn<From, To, TypeProps>["_keys"],
341
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
342
- >
343
- | undefined,
344
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
345
- From,
346
- OmegaFormReturn<From, To, TypeProps>["_keys"],
347
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
348
- >
349
- | undefined,
350
- | import("@tanstack/vue-form").FieldValidateOrFn<
351
- From,
352
- OmegaFormReturn<From, To, TypeProps>["_keys"],
353
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
354
- >
355
- | undefined,
356
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
357
- From,
358
- OmegaFormReturn<From, To, TypeProps>["_keys"],
359
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
360
- >
361
- | undefined,
362
- | import("@tanstack/vue-form").FieldValidateOrFn<
363
- From,
364
- OmegaFormReturn<From, To, TypeProps>["_keys"],
365
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
366
- >
367
- | undefined,
368
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
369
- From,
370
- OmegaFormReturn<From, To, TypeProps>["_keys"],
371
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
372
- >
373
- | undefined,
374
- | import("@tanstack/vue-form").FieldValidateOrFn<
375
- From,
376
- OmegaFormReturn<From, To, TypeProps>["_keys"],
377
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
378
- >
379
- | undefined,
380
- | import("@tanstack/vue-form").FieldAsyncValidateOrFn<
381
- From,
382
- OmegaFormReturn<From, To, TypeProps>["_keys"],
383
- DeepValue<From, OmegaFormReturn<From, To, TypeProps>["_keys"]>
384
- >
385
- | undefined,
386
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
387
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
388
- import("@tanstack/vue-form").StandardSchemaV1<From, To>,
389
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
390
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined,
391
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
392
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined,
393
- import("@tanstack/vue-form").FormValidateOrFn<From> | undefined,
394
- import("@tanstack/vue-form").FormAsyncValidateOrFn<From> | undefined
395
- >
396
-
397
- export interface OmegaFormReturn<
398
- From extends Record<PropertyKey, any>,
399
- To extends Record<PropertyKey, any>,
400
- TypeProps = DefaultTypeProps
401
- > extends OF<From, To> {
402
- // Pre-computed type aliases - computed ONCE for performance
403
- _paths: FieldPath<From>
404
- _keys: DeepKeys<From>
405
- _schema: S.Codec<To, From, never>
406
-
407
- // this crazy thing here is copied from the OmegaFormInput.vue.d.ts, with `From` removed as Generic, instead closed over from the From generic above..
408
- Input: <Name extends OmegaFormReturn<From, To, TypeProps>["_paths"]>(
409
- __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"],
410
- __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
411
- __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
412
- __VLS_setup?: Promise<{
413
- props:
414
- & __VLS_PrettifyLocal<
415
- & Pick<
416
- & Partial<{}>
417
- & Omit<
418
- {} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps,
419
- never
420
- >,
421
- never
422
- >
423
- & TypeProps
424
- & Partial<{}>
425
- >
426
- & BaseProps<From, Name>
427
- & import("vue").PublicProps
428
- expose(exposed: import("vue").ShallowUnwrapRef<{}>): void
429
- attrs: any
430
- slots: {
431
- default?(props: MergedInputProps<From, Name>): void
432
- label?: (props: { required: boolean; id: string; label: string }) => void
433
- }
434
- emit: {}
435
- }>
436
- ) => import("vue").VNode & {
437
- __ctx?: Awaited<typeof __VLS_setup>
438
- }
439
- Errors: (
440
- __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"],
441
- __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
442
- __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
443
- __VLS_setup?: Promise<{
444
- props:
445
- & __VLS_PrettifyLocal<
446
- & Pick<
447
- & Partial<{}>
448
- & Omit<
449
- {} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps,
450
- never
451
- >,
452
- never
453
- >
454
- & Partial<{}>
455
- >
456
- & import("vue").PublicProps
457
- expose(exposed: import("vue").ShallowUnwrapRef<{}>): void
458
- attrs: any
459
- slots: {
460
- default: (props: { errors: readonly OmegaError[]; showedGeneralErrors: string[] }) => void
461
- }
462
- emit: {}
463
- }>
464
- ) => import("vue").VNode & {
465
- __ctx?: Awaited<typeof __VLS_setup>
466
- }
467
- TaggedUnion: <Name extends OmegaFormReturn<From, To, TypeProps>["_keys"]>(
468
- __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"],
469
- __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
470
- __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
471
- __VLS_setup?: Promise<{
472
- props:
473
- & __VLS_PrettifyLocal<
474
- & Pick<
475
- & Partial<{}>
476
- & Omit<
477
- {} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps,
478
- never
479
- >,
480
- never
481
- >
482
- & {
483
- name?: Name
484
- type?: "select" | "radio"
485
- options: import("./InputProps").TaggedUnionOptionsArray<From, Name>
486
- _debugName?: [NoInfer<Name>]
487
- label?: string
488
- }
489
- & {}
490
- >
491
- & import("vue").PublicProps
492
- expose(exposed: import("vue").ShallowUnwrapRef<{}>): void
493
- attrs: any
494
- slots: Record<
495
- string,
496
- (props: {
497
- field: import("@tanstack/vue-form").FieldApi<
498
- From,
499
- Name,
500
- DeepValue<From, Name>,
501
- any,
502
- any,
503
- any,
504
- any,
505
- any,
506
- any,
507
- any,
508
- any,
509
- any,
510
- any,
511
- any,
512
- any,
513
- any,
514
- any,
515
- any,
516
- any,
517
- any,
518
- any,
519
- any,
520
- any
521
- >
522
- state: import("@tanstack/vue-form").FieldState<
523
- From,
524
- Name,
525
- DeepValue<From, Name>,
526
- any,
527
- any,
528
- any,
529
- any,
530
- any,
531
- any,
532
- any,
533
- any,
534
- any,
535
- any,
536
- any,
537
- any,
538
- any,
539
- any,
540
- any,
541
- any,
542
- any,
543
- any
544
- >
545
- }) => any
546
- >
547
- emit: {}
548
- }>
549
- ) => import("vue").VNode & {
550
- __ctx?: Awaited<typeof __VLS_setup>
551
- }
552
- Array: <Name extends OmegaFormReturn<From, To, TypeProps>["_keys"]>(
553
- __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"],
554
- __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
555
- __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
556
- __VLS_setup?: Promise<{
557
- props:
558
- & __VLS_PrettifyLocal<
559
- & Pick<
560
- & Partial<{}>
561
- & Omit<
562
- {} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps,
563
- never
564
- >,
565
- never
566
- >
567
- & (Omit<OmegaArrayProps<From, To, Name>, "form">)
568
- & {}
569
- >
570
- & import("vue").PublicProps
571
- expose(exposed: import("vue").ShallowUnwrapRef<{}>): void
572
- attrs: any
573
- slots: {
574
- "pre-array"?: (props: {
575
- field: CachedFieldApi<From, To, TypeProps>
576
- state: CachedFieldState<From, To, TypeProps>
577
- }) => any
578
- } & {
579
- default?: (props: {
580
- subField: CachedFieldApi<From, To, TypeProps>
581
- subState: CachedFieldState<From, To, TypeProps>
582
- index: number
583
- field: CachedFieldApi<From, To, TypeProps>
584
- }) => any
585
- } & {
586
- "post-array"?: (props: {
587
- field: CachedFieldApi<From, To, TypeProps>
588
- state: CachedFieldState<From, To, TypeProps>
589
- }) => any
590
- } & {
591
- field?: (props: {
592
- field: CachedFieldApi<From, To, TypeProps>
593
- }) => any
594
- }
595
- emit: {}
596
- }>
597
- ) => import("vue").VNode & {
598
- __ctx?: Awaited<typeof __VLS_setup>
599
- }
600
-
601
- AutoGen: <Name extends OmegaFormReturn<From, To, TypeProps>["_keys"]>(
602
- __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"],
603
- __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
604
- __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
605
- __VLS_setup?: Promise<{
606
- props:
607
- & __VLS_PrettifyLocal<
608
- Pick<
609
- & Partial<{}>
610
- & Omit<
611
- {} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps,
612
- never
613
- >,
614
- never
615
- > & {
616
- // form: OmegaInputProps<From, To>["form"]
617
- pick?: OmegaFormReturn<From, To, TypeProps>["_keys"][]
618
- omit?: OmegaFormReturn<From, To, TypeProps>["_keys"][]
619
- labelMap?: (key: OmegaFormReturn<From, To, TypeProps>["_keys"]) => string | undefined
620
- filterMap?: <M extends OmegaAutoGenMeta<From, To, Name>>(
621
- key: OmegaFormReturn<From, To, TypeProps>["_keys"],
622
- meta: M
623
- ) => boolean | M
624
- order?: OmegaFormReturn<From, To, TypeProps>["_keys"][]
625
- sort?: Order.Order<OmegaAutoGenMeta<From, To, Name>>
626
- } & {}
627
- >
628
- & import("vue").PublicProps
629
- expose(exposed: import("vue").ShallowUnwrapRef<{}>): void
630
- attrs: any
631
- slots: {
632
- default(props: {
633
- child: OmegaAutoGenMeta<From, To, Name>
634
- }): void
635
- }
636
- emit: {}
637
- }>
638
- ) => import("vue").VNode & {
639
- __ctx?: Awaited<typeof __VLS_setup>
640
- }
641
-
642
- Form: <K extends keyof OmegaFormState<To, From>>(
643
- __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"],
644
- __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
645
- __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
646
- __VLS_setup?: Promise<{
647
- props:
648
- & __VLS_PrettifyLocal<
649
- Pick<
650
- & Partial<{}>
651
- & Omit<
652
- {} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps,
653
- never
654
- >,
655
- never
656
- > & {
657
- // form: OmegaFormReturn<From, To, Props>
658
- disabled?: boolean
659
- subscribe?: K[]
660
- } & {}
661
- >
662
- & import("vue").PublicProps
663
- expose(exposed: import("vue").ShallowUnwrapRef<{}>): void
664
- attrs: any
665
- slots: {
666
- default(props: {
667
- subscribedValues: K[] extends undefined[] ? Record<string, never> : Pick<OmegaFormState<From, To>, K>
668
- }): void
669
- }
670
- emit: {}
671
- }>
672
- ) => import("vue").VNode & {
673
- __ctx?: Awaited<typeof __VLS_setup>
674
- }
675
- }
32
+ const runPromise = makeRunPromise(Context.empty())
676
33
 
677
34
  export const useOmegaForm = <
678
35
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -681,98 +38,41 @@ export const useOmegaForm = <
681
38
  To extends Record<PropertyKey, any>,
682
39
  TypeProps = DefaultTypeProps
683
40
  >(
684
- schema: S.Codec<To, From, never>,
41
+ schema: S.Codec<To, From>,
685
42
  tanstackFormOptions?: NoInfer<FormProps<From, To>>,
686
43
  omegaConfig?: OmegaConfig<To>
687
44
  ): OmegaFormReturn<From, To, TypeProps> => {
688
45
  if (!schema) throw new Error("Schema is required")
689
- const standardSchema = S.toStandardSchemaV1(schema)
690
- const decode = S.decodeEffect(schema)
691
-
692
- const { meta, unionMeta } = generateMetaFromSchema(schema)
693
-
694
- const persistencyKey = computed(() => {
695
- if (omegaConfig?.persistency?.id) {
696
- return omegaConfig.persistency.id
697
- }
698
- const path = window.location.pathname
699
- const keys = Object.keys(meta)
700
- return `${path}-${keys.join("-")}`
701
- })
702
-
703
- const clearUrlParams = () => {
704
- const params = new URLSearchParams(window.location.search)
705
- params.delete(persistencyKey.value)
706
- const url = new URL(window.location.href)
707
- url.search = params.toString()
708
- window.history.replaceState({}, "", url.toString())
709
- }
710
-
711
- const defaultValues = computed(() => {
712
- // will contain what we get from querystring or local/session storage
713
- let persistencyDefaultValues
714
-
715
- const persistency = omegaConfig?.persistency
716
-
717
- if (
718
- // query string has higher priority than local/session storage
719
- persistency?.policies
720
- && !persistencyDefaultValues
721
- && (includesPolicy(persistency.policies, "local")
722
- || includesPolicy(persistency.policies, "session"))
723
- ) {
724
- const storage = includesPolicy(persistency.policies, "local")
725
- ? localStorage
726
- : sessionStorage
727
- if (storage) {
728
- try {
729
- const value = JSON.parse(
730
- storage.getItem(persistencyKey.value) || "{}"
731
- )
732
- storage.removeItem(persistencyKey.value)
733
- persistencyDefaultValues = value
734
- } catch (error) {
735
- console.error(error)
736
- }
737
- }
738
- }
739
- if (persistency?.policies && includesPolicy(persistency.policies, "querystring")) {
740
- try {
741
- const params = new URLSearchParams(window.location.search)
742
- const value = params.get(persistencyKey.value)
743
- clearUrlParams()
744
- if (value) {
745
- persistencyDefaultValues = deepMerge(persistencyDefaultValues || {}, JSON.parse(value))
746
- }
747
- } catch (error) {
748
- console.error(error)
749
- }
750
- }
751
-
752
- // to be sure we have a valid object at the end of the gathering process
753
- persistencyDefaultValues ??= {}
754
-
755
- const defaults: Record<defaultValuesPriorityUnion, any> = {
756
- tanstack: tanstackFormOptions?.defaultValues || {},
757
- persistency: persistencyDefaultValues,
758
- schema: defaultsValueFromSchema(schema)
759
- }
760
-
761
- return (omegaConfig?.defaultValuesPriority || ["tanstack", "persistency", "schema"] as const).reverse().reduce(
762
- (acc, m) => {
763
- if (!Object.keys(acc).length) {
764
- return defaults[m]
765
- }
766
- return deepMerge(acc, defaults[m])
767
- },
768
- {}
769
- )
46
+ const { trans } = useIntl()
47
+ const formCompatibleSchema = toFormSchema(schema)
48
+ // Effect's Standard Schema formatter emits `Expected X | Y, got Z` for
49
+ // `AnyOf` issues without consulting our hooks. Pre-annotate literal-union
50
+ // (select) and literal-array (multiple) AST nodes with a localized
51
+ // `message` so the formatter picks them up via `findMessage`.
52
+ const localizedSchema = annotateLiteralUnionMessages(formCompatibleSchema, trans)
53
+ const standardSchema = toLocalizedStandardSchemaV1(
54
+ localizedSchema as any,
55
+ trans
56
+ )
57
+ const decode = S.decodeUnknownEffectConcurrently(formCompatibleSchema)
58
+
59
+ const { meta, unionMeta } = generateMetaFromSchema(formCompatibleSchema)
60
+
61
+ // Persistency must be created before `useForm` so its merged
62
+ // `defaultValues` (tanstack + storage/querystring + schema) can flow into
63
+ // the form. The `getForm` accessor is lazy because the form is constructed
64
+ // immediately after, and persistency's listeners only fire later.
65
+ const formHolder: { form: any } = { form: undefined }
66
+ const persistency = usePersistency<From>({
67
+ meta,
68
+ persistency: omegaConfig?.persistency,
69
+ preventWindowExit: omegaConfig?.preventWindowExit,
70
+ defaultValuesPriority: omegaConfig?.defaultValuesPriority,
71
+ tanstackDefaultValues: tanstackFormOptions?.defaultValues,
72
+ schemaDefaultValues: () => defaultsValueFromSchema(schema),
73
+ getForm: () => formHolder.form
770
74
  })
771
75
 
772
- const wrapWithSpan = (span: api.Span | undefined, toWrap: () => any) => {
773
- return span ? api.context.with(api.trace.setSpan(api.context.active(), span), toWrap) : toWrap()
774
- }
775
-
776
76
  const form = useForm<
777
77
  From,
778
78
  FormValidateOrFn<From> | undefined,
@@ -788,31 +88,16 @@ export const useOmegaForm = <
788
88
  Record<string, any> | undefined
789
89
  >({
790
90
  ...tanstackFormOptions,
91
+ validationLogic: revalidateLogic(),
791
92
  validators: {
792
- onSubmit: standardSchema,
793
- ...(tanstackFormOptions?.validators || {})
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ onDynamic: standardSchema as any,
95
+ ...tanstackFormOptions?.validators
794
96
  },
795
- onSubmit: tanstackFormOptions?.onSubmit
796
- ? ({ formApi, meta, value }) =>
797
- wrapWithSpan(meta?.currentSpan, async () => {
798
- // validators only validate, they don't actually transform, so we have to do that manually here.
799
- const parsedValue = await Effect.runPromise(decode(value))
800
- const r = tanstackFormOptions.onSubmit!({
801
- formApi: formApi as OmegaFormApi<From, To>,
802
- meta,
803
- value: parsedValue
804
- })
805
- if (Fiber.isFiber(r)) {
806
- return await runtimeFiberAsPromise(r as any)
807
- }
808
- if (Effect.isEffect(r)) {
809
- return await Effect.runPromise(r)
810
- }
811
- return r
812
- })
813
- : undefined,
814
- defaultValues: defaultValues.value as any
97
+ onSubmit: wrapOnSubmit<From, To>(tanstackFormOptions?.onSubmit, decode, runPromise),
98
+ defaultValues: persistency.defaultValues.value
815
99
  }) satisfies OmegaFormApi<To, From>
100
+ formHolder.form = form
816
101
 
817
102
  const clear = () => {
818
103
  Object.keys(meta).forEach((key: any) => {
@@ -820,88 +105,6 @@ export const useOmegaForm = <
820
105
  })
821
106
  }
822
107
 
823
- const createNestedObjectFromPaths = (paths: string[]) =>
824
- paths.reduce((result, path) => {
825
- const parts = path.split(".")
826
- parts.reduce((acc, part, i) => {
827
- if (i === parts.length - 1) {
828
- acc[part] = form.getFieldValue(path as any)
829
- } else {
830
- acc[part] = acc[part] ?? {}
831
- }
832
- return acc[part]
833
- }, result)
834
- return result
835
- }, {} as Record<string, any>)
836
-
837
- const persistFilter = (persistency: OmegaConfig<From>["persistency"]) => {
838
- if (!persistency) return
839
- if (Array.isArray(persistency.keys)) {
840
- return createNestedObjectFromPaths(persistency.keys)
841
- }
842
- if (Array.isArray(persistency.banKeys)) {
843
- const subs = Object.keys(meta).filter((metakey) => persistency.banKeys?.includes(metakey as any))
844
- return createNestedObjectFromPaths(subs)
845
- }
846
- return form.store.state.values
847
- }
848
-
849
- const persistData = () => {
850
- const persistency = omegaConfig?.persistency
851
- if (!persistency?.policies || persistency.policies.length === 0) {
852
- return
853
- }
854
- if (
855
- includesPolicy(persistency.policies, "local")
856
- || includesPolicy(persistency.policies, "session")
857
- ) {
858
- const storage = includesPolicy(persistency.policies, "local")
859
- ? localStorage
860
- : sessionStorage
861
- if (!storage) return
862
- const values = persistFilter(persistency)
863
- return storage.setItem(persistencyKey.value, JSON.stringify(values))
864
- }
865
- }
866
-
867
- const saveDataInUrl = () => {
868
- const persistency = omegaConfig?.persistency
869
- if (!persistency?.policies || persistency.policies.length === 0) {
870
- return
871
- }
872
- if (includesPolicy(persistency.policies, "querystring")) {
873
- const values = persistFilter(persistency)
874
- const searchParams = new URLSearchParams(window.location.search)
875
- searchParams.set(persistencyKey.value, JSON.stringify(values))
876
- const url = new URL(window.location.href)
877
- url.search = searchParams.toString()
878
- window.history.replaceState({}, "", url.toString())
879
- }
880
- }
881
-
882
- const preventWindowExit = (e: BeforeUnloadEvent) => {
883
- if (form.store.state.isDirty) {
884
- e.preventDefault()
885
- }
886
- }
887
-
888
- onUnmounted(persistData)
889
-
890
- onMounted(() => {
891
- window.addEventListener("beforeunload", persistData)
892
- window.addEventListener("blur", saveDataInUrl)
893
- if (omegaConfig?.preventWindowExit && omegaConfig.preventWindowExit !== "nope") {
894
- window.addEventListener("beforeunload", preventWindowExit)
895
- }
896
- })
897
- onBeforeUnmount(() => {
898
- window.removeEventListener("beforeunload", persistData)
899
- window.removeEventListener("blur", saveDataInUrl)
900
- if (omegaConfig?.preventWindowExit && omegaConfig.preventWindowExit !== "nope") {
901
- window.removeEventListener("beforeunload", preventWindowExit)
902
- }
903
- })
904
-
905
108
  // Watch for successful form submissions and auto-reset if prevent-and-reset is enabled
906
109
  // We put it as a side effect, so we don't overwhelm submit handler and we can support
907
110
  // effects submission more freely
@@ -920,33 +123,9 @@ export const useOmegaForm = <
920
123
  })
921
124
  }
922
125
 
923
- const handleSubmitEffect_ = (meta?: Record<string, any>) =>
924
- Effect.currentSpan.pipe(
925
- Effect.option,
926
- Effect
927
- .flatMap((span) =>
928
- Effect.promise(() => form.handleSubmit(Option.isSome(span) ? { currentSpan: span.value, ...meta } : meta))
929
- )
930
- )
126
+ const { handleSubmit, handleSubmitEffect } = makeSubmitHandlers<From, To>(form)
931
127
 
932
- const handleSubmitEffect: {
933
- (options: { checkErrors: true; meta?: Record<string, any> }): Effect.Effect<void, FormErrors<From>>
934
- (options?: { meta?: Record<string, any> }): Effect.Effect<void>
935
- } = (
936
- options?: { meta?: Record<string, any>; checkErrors?: true }
937
- ): any =>
938
- options?.checkErrors
939
- ? handleSubmitEffect_(options?.meta).pipe(Effect.flatMap(Effect.fnUntraced(function*() {
940
- const errors = form.getAllErrors()
941
- if (Object.keys(errors.fields).length || errors.form.errors.length) {
942
- return yield* new FormErrors({ form: errors.form, fields: errors.fields })
943
- }
944
- })))
945
- : handleSubmitEffect_(options?.meta)
946
-
947
- const handleSubmit = form.handleSubmit
948
-
949
- const fieldMap = ref(new Map<string, { label: string; id: string }>())
128
+ const { fieldMap, registerField } = makeFieldMap()
950
129
 
951
130
  const formWithExtras: OF<From, To> = Object.assign(form, {
952
131
  i18nNamespace: omegaConfig?.i18nNamespace,
@@ -954,26 +133,10 @@ export const useOmegaForm = <
954
133
  meta,
955
134
  unionMeta,
956
135
  clear,
957
- handleSubmit: (meta?: Record<string, any>) => {
958
- const span = api.trace.getSpan(api.context.active())
959
- return handleSubmit({ currentSpan: span, ...meta })
960
- },
136
+ handleSubmit,
961
137
  // /** @experimental */
962
138
  handleSubmitEffect,
963
- registerField: (field: ComputedRef<{ name: string; label: string; id: string }>) => {
964
- watch(field, (f) => {
965
- fieldMap.value.set(f.name, { label: f.label, id: f.id })
966
- }, { immediate: true })
967
- onUnmounted(() => {
968
- // Only delete if we still own this entry (id matches)
969
- // This prevents old components from deleting entries registered by new components
970
- // during re-mount transitions (e.g., when :key changes)
971
- const currentEntry = fieldMap.value.get(field.value.name)
972
- if (currentEntry?.id === field.value.id) {
973
- fieldMap.value.delete(field.value.name)
974
- }
975
- })
976
- }
139
+ registerField
977
140
  })
978
141
 
979
142
  const errorContext = { form: formWithExtras, fieldMap }