@effect-app/vue-components 4.0.0-beta.3 → 4.0.0-beta.300

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 (245) hide show
  1. package/README.md +36 -8
  2. package/dist/reset.css +52 -0
  3. package/dist/types/components/CommandButton.vue.d.ts +24 -5
  4. package/dist/types/components/Dialog.vue.d.ts +3 -1
  5. package/dist/types/components/FixedNuxtErrorBoundary.vue.d.ts +39 -0
  6. package/dist/types/components/OmegaForm/InputProps.d.ts +1 -1
  7. package/dist/types/components/OmegaForm/OmegaArray.vue.d.ts +1 -1
  8. package/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +1 -1
  9. package/dist/types/components/OmegaForm/OmegaErrorsInternal.vue.d.ts +1 -1
  10. package/dist/types/components/OmegaForm/OmegaFormInput.vue.d.ts +1 -1
  11. package/dist/types/components/OmegaForm/OmegaInput.vue.d.ts +1 -1
  12. package/dist/types/components/OmegaForm/OmegaInputVuetify.vue.d.ts +6 -0
  13. package/dist/types/components/OmegaForm/OmegaInternalInput.vue.d.ts +6 -9
  14. package/dist/types/components/OmegaForm/OmegaTaggedUnion.vue.d.ts +2 -2
  15. package/dist/types/components/OmegaForm/OmegaTaggedUnionInternal.vue.d.ts +3 -3
  16. package/dist/types/components/OmegaForm/OmegaWrapper.vue.d.ts +1 -1
  17. package/dist/types/components/OmegaForm/createUseFormWithCustomInput.d.ts +4 -2
  18. package/dist/types/components/OmegaForm/errors.d.ts +33 -0
  19. package/dist/types/components/OmegaForm/getOmegaStore.d.ts +1 -1
  20. package/dist/types/components/OmegaForm/hocs.d.ts +3 -0
  21. package/dist/types/components/OmegaForm/index.d.ts +14 -3
  22. package/dist/types/components/OmegaForm/inputs.d.ts +4 -0
  23. package/dist/types/components/OmegaForm/meta/checks.d.ts +4 -0
  24. package/dist/types/components/OmegaForm/meta/createMeta.d.ts +33 -0
  25. package/dist/types/components/OmegaForm/meta/defaults.d.ts +21 -0
  26. package/dist/types/components/OmegaForm/meta/redacted.d.ts +2 -0
  27. package/dist/types/components/OmegaForm/meta/types.d.ts +56 -0
  28. package/dist/types/components/OmegaForm/meta/walker.d.ts +18 -0
  29. package/dist/types/components/OmegaForm/persistency.d.ts +58 -0
  30. package/dist/types/components/OmegaForm/submit.d.ts +60 -0
  31. package/dist/types/components/OmegaForm/types.d.ts +312 -0
  32. package/dist/types/components/OmegaForm/useOmegaForm.d.ts +9 -215
  33. package/dist/types/components/OmegaForm/validation/localized.d.ts +10 -0
  34. package/dist/types/components/index.d.ts +1 -0
  35. package/dist/types/index.d.ts +0 -1
  36. package/dist/types/utils/index.d.ts +8 -9
  37. package/dist/vue-components.es.js +30 -44
  38. package/dist/vue-components10.es.js +5 -0
  39. package/dist/vue-components11.es.js +56 -0
  40. package/dist/vue-components12.es.js +5 -0
  41. package/dist/vue-components13.es.js +20 -0
  42. package/dist/vue-components14.es.js +49 -0
  43. package/dist/vue-components15.es.js +128 -0
  44. package/dist/vue-components16.es.js +65 -0
  45. package/dist/vue-components17.es.js +114 -0
  46. package/dist/vue-components18.es.js +22 -0
  47. package/dist/vue-components19.es.js +5 -0
  48. package/dist/vue-components2.es.js +11 -0
  49. package/dist/vue-components20.es.js +80 -0
  50. package/dist/vue-components21.es.js +93 -0
  51. package/dist/vue-components22.es.js +73 -0
  52. package/dist/vue-components23.es.js +12 -0
  53. package/dist/vue-components24.es.js +57 -0
  54. package/dist/vue-components25.es.js +5 -0
  55. package/dist/vue-components26.es.js +44 -0
  56. package/dist/vue-components27.es.js +5 -0
  57. package/dist/vue-components28.es.js +84 -0
  58. package/dist/vue-components3.es.js +98 -0
  59. package/dist/vue-components30.es.js +8 -0
  60. package/dist/vue-components31.es.js +9 -0
  61. package/dist/vue-components32.es.js +24 -0
  62. package/dist/vue-components33.es.js +300 -0
  63. package/dist/vue-components35.es.js +8 -0
  64. package/dist/vue-components36.es.js +73 -0
  65. package/dist/vue-components37.es.js +5 -0
  66. package/dist/vue-components38.es.js +64 -0
  67. package/dist/vue-components39.es.js +5 -0
  68. package/dist/vue-components4.es.js +5 -0
  69. package/dist/vue-components40.es.js +24 -0
  70. package/dist/vue-components41.es.js +5 -0
  71. package/dist/vue-components42.es.js +59 -0
  72. package/dist/vue-components43.es.js +5 -0
  73. package/dist/vue-components44.es.js +12 -0
  74. package/dist/vue-components45.es.js +22 -0
  75. package/dist/vue-components47.es.js +9 -0
  76. package/dist/vue-components48.es.js +4 -0
  77. package/dist/vue-components49.es.js +38 -0
  78. package/dist/vue-components5.es.js +24 -0
  79. package/dist/vue-components50.es.js +27 -0
  80. package/dist/vue-components51.es.js +28 -0
  81. package/dist/vue-components52.es.js +7 -0
  82. package/dist/vue-components53.es.js +18 -0
  83. package/dist/vue-components54.es.js +36 -0
  84. package/dist/vue-components55.es.js +18 -0
  85. package/dist/vue-components56.es.js +21 -0
  86. package/dist/vue-components57.es.js +30 -0
  87. package/dist/vue-components58.es.js +7 -0
  88. package/dist/vue-components59.es.js +9 -0
  89. package/dist/vue-components6.es.js +13 -0
  90. package/dist/vue-components60.es.js +38 -0
  91. package/dist/vue-components61.es.js +25 -0
  92. package/dist/vue-components62.es.js +128 -0
  93. package/dist/vue-components63.es.js +24 -0
  94. package/dist/vue-components64.es.js +21 -0
  95. package/dist/vue-components65.es.js +9 -0
  96. package/dist/vue-components66.es.js +19 -0
  97. package/dist/vue-components67.es.js +5 -0
  98. package/dist/vue-components68.es.js +29 -0
  99. package/dist/vue-components69.es.js +5 -0
  100. package/dist/vue-components7.es.js +13 -0
  101. package/dist/vue-components70.es.js +43 -0
  102. package/dist/vue-components71.es.js +101 -0
  103. package/dist/vue-components72.es.js +36 -0
  104. package/dist/vue-components73.es.js +19 -0
  105. package/dist/vue-components74.es.js +50 -0
  106. package/dist/vue-components8.es.js +35 -0
  107. package/dist/vue-components9.es.js +47 -0
  108. package/package.json +44 -34
  109. package/src/components/CommandButton.vue +96 -16
  110. package/src/components/Dialog.vue +0 -1
  111. package/src/components/FixedNuxtErrorBoundary.vue +112 -0
  112. package/src/components/OmegaForm/InputProps.ts +1 -1
  113. package/src/components/OmegaForm/OmegaArray.vue +8 -9
  114. package/src/components/OmegaForm/OmegaAutoGen.vue +26 -30
  115. package/src/components/OmegaForm/OmegaErrorsInternal.vue +3 -4
  116. package/src/components/OmegaForm/OmegaFormInput.vue +1 -1
  117. package/src/components/OmegaForm/OmegaInput.vue +26 -40
  118. package/src/components/OmegaForm/OmegaInputVuetify.vue +58 -8
  119. package/src/components/OmegaForm/OmegaInternalInput.vue +41 -18
  120. package/src/components/OmegaForm/OmegaTaggedUnion.vue +10 -3
  121. package/src/components/OmegaForm/OmegaTaggedUnionInternal.vue +6 -6
  122. package/src/components/OmegaForm/OmegaWrapper.vue +1 -1
  123. package/src/components/OmegaForm/blockDialog.ts +18 -6
  124. package/src/components/OmegaForm/createUseFormWithCustomInput.ts +16 -14
  125. package/src/components/OmegaForm/errors.ts +136 -0
  126. package/src/components/OmegaForm/getOmegaStore.ts +1 -1
  127. package/src/components/OmegaForm/hocs.ts +19 -0
  128. package/src/components/OmegaForm/index.ts +17 -4
  129. package/src/components/OmegaForm/inputs.ts +22 -0
  130. package/src/components/OmegaForm/meta/checks.ts +82 -0
  131. package/src/components/OmegaForm/meta/createMeta.ts +140 -0
  132. package/src/components/OmegaForm/meta/defaults.ts +261 -0
  133. package/src/components/OmegaForm/meta/redacted.ts +66 -0
  134. package/src/components/OmegaForm/meta/types.ts +78 -0
  135. package/src/components/OmegaForm/meta/walker.ts +248 -0
  136. package/src/components/OmegaForm/persistency.ts +247 -0
  137. package/src/components/OmegaForm/submit.ts +131 -0
  138. package/src/components/OmegaForm/types.ts +801 -0
  139. package/src/components/OmegaForm/useOmegaForm.ts +103 -898
  140. package/src/components/OmegaForm/useRegisterField.ts +1 -1
  141. package/src/components/OmegaForm/validation/localized.ts +203 -0
  142. package/src/components/index.ts +1 -0
  143. package/src/index.ts +0 -1
  144. package/src/reset.css +52 -0
  145. package/src/utils/index.ts +10 -11
  146. package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +0 -157
  147. package/dist/types/constants/index.d.ts +0 -1
  148. package/dist/vue-components.es10.js +0 -237
  149. package/dist/vue-components.es100.js +0 -4
  150. package/dist/vue-components.es11.js +0 -32
  151. package/dist/vue-components.es12.js +0 -439
  152. package/dist/vue-components.es13.js +0 -49
  153. package/dist/vue-components.es14.js +0 -4
  154. package/dist/vue-components.es15.js +0 -4
  155. package/dist/vue-components.es16.js +0 -725
  156. package/dist/vue-components.es17.js +0 -143
  157. package/dist/vue-components.es18.js +0 -6
  158. package/dist/vue-components.es19.js +0 -13
  159. package/dist/vue-components.es2.js +0 -30
  160. package/dist/vue-components.es20.js +0 -5
  161. package/dist/vue-components.es21.js +0 -26
  162. package/dist/vue-components.es22.js +0 -6
  163. package/dist/vue-components.es23.js +0 -10
  164. package/dist/vue-components.es24.js +0 -57
  165. package/dist/vue-components.es25.js +0 -71
  166. package/dist/vue-components.es26.js +0 -8
  167. package/dist/vue-components.es27.js +0 -8
  168. package/dist/vue-components.es28.js +0 -5
  169. package/dist/vue-components.es29.js +0 -5
  170. package/dist/vue-components.es3.js +0 -16
  171. package/dist/vue-components.es30.js +0 -4
  172. package/dist/vue-components.es31.js +0 -4
  173. package/dist/vue-components.es32.js +0 -4
  174. package/dist/vue-components.es33.js +0 -4
  175. package/dist/vue-components.es34.js +0 -19
  176. package/dist/vue-components.es35.js +0 -13
  177. package/dist/vue-components.es36.js +0 -40
  178. package/dist/vue-components.es37.js +0 -6
  179. package/dist/vue-components.es38.js +0 -85
  180. package/dist/vue-components.es39.js +0 -54
  181. package/dist/vue-components.es4.js +0 -52
  182. package/dist/vue-components.es40.js +0 -563
  183. package/dist/vue-components.es41.js +0 -43
  184. package/dist/vue-components.es42.js +0 -29
  185. package/dist/vue-components.es43.js +0 -7
  186. package/dist/vue-components.es44.js +0 -42
  187. package/dist/vue-components.es45.js +0 -316
  188. package/dist/vue-components.es46.js +0 -33
  189. package/dist/vue-components.es47.js +0 -6
  190. package/dist/vue-components.es48.js +0 -26
  191. package/dist/vue-components.es49.js +0 -77
  192. package/dist/vue-components.es5.js +0 -52
  193. package/dist/vue-components.es50.js +0 -101
  194. package/dist/vue-components.es51.js +0 -4
  195. package/dist/vue-components.es52.js +0 -320
  196. package/dist/vue-components.es53.js +0 -66
  197. package/dist/vue-components.es54.js +0 -4
  198. package/dist/vue-components.es55.js +0 -4
  199. package/dist/vue-components.es56.js +0 -113
  200. package/dist/vue-components.es58.js +0 -9
  201. package/dist/vue-components.es59.js +0 -34
  202. package/dist/vue-components.es6.js +0 -69
  203. package/dist/vue-components.es61.js +0 -194
  204. package/dist/vue-components.es63.js +0 -6
  205. package/dist/vue-components.es64.js +0 -103
  206. package/dist/vue-components.es65.js +0 -84
  207. package/dist/vue-components.es66.js +0 -17
  208. package/dist/vue-components.es67.js +0 -34
  209. package/dist/vue-components.es68.js +0 -4
  210. package/dist/vue-components.es69.js +0 -23
  211. package/dist/vue-components.es7.js +0 -83
  212. package/dist/vue-components.es70.js +0 -14
  213. package/dist/vue-components.es71.js +0 -115
  214. package/dist/vue-components.es72.js +0 -5
  215. package/dist/vue-components.es73.js +0 -4
  216. package/dist/vue-components.es74.js +0 -4
  217. package/dist/vue-components.es75.js +0 -17
  218. package/dist/vue-components.es76.js +0 -72
  219. package/dist/vue-components.es77.js +0 -25
  220. package/dist/vue-components.es78.js +0 -7
  221. package/dist/vue-components.es79.js +0 -23
  222. package/dist/vue-components.es8.js +0 -63
  223. package/dist/vue-components.es80.js +0 -32
  224. package/dist/vue-components.es81.js +0 -24
  225. package/dist/vue-components.es82.js +0 -14
  226. package/dist/vue-components.es83.js +0 -7
  227. package/dist/vue-components.es84.js +0 -21
  228. package/dist/vue-components.es85.js +0 -11
  229. package/dist/vue-components.es86.js +0 -33
  230. package/dist/vue-components.es87.js +0 -50
  231. package/dist/vue-components.es88.js +0 -28
  232. package/dist/vue-components.es89.js +0 -18
  233. package/dist/vue-components.es9.js +0 -21
  234. package/dist/vue-components.es90.js +0 -10
  235. package/dist/vue-components.es91.js +0 -13
  236. package/dist/vue-components.es92.js +0 -67
  237. package/dist/vue-components.es93.js +0 -58
  238. package/dist/vue-components.es94.js +0 -19
  239. package/dist/vue-components.es95.js +0 -35
  240. package/dist/vue-components.es96.js +0 -31
  241. package/dist/vue-components.es97.js +0 -44
  242. package/dist/vue-components.es98.js +0 -4
  243. package/dist/vue-components.es99.js +0 -46
  244. package/src/components/OmegaForm/OmegaFormStuff.ts +0 -1174
  245. package/src/constants/index.ts +0 -1
@@ -1,9 +1,11 @@
1
1
  <script
2
2
  setup
3
3
  lang="ts"
4
- generic="I = never"
4
+ generic="I = never, RA = unknown, RE = unknown"
5
5
  >
6
- import type { CommandBase } from "@effect-app/vue"
6
+ import type { CommandBase, Progress } from "@effect-app/vue/makeClient"
7
+ import * as Option from "effect-app/Option"
8
+ import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
7
9
  import { computed } from "vue"
8
10
  import type { VBtn } from "vuetify/components"
9
11
 
@@ -14,38 +16,89 @@ const props = defineProps<
14
16
  & (
15
17
  | {
16
18
  input: NoInfer<I>
17
- command: CommandBase<I>
19
+ optionalInput?: undefined
20
+ command: CommandBase<I, any, RA, RE>
18
21
  empty?: boolean
19
22
  }
20
23
  | {
21
- command: CommandBase
24
+ optionalInput: Option.Option<NoInfer<I>>
22
25
  input?: undefined
26
+ command: CommandBase<I, any, RA, RE>
27
+ empty?: boolean
28
+ }
29
+ | {
30
+ command: CommandBase<any, any, RA, RE>
31
+ input?: undefined
32
+ optionalInput?: undefined
23
33
  empty?: boolean
24
34
  }
25
35
  )
26
36
  & {
27
37
  disabled?: ButtonProps["disabled"]
28
38
  title?: string // why isn't it part of VBtnProps??
39
+ mapProgress?: (result: AsyncResult.AsyncResult<RA, RE>) => Progress | undefined
29
40
  }
30
41
  & ButtonProps
31
42
  >()
32
43
 
33
- const isDisabled = computed(() => props.command.blocked || props.disabled)
44
+ const resolvedInput = computed<{ _tag: "ready"; value: I } | { _tag: "missing" } | { _tag: "void" }>(() => {
45
+ if ("optionalInput" in props && props.optionalInput !== undefined) {
46
+ return Option.isSome(props.optionalInput)
47
+ ? { _tag: "ready", value: props.optionalInput.value }
48
+ : { _tag: "missing" }
49
+ }
50
+ if ("input" in props && props.input !== undefined) {
51
+ return { _tag: "ready", value: props.input as I }
52
+ }
53
+ return { _tag: "void" }
54
+ })
34
55
 
35
- const handleClick = () => {
36
- // Block execution if button is disabled
37
- if (isDisabled.value) {
38
- return
56
+ const isDisabled = computed(() =>
57
+ props.command.blocked
58
+ || props.disabled
59
+ || resolvedInput.value._tag === "missing"
60
+ )
61
+
62
+ const resolvedProgress = computed(() => {
63
+ if (props.mapProgress) {
64
+ const result = props.command.result
65
+ return result !== undefined ? props.mapProgress(result) : undefined
39
66
  }
67
+ return props.command.progress
68
+ })
40
69
 
41
- const input = ("input" in props && props.input
42
- ? props.input
43
- : undefined) as unknown as I
44
- ;(props.command.handle as any)(input)
70
+ const progressText = computed(() => {
71
+ const p = resolvedProgress.value
72
+ if (p === undefined) return undefined
73
+ return typeof p === "string" ? p : p.text
74
+ })
75
+
76
+ const progressPercentage = computed(() => {
77
+ const p = resolvedProgress.value
78
+ return typeof p === "object" && p !== null ? p.percentage : undefined
79
+ })
80
+
81
+ const handleClick = () => {
82
+ if (isDisabled.value) return
83
+ const ri = resolvedInput.value
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ const handle = props.command.handle as any
86
+ if (ri._tag === "ready") handle(ri.value)
87
+ else if (ri._tag === "void") handle(undefined)
88
+ // _tag === "missing" can't reach here — guarded by isDisabled
45
89
  }
46
90
  </script>
47
91
  <script lang="ts">
48
- /** Command Button is an easy way to connect commands and have it execute on click, while keeping track of disabled/loading states automatically */
92
+ /**
93
+ * CommandButton connects a command to a button and tracks disabled / loading state.
94
+ *
95
+ * Input variants:
96
+ * - `input`: pass a validated value; button enabled when command + disabled allow it.
97
+ * - `optionalInput`: pass an `Option<I>`. `Some` → enabled, click fires with the value.
98
+ * `None` → disabled. Use this when the input is gated by a `computed` instead of
99
+ * a `v-if` on the button itself.
100
+ * - neither: command takes no input.
101
+ */
49
102
  export default {
50
103
  name: "CommandButton"
51
104
  }
@@ -55,27 +108,54 @@ export default {
55
108
  v-if="command.allowed && !empty"
56
109
  v-bind="$attrs"
57
110
  :loading="command.waiting"
111
+ :disabled="isDisabled"
58
112
  :aria-disabled="isDisabled"
59
113
  :title="title ?? command.action"
60
114
  :class="{ 'v-btn--disabled': isDisabled }"
61
115
  @click="handleClick"
62
116
  >
117
+ <template
118
+ v-if="progressText !== undefined"
119
+ #loader
120
+ >
121
+ <v-progress-circular
122
+ :indeterminate="progressPercentage === undefined"
123
+ :model-value="progressPercentage"
124
+ size="20"
125
+ width="2"
126
+ />
127
+ <span class="ml-2">{{ progressText }}</span>
128
+ </template>
63
129
  <slot
64
130
  :loading="command.waiting"
65
131
  :disabled="isDisabled"
66
132
  :label="command.label"
67
133
  :title="title ?? command.action"
68
134
  >
69
- <span>{{ command.label }}</span>
135
+ {{ command.label }}
70
136
  </slot>
71
137
  </v-btn>
72
138
  <v-btn
73
139
  v-else-if="command.allowed"
74
140
  v-bind="$attrs"
75
141
  :loading="command.waiting"
142
+ :disabled="isDisabled"
76
143
  :aria-disabled="isDisabled"
77
144
  :title="title ?? command.action"
78
145
  :class="{ 'v-btn--disabled': isDisabled }"
79
146
  @click="handleClick"
80
- />
147
+ >
148
+ <template
149
+ v-if="progressText !== undefined"
150
+ #loader
151
+ >
152
+ <v-progress-circular
153
+ :indeterminate="progressPercentage === undefined"
154
+ :model-value="progressPercentage"
155
+ size="20"
156
+ width="2"
157
+ />
158
+ <span class="ml-2">{{ progressText }}</span>
159
+ </template>
160
+ </v-btn>
81
161
  </template>
@@ -12,7 +12,6 @@
12
12
  />
13
13
  </template>
14
14
  <!-- pass down slots -->
15
- <!-- @vue-skip -->
16
15
  <template
17
16
  v-for="(_, name) in otherSlots"
18
17
  #[name]="slotData"
@@ -0,0 +1,112 @@
1
+ <script setup lang="ts">
2
+ import { CauseException } from "effect-app/client"
3
+ import * as Cause from "effect/Cause"
4
+ import { onErrorCaptured, shallowRef } from "vue"
5
+ import { useRouter } from "vue-router"
6
+
7
+ // withDefaults, NOT `props.enabled ?? true`: Vue's boolean casting resolves an
8
+ // ABSENT boolean prop to `false`, so the `??` fallback would never fire and an
9
+ // omitted `enabled` (the frontend case) would silently disable the boundary.
10
+ const props = withDefaults(
11
+ defineProps<{
12
+ captureException: (err: Error, hint?: { extra?: Record<string, unknown> }) => void
13
+ toastError: (message: string) => void
14
+ debug: boolean
15
+ /** register the boundary only when true (backend passes import.meta.client; frontend omits → true) */
16
+ enabled?: boolean
17
+ /** defer handling until app ready (backend: onNuxtReady while hydrating; frontend: omit → run now) */
18
+ scheduleAfterReady?: (fn: () => void) => void
19
+ /** extra side-effect after emit, before error.value is set (backend: nuxtApp vue:error hook) */
20
+ onHandled?: (err: Error, instance: unknown, info: string) => void
21
+ }>(),
22
+ { enabled: true }
23
+ )
24
+
25
+ defineOptions({ name: "NuxtErrorBoundary", inheritAttrs: false })
26
+
27
+ const emit = defineEmits<{ error: [error: Error] }>()
28
+
29
+ defineSlots<{
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ error(props: { error: Error; clearError: () => void }): any
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ default(): any
34
+ }>()
35
+
36
+ const error = shallowRef<Error | null>(null)
37
+ function clearError() {
38
+ error.value = null
39
+ }
40
+
41
+ // lol in production these are different...
42
+ const supportedErrors = ["https://vuejs.org/error-reference/#runtime-0", 0, "0", "setup function"]
43
+
44
+ function handleError(...args: Parameters<Parameters<typeof onErrorCaptured<Error>>[0]>) {
45
+ const [err, instance, info] = args
46
+ const fiberFailure = err instanceof CauseException ? err : null
47
+ // PRO: log that we hit the error boundary
48
+ console.warn(
49
+ "NuxtErrorBoundary caught error in " + info + ": " + (fiberFailure ? "CauseException" : "classic error"),
50
+ fiberFailure ? Cause.pretty(fiberFailure.originalCause) : err,
51
+ instance
52
+ )
53
+
54
+ // PRO: we don't handle native event handlers the same way we handle setup errors,
55
+ // because these errors should only get reported, not take over the page.
56
+ if (!supportedErrors.includes(info)) {
57
+ props.captureException(err, { extra: { info, instance } })
58
+ if (props.debug) {
59
+ props.toastError("An unexpected error has occurred: " + err.toString())
60
+ }
61
+ return
62
+ }
63
+
64
+ // PRO: don't render interruptions..
65
+ // e.g when we run useSuspenseQuery, and we navigate away before a query is finished, we get a CancelledError
66
+ // if we however render it here instead of the default slot, we will show the cancellation error of the previous page, instead of rendering the new page
67
+ //
68
+ // NOTE the engine-side contract that makes this blanket silence safe: `useSuspenseQuery(New)`
69
+ // converts an interrupt that settles while the component is STILL MOUNTED (a query-side interrupt,
70
+ // e.g. a server RPC interrupt Exit — the thing that used to blank the page) into a typed
71
+ // `SuspenseInterruptedError` (@effect-app/vue makeClient), whose cause is NOT interrupt-only and
72
+ // therefore falls through to the error slot below. What remains interrupt-only here is genuinely
73
+ // "navigated away / unmounted" — silencing it is correct and avoids rendering the previous page's
74
+ // cancellation over the new page.
75
+ if (fiberFailure && Cause.hasInterruptsOnly(fiberFailure.originalCause)) {
76
+ return
77
+ }
78
+
79
+ emit("error", err)
80
+ props.onHandled?.(err, instance, info)
81
+ error.value = err
82
+ }
83
+
84
+ if (props.enabled) {
85
+ onErrorCaptured((err, instance, info) => {
86
+ if (props.scheduleAfterReady) props.scheduleAfterReady(() => handleError(err, instance, info))
87
+ else handleError(err, instance, info)
88
+ return false
89
+ })
90
+ }
91
+
92
+ // PRO: fix error not clearing after route change: https://github.com/nuxt/nuxt/issues/15781#issuecomment-2320928163
93
+ const router = useRouter()
94
+ router.afterEach(() => {
95
+ clearError()
96
+ })
97
+
98
+ defineExpose({ error, clearError })
99
+ </script>
100
+
101
+ <template>
102
+ <slot
103
+ v-if="error"
104
+ v-bind="{ error, clearError }"
105
+ name="error"
106
+ />
107
+
108
+ <slot
109
+ v-else
110
+ name="default"
111
+ />
112
+ </template>
@@ -43,7 +43,7 @@ export type InputProps<From extends Record<PropertyKey, any>, TName extends Deep
43
43
  inputClass: string | undefined | null
44
44
  }
45
45
  field: OmegaFieldInternalApi<From, TName>
46
- /** be sure to use this state and not `field.state` as it is not reactive */
46
+ /** reactive field state, sourced from `field.state` (the Field slot's own `state` prop is a stale snapshot since @tanstack/vue-form 1.32) */
47
47
  state: OmegaFieldInternalApi<From, TName>["state"]
48
48
  }
49
49
 
@@ -3,24 +3,23 @@
3
3
  :is="form.Field"
4
4
  :name="name"
5
5
  >
6
- <template #default="{ field, state }">
6
+ <!-- `field.state` is reactive; the Field slot's `state` prop is a stale snapshot since @tanstack/vue-form 1.32 -->
7
+ <template #default="{ field }">
7
8
  <slot
8
9
  name="pre-array"
9
- v-bind="{ field, state }"
10
+ v-bind="{ field, state: field.state }"
10
11
  />
11
12
  <component
12
13
  :is="form.Field"
13
14
  v-for="(_, i) of items"
14
15
  :key="`${name}[${Number(i)}]`"
15
- :name="// eslint-disable-next-line
16
- `${name}[${Number(i)}]` as DeepKeys<From>
17
- "
16
+ :name="`${name}[${Number(i)}]` as DeepKeys<From>"
18
17
  >
19
- <template #default="{ field: subField, state: subState }">
18
+ <template #default="{ field: subField }">
20
19
  <slot
21
20
  v-bind="{
22
21
  subField,
23
- subState,
22
+ subState: subField.state,
24
23
  index: Number(i),
25
24
  field
26
25
  }"
@@ -29,7 +28,7 @@
29
28
  </component>
30
29
  <slot
31
30
  name="post-array"
32
- v-bind="{ field, state }"
31
+ v-bind="{ field, state: field.state }"
33
32
  />
34
33
  <!-- TODO: legacy slot, remove this slot -->
35
34
  <slot
@@ -46,7 +45,7 @@
46
45
  >
47
46
  import { type DeepKeys } from "@tanstack/vue-form"
48
47
  import { computed, onMounted, provide } from "vue"
49
- import { type OmegaArrayProps } from "./OmegaFormStuff"
48
+ import { type OmegaArrayProps } from "./types"
50
49
 
51
50
  const props = defineProps<OmegaArrayProps<From, To, Name>>()
52
51
 
@@ -20,10 +20,10 @@
20
20
  Name extends DeepKeys<From>"
21
21
  >
22
22
  import { type DeepKeys } from "@tanstack/vue-form"
23
- import { pipe } from "effect/Function"
24
23
  import * as Order from "effect/Order"
25
24
  import { computed } from "vue"
26
- import { type FieldMeta, type FieldPath, type OmegaAutoGenMeta, type OmegaInputProps } from "./OmegaFormStuff"
25
+ import { type FieldMeta } from "./meta/types"
26
+ import { type FieldPath, type OmegaAutoGenMeta, type OmegaInputProps } from "./types"
27
27
 
28
28
  type NewMeta = OmegaAutoGenMeta<From, To, Name>
29
29
 
@@ -71,37 +71,33 @@ const orderBy: Order.Order<NewMeta> = Order.mapInput(
71
71
  (x: NewMeta) => namePosition(x.name, props.order || [])
72
72
  )
73
73
 
74
- const children = computed<NewMeta[]>(() =>
75
- pipe(
76
- props.form.meta as Record<DeepKeys<From>, FieldMeta | undefined>,
77
- // include / exclude
78
- filterRecord((_, metaKey) =>
74
+ const children = computed<NewMeta[]>(() => {
75
+ const included = filterRecord((value, metaKey) =>
76
+ Boolean(value)
77
+ && (
79
78
  props.pick
80
79
  ? props.pick.includes(metaKey) && !props.omit?.includes(metaKey)
81
80
  : !props.omit?.includes(metaKey)
82
- ),
83
- (x: Record<DeepKeys<From>, FieldMeta | undefined>) => x,
84
- // labelMap and adding name
85
- mapObject((metaValue, metaKey) => ({
86
- name: metaKey as Name,
87
- label: props.labelMap?.(metaKey) || metaKey,
88
- ...(metaValue ?? {})
89
- })),
90
- // filterMap
91
- props.filterMap
92
- ? filterMapRecord((m: NewMeta) => {
93
- const result = props.filterMap?.(m.name!, m as NewMeta)
94
- return result === undefined || result === true ? m : result
95
- })
96
- : (x: Record<DeepKeys<From>, NewMeta>) => x,
97
- // transform to array
98
- (obj: Record<DeepKeys<From>, NewMeta>) => Object.values(obj) as NewMeta[],
99
- // order
100
- (items: NewMeta[]) => [...items].sort((a, b) => orderBy(a, b)),
101
- // sort
102
- props.sort ? (items: NewMeta[]) => [...items].sort((a, b) => props.sort!(a, b)) : (x: NewMeta[]) => x
103
- )
104
- )
81
+ )
82
+ )(props.form.meta as Record<DeepKeys<From>, FieldMeta | undefined>) as Record<DeepKeys<From>, FieldMeta>
83
+
84
+ const withLabels = mapObject((metaValue: FieldMeta, metaKey) => ({
85
+ name: metaKey,
86
+ label: props.labelMap?.(metaKey) || metaKey,
87
+ ...metaValue
88
+ }))(included) as unknown as Record<DeepKeys<From>, NewMeta>
89
+
90
+ const filtered = props.filterMap
91
+ ? filterMapRecord((m: NewMeta) => {
92
+ const result = props.filterMap?.(m.name, m)
93
+ return result === undefined || result === true ? m : result
94
+ })(withLabels) as Record<DeepKeys<From>, NewMeta>
95
+ : withLabels
96
+
97
+ const sorted = [...Object.values(filtered) as NewMeta[]].sort(orderBy)
98
+
99
+ return props.sort ? sorted.sort(props.sort) : sorted
100
+ })
105
101
 
106
102
  defineSlots<{
107
103
  default(props: { child: NewMeta }): void
@@ -102,7 +102,7 @@
102
102
  import type { StandardSchemaV1Issue } from "@tanstack/vue-form"
103
103
  import { computed, getCurrentInstance } from "vue"
104
104
  import { useIntl } from "../../utils"
105
- import { type OmegaError } from "./OmegaFormStuff"
105
+ import { type OmegaError } from "./types"
106
106
 
107
107
  const instance = getCurrentInstance()
108
108
  const vuetified = instance?.appContext.components["VAlert"]
@@ -130,10 +130,9 @@ const showedGeneralErrors = computed(() => {
130
130
  .flatMap((issues) =>
131
131
  issues
132
132
  .filter(
133
- (issue): issue is StandardSchemaV1Issue & { message: string } =>
134
- typeof (issue as { message?: unknown })?.message === "string"
133
+ (issue): issue is StandardSchemaV1Issue & { message: string } => Boolean(issue?.message)
135
134
  )
136
- .map((issue) => (issue as StandardSchemaV1Issue & { message: string }).message)
135
+ .map((issue) => issue.message)
137
136
  )
138
137
  )
139
138
  })
@@ -17,8 +17,8 @@
17
17
  import { type DeepKeys } from "@tanstack/vue-form"
18
18
  import { inject } from "vue"
19
19
  import type { MergedInputProps } from "./InputProps"
20
- import type { BaseProps, DefaultTypeProps, OmegaInputProps } from "./OmegaFormStuff"
21
20
  import OmegaInput from "./OmegaInput.vue"
21
+ import type { BaseProps, DefaultTypeProps, OmegaInputProps } from "./types"
22
22
  import { OmegaFormKey } from "./useOmegaForm"
23
23
 
24
24
  const form = inject(OmegaFormKey) as unknown as OmegaInputProps<
@@ -1,19 +1,21 @@
1
1
  <template>
2
2
  <component
3
3
  :is="form.Field"
4
- :key="fieldKey"
5
4
  :name="name"
6
- :validators="{
7
- onChange: schema,
8
- ...validators
9
- }"
5
+ :validators="validators"
10
6
  >
11
- <template #default="{ field, state }">
7
+ <!--
8
+ Read `state` from `field.state`, not the Field slot's `state` prop.
9
+ Since @tanstack/vue-form 1.32 the slot `state` is a one-time snapshot
10
+ taken when the field mounts and never updates, whereas `field.state`
11
+ is a reactive getter backed by the field store.
12
+ -->
13
+ <template #default="{ field }">
12
14
  <OmegaInternalInput
13
15
  v-if="meta"
14
- v-bind="{ ...$attrs, ...$props, inputClass: computedClass }"
15
- :field="field"
16
- :state="state"
16
+ v-bind="{ ...$attrs, ...internalInputProps, inputClass: computedClass }"
17
+ :field="field as any"
18
+ :state="field.state"
17
19
  :register="form.registerField"
18
20
  :label="label ?? errori18n(propsName)"
19
21
  :meta="meta"
@@ -40,14 +42,24 @@
40
42
  lang="ts"
41
43
  generic="From extends Record<PropertyKey, any>, To extends Record<PropertyKey, any>, Name extends DeepKeys<From>"
42
44
  >
45
+ /* eslint-disable @typescript-eslint/no-explicit-any -- TanStack Form Field generic interop and slot prop typing */
43
46
  import { type DeepKeys } from "@tanstack/vue-form"
44
47
  import { computed, inject, type Ref, useAttrs } from "vue"
45
- import { useIntl } from "../../utils"
46
- import { type FieldMeta, generateInputStandardSchemaFromFieldMeta, type OmegaInputPropsBase } from "./OmegaFormStuff"
48
+ import { useErrorLabel } from "./errors"
49
+ import { type FieldMeta } from "./meta/types"
47
50
  import OmegaInternalInput from "./OmegaInternalInput.vue"
48
- import { useErrorLabel } from "./useOmegaForm"
51
+ import { type OmegaInputPropsBase } from "./types"
49
52
 
50
- const props = defineProps<OmegaInputPropsBase<From, To, Name>>()
53
+ const props = withDefaults(defineProps<OmegaInputPropsBase<From, To, Name>>(), {
54
+ required: undefined
55
+ })
56
+ const internalInputProps = computed(() => ({
57
+ label: props.label,
58
+ required: props.required,
59
+ type: props.type,
60
+ options: props.options,
61
+ inputs: props.form.inputs
62
+ }))
51
63
 
52
64
  // downgrade to *as* DeepKeys<From> to avoid useless and possible infinite recursion in TS
53
65
  const propsName = computed(() => props.name as DeepKeys<From>)
@@ -57,13 +69,10 @@ defineSlots<{
57
69
  default?: (props: any) => any
58
70
  }>()
59
71
 
60
- defineOptions({
61
- inheritAttrs: false
62
- })
72
+ defineOptions({ inheritAttrs: false })
63
73
 
64
74
  const attrs = useAttrs()
65
75
 
66
- // Compute the class to use based on inputClass prop
67
76
  const computedClass = computed(() => {
68
77
  if (props.inputClass === null) return undefined
69
78
  if (props.inputClass !== undefined) return props.inputClass
@@ -82,28 +91,5 @@ const meta = computed(() => {
82
91
  return props.form.meta[propsName.value]
83
92
  })
84
93
 
85
- // Key to force Field re-mount when meta type changes (for TaggedUnion support)
86
- const fieldKey = computed(() => {
87
- const m = meta.value
88
- if (!m) return propsName.value
89
- // Include type and key constraints in the key so Field re-mounts when validation rules change
90
- // Cast to any since not all FieldMeta variants have these properties
91
- const fm = m as any
92
- return `${propsName.value}-${fm.type}-${fm.minLength ?? ""}-${fm.maxLength ?? ""}-${fm.minimum ?? ""}-${
93
- fm.maximum ?? ""
94
- }`
95
- })
96
-
97
- // Call useIntl during setup to avoid issues when computed re-evaluates
98
- const { trans } = useIntl()
99
-
100
- const schema = computed(() => {
101
- if (!meta.value) {
102
- console.log(props.name, Object.keys(props.form.meta), props.form.meta)
103
- throw new Error("Meta is undefined")
104
- }
105
- return generateInputStandardSchemaFromFieldMeta(meta.value, trans)
106
- })
107
-
108
94
  const errori18n = useErrorLabel(props.form)
109
95
  </script>