Skip to content

Commit f50bc40

Browse files
committed
feat: enhance OmegaForm with default value extraction for tagged unions
1 parent f63d59d commit f50bc40

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

packages/vue-components/src/components/OmegaForm/OmegaTaggedUnionInternal.vue

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { type DeepKeys, type DeepValue } from "@tanstack/vue-form"
1919
import { S } from "effect-app"
2020
import { watch } from "vue"
2121
import { getTransformationFrom } from "../../utils"
22+
import { extractSchemaDefaults } from "./defaultAST"
2223
import { type OmegaFieldInternalApi } from "./InputProps"
2324
import { type useOmegaForm } from "./useOmegaForm"
2425
@@ -37,20 +38,51 @@ watch(() => props.state, (newTag, oldTag) => {
3738
if (newTag === null) {
3839
props.field.setValue(null as DeepValue<From, Name>)
3940
}
41+
42+
props.form.reset(values.value)
43+
4044
if (newTag !== oldTag) {
45+
// get default values from AST for the new tag (only for root level tagged unions)
4146
if (props.name === void 0 && S.AST.isUnion(props.form._schema.ast)) {
42-
const members = props
47+
const indexOfSelectedMember = props
4348
.form
4449
._schema
4550
.ast
4651
.types
47-
.map((t) => getTransformationFrom(t))
48-
.filter((t) => S.AST.isTypeLiteral(t) || S.AST.isTransformation(t))
49-
.map((t) => t.propertySignatures)
50-
console.log("members", members)
52+
.map((t, i) => ({ original: i, unwrapped: getTransformationFrom(t) }))
53+
.flatMap((x) =>
54+
S.AST.isTypeLiteral(x.unwrapped) || S.AST.isTransformation(x.unwrapped)
55+
? x
56+
.unwrapped
57+
.propertySignatures
58+
.filter((ps) => S.AST.isLiteral(ps.type) && ps.type.literal === newTag)
59+
.length > 0
60+
? [x.original]
61+
: []
62+
: []
63+
)[0]
64+
65+
// even if the type doesn't say so, indexOfSelectedMember may be undefined
66+
if (
67+
indexOfSelectedMember != void 0
68+
&& "members" in props.form._schema
69+
&& Array.isArray(props.form._schema.members)
70+
) {
71+
const defaultsOfSelectedMember = Object.assign(
72+
extractSchemaDefaults(
73+
props
74+
.form
75+
._schema
76+
.members[indexOfSelectedMember],
77+
values.value
78+
),
79+
{ _tag: newTag }
80+
)
81+
82+
props.form.reset(defaultsOfSelectedMember)
83+
}
5184
}
52-
console.log("resetting form", values.value)
53-
props.form.reset(values.value)
85+
5486
setTimeout(() => {
5587
props.field.validate("change")
5688
}, 0)

packages/vue-components/src/components/OmegaForm/defaultAST.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ const partialRecursive = <A, I, R>(schema: S.Schema<A, I, R>): S.Schema<Partial<
122122
}
123123

124124
// Helper function to recursively extract default values from schema AST swag ast
125-
const extractDefaultsFromAST = (schemaObj: any): any => {
125+
export const extractDefaultsFromAST = (schemaObj: any): any => {
126126
const result: Record<string, any> = {}
127127

128128
// Check if this schema has fields (struct)

packages/vue-components/stories/OmegaForm/RootLevelTaggedUnion.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ import { useOmegaForm } from "../../src"
7474
// Root-level union schema - the entire form is a union
7575
const schema = S.Union(
7676
S.Struct({
77-
a: S.NonEmptyString255,
78-
first: S.PositiveNumber.pipe(S.withDefaultConstructor(() => S.PositiveNumber(200))),
77+
a: S.NonEmptyString255.pipe(S.withDefaultConstructor(() => S.NonEmptyString255("aaaa"))),
7978
common: S.String,
8079
_tag: S.Literal("A")
8180
}),

0 commit comments

Comments
 (0)