@effect-app/vue-components 2.6.1 → 2.7.0
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.
- package/dist/types/components/OmegaForm/InputProps.d.ts +10 -4
- package/dist/types/components/OmegaForm/OmegaTaggedUnion.vue.d.ts +9 -13
- package/dist/types/components/OmegaForm/OmegaTaggedUnionInternal.vue.d.ts +2 -9
- package/dist/types/components/OmegaForm/useOmegaForm.d.ts +2 -1
- package/dist/vue-components.es10.js +244 -167
- package/dist/vue-components.es12.js +137 -115
- package/dist/vue-components.es22.js +1 -1
- package/dist/vue-components.es23.js +1 -1
- package/dist/vue-components.es36.js +1 -1
- package/dist/vue-components.es40.js +4 -23
- package/dist/vue-components.es41.js +23 -5
- package/dist/vue-components.es42.js +5 -21
- package/dist/vue-components.es43.js +16 -25
- package/dist/vue-components.es44.js +23 -15
- package/dist/vue-components.es45.js +17 -7
- package/dist/vue-components.es46.js +12 -5
- package/dist/vue-components.es47.js +5 -19
- package/dist/vue-components.es48.js +19 -9
- package/dist/vue-components.es49.js +9 -31
- package/dist/vue-components.es50.js +25 -42
- package/dist/vue-components.es51.js +38 -16
- package/dist/vue-components.es52.js +26 -11
- package/dist/vue-components.es53.js +11 -4
- package/dist/vue-components.es54.js +1 -1
- package/dist/vue-components.es56.js +1 -1
- package/dist/vue-components.es58.js +3 -3
- package/dist/vue-components.es59.js +1 -1
- package/dist/vue-components.es8.js +29 -36
- package/dist/vue-components.es9.js +7 -6
- package/package.json +1 -1
- package/src/components/OmegaForm/InputProps.ts +17 -8
- package/src/components/OmegaForm/OmegaFormStuff.ts +52 -0
- package/src/components/OmegaForm/OmegaTaggedUnion.vue +16 -35
- package/src/components/OmegaForm/OmegaTaggedUnionInternal.vue +2 -1
- package/src/components/OmegaForm/useOmegaForm.ts +170 -7
|
@@ -4,59 +4,40 @@
|
|
|
4
4
|
generic="
|
|
5
5
|
From extends Record<PropertyKey, any>,
|
|
6
6
|
To extends Record<PropertyKey, any>,
|
|
7
|
-
Name extends DeepKeys<From>
|
|
7
|
+
Name extends DeepKeys<From> | undefined = DeepKeys<From>
|
|
8
8
|
"
|
|
9
9
|
>
|
|
10
|
-
import { type DeepKeys
|
|
11
|
-
import {
|
|
12
|
-
import { type TaggedUnionOption, type TaggedUnionOptionsArray } from "./InputProps"
|
|
10
|
+
import { type DeepKeys } from "@tanstack/vue-form"
|
|
11
|
+
import { type TaggedUnionOption } from "./InputProps"
|
|
13
12
|
import { type FieldPath } from "./OmegaFormStuff"
|
|
14
13
|
import OmegaTaggedUnionInternal from "./OmegaTaggedUnionInternal.vue"
|
|
15
14
|
import { type useOmegaForm } from "./useOmegaForm"
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
name
|
|
16
|
+
defineProps<{
|
|
17
|
+
name?: Name
|
|
19
18
|
form: ReturnType<typeof useOmegaForm<From, To>>
|
|
20
19
|
type?: "select" | "radio"
|
|
21
|
-
options:
|
|
20
|
+
options: TaggedUnionOption<From, Name>[]
|
|
22
21
|
label?: string
|
|
23
22
|
}>()
|
|
24
|
-
|
|
25
|
-
// Initialize the union field on mount
|
|
26
|
-
onMounted(() => {
|
|
27
|
-
const currentValue = props.form.getFieldValue(props.name)
|
|
28
|
-
const meta = props.form.meta[props.name as keyof typeof props.form.meta]
|
|
29
|
-
|
|
30
|
-
if (currentValue === undefined) {
|
|
31
|
-
if (meta?.nullableOrUndefined === "null" || !meta?.required) {
|
|
32
|
-
// Initialize to null for nullable/optional unions
|
|
33
|
-
props.form.setFieldValue(props.name, null as DeepValue<From, Name>)
|
|
34
|
-
} else {
|
|
35
|
-
// For required unions, initialize with first non-null option
|
|
36
|
-
const firstOption = props.options.find((opt) => opt.value !== null)
|
|
37
|
-
if (firstOption && firstOption.value) {
|
|
38
|
-
props.form.setFieldValue(props.name, {
|
|
39
|
-
_tag: firstOption.value
|
|
40
|
-
} as DeepValue<From, Name>)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
23
|
</script>
|
|
46
24
|
|
|
47
25
|
<template>
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
26
|
+
<slot name="OmegaCustomInput">
|
|
27
|
+
<form.Input
|
|
28
|
+
:name="(name ? `${name}._tag` : '_tag') as FieldPath<From>"
|
|
29
|
+
:label="label"
|
|
30
|
+
:type="type ?? 'select'"
|
|
31
|
+
:options="options"
|
|
32
|
+
/>
|
|
33
|
+
</slot>
|
|
34
|
+
<form.Field :name="(name ?? '') as any">
|
|
55
35
|
<template #default="{ field, state }">
|
|
56
36
|
<slot v-if="state.value" />
|
|
57
37
|
<OmegaTaggedUnionInternal
|
|
58
38
|
:field="field as any"
|
|
59
39
|
:state="state.value"
|
|
40
|
+
:name="name"
|
|
60
41
|
>
|
|
61
42
|
<template
|
|
62
43
|
v-for="(_, slotname) in $slots"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<slot
|
|
3
3
|
v-if="state?._tag"
|
|
4
|
-
:name="state?._tag"
|
|
4
|
+
:name="`${name ? `${name}.` : ''}${state?._tag}`"
|
|
5
5
|
v-bind="{ field, state }"
|
|
6
6
|
/>
|
|
7
7
|
</template>
|
|
@@ -22,6 +22,7 @@ import { type OmegaFieldInternalApi } from "./InputProps"
|
|
|
22
22
|
const props = defineProps<{
|
|
23
23
|
state: DeepValue<From, Name>
|
|
24
24
|
field: OmegaFieldInternalApi<From, Name>
|
|
25
|
+
name?: DeepKeys<From>
|
|
25
26
|
}>()
|
|
26
27
|
|
|
27
28
|
// Watch for _tag changes
|
|
@@ -16,6 +16,86 @@ import OmegaInput from "./OmegaInput.vue"
|
|
|
16
16
|
import OmegaTaggedUnion from "./OmegaTaggedUnion.vue"
|
|
17
17
|
import OmegaForm from "./OmegaWrapper.vue"
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Recursively makes all properties in a schema optional, including nested objects.
|
|
21
|
+
* Unlike S.partial which only makes top-level properties optional, this utility
|
|
22
|
+
* traverses the schema tree and applies partial transformation at every level.
|
|
23
|
+
*
|
|
24
|
+
* Handles:
|
|
25
|
+
* - TypeLiteral (structs): Makes all properties optional and recursively processes nested types
|
|
26
|
+
* - Union types: Recursively applies partial to each union member
|
|
27
|
+
* - Transformation types: Applies partial to both 'from' and 'to' sides
|
|
28
|
+
*/
|
|
29
|
+
const partialRecursive = <A, I, R>(schema: S.Schema<A, I, R>): S.Schema<Partial<A>, Partial<I>, R> => {
|
|
30
|
+
const ast = schema.ast
|
|
31
|
+
|
|
32
|
+
// Handle Union types - recursively apply partial to each member
|
|
33
|
+
if (ast._tag === "Union") {
|
|
34
|
+
const partialMembers = (ast as any).types.map((memberAst: any) => {
|
|
35
|
+
const memberSchema = S.make(memberAst)
|
|
36
|
+
const partialMember = partialRecursive(memberSchema as any)
|
|
37
|
+
return partialMember.ast
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const newAst = {
|
|
41
|
+
...ast,
|
|
42
|
+
types: partialMembers
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return S.make(newAst as any)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Handle Transformation types (e.g., withDefaultConstructor)
|
|
49
|
+
if (ast._tag === "Transformation") {
|
|
50
|
+
// For transformations, apply partial to both the 'from' and 'to' sides
|
|
51
|
+
const fromSchema = S.make((ast as any).from)
|
|
52
|
+
const toSchema = S.make((ast as any).to)
|
|
53
|
+
const partialFrom = partialRecursive(fromSchema as any)
|
|
54
|
+
const partialTo = partialRecursive(toSchema as any)
|
|
55
|
+
|
|
56
|
+
const newAst = {
|
|
57
|
+
...ast,
|
|
58
|
+
from: partialFrom.ast,
|
|
59
|
+
to: partialTo.ast
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return S.make(newAst as any)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// If this is a TypeLiteral (struct), recursively apply partial to nested fields
|
|
66
|
+
if (ast._tag === "TypeLiteral") {
|
|
67
|
+
const fields = ast.propertySignatures.map((prop: any) => {
|
|
68
|
+
const propType = prop.type
|
|
69
|
+
let newType = propType
|
|
70
|
+
|
|
71
|
+
// Recursively handle nested complex types (structs, unions, transformations)
|
|
72
|
+
if (propType._tag === "TypeLiteral" || propType._tag === "Union" || propType._tag === "Transformation") {
|
|
73
|
+
const nestedSchema = S.make(propType)
|
|
74
|
+
const recursivePartial = partialRecursive(nestedSchema as any)
|
|
75
|
+
newType = recursivePartial.ast
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create a new property signature with isOptional: true
|
|
79
|
+
return {
|
|
80
|
+
...prop,
|
|
81
|
+
type: newType,
|
|
82
|
+
isOptional: true
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const newAst = {
|
|
87
|
+
...ast,
|
|
88
|
+
propertySignatures: fields
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return S.make(newAst as any)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// For other schema types (primitives, refinements, etc.), return as-is
|
|
95
|
+
// These types don't need to be made partial, and S.partial doesn't support them anyway
|
|
96
|
+
return schema as any
|
|
97
|
+
}
|
|
98
|
+
|
|
19
99
|
type keysRule<T> =
|
|
20
100
|
| {
|
|
21
101
|
keys?: NestedKeyOf<T>[]
|
|
@@ -433,9 +513,10 @@ export interface OmegaFormReturn<
|
|
|
433
513
|
never
|
|
434
514
|
>
|
|
435
515
|
& {
|
|
436
|
-
name
|
|
516
|
+
name?: Name
|
|
437
517
|
type?: "select" | "radio"
|
|
438
518
|
options: import("./InputProps").TaggedUnionOptionsArray<From, Name>
|
|
519
|
+
_debugName?: [NoInfer<Name>]
|
|
439
520
|
label?: string
|
|
440
521
|
}
|
|
441
522
|
& {}
|
|
@@ -706,22 +787,104 @@ export const useOmegaForm = <
|
|
|
706
787
|
return normalized
|
|
707
788
|
}
|
|
708
789
|
|
|
790
|
+
// Helper function to recursively extract default values from schema AST
|
|
791
|
+
const extractDefaultsFromAST = (schemaObj: any): any => {
|
|
792
|
+
const result: Record<string, any> = {}
|
|
793
|
+
|
|
794
|
+
// Check if this schema is a union
|
|
795
|
+
if (schemaObj?.members && Array.isArray(schemaObj.members)) {
|
|
796
|
+
// For unions, we try to find the first member that has a complete set of defaults
|
|
797
|
+
// Priority is given to members with default values for discriminator fields
|
|
798
|
+
for (const member of schemaObj.members) {
|
|
799
|
+
const memberDefaults = extractDefaultsFromAST(member)
|
|
800
|
+
if (Object.keys(memberDefaults).length > 0) {
|
|
801
|
+
// Check if this member has a default value for a discriminator field (like _tag)
|
|
802
|
+
// If it does, use this member's defaults
|
|
803
|
+
const hasDiscriminatorDefault = member?.fields && Object.entries(member.fields).some(
|
|
804
|
+
([key, fieldSchema]: [string, any]) => {
|
|
805
|
+
// Common discriminator field names
|
|
806
|
+
if (key === "_tag" || key === "type" || key === "kind") {
|
|
807
|
+
return fieldSchema?.ast?.defaultValue !== undefined
|
|
808
|
+
}
|
|
809
|
+
return false
|
|
810
|
+
}
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
if (hasDiscriminatorDefault) {
|
|
814
|
+
return memberDefaults
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
// If no member has a discriminator default, return empty
|
|
819
|
+
return {}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Check if this schema has fields (struct)
|
|
823
|
+
if (schemaObj?.fields && typeof schemaObj.fields === "object") {
|
|
824
|
+
for (const [key, fieldSchema] of Object.entries(schemaObj.fields)) {
|
|
825
|
+
// Check if this field has a default value in its AST
|
|
826
|
+
if ((fieldSchema as any)?.ast?.defaultValue) {
|
|
827
|
+
try {
|
|
828
|
+
const defaultValue = (fieldSchema as any).ast.defaultValue()
|
|
829
|
+
if (defaultValue !== undefined) {
|
|
830
|
+
result[key] = defaultValue
|
|
831
|
+
}
|
|
832
|
+
} catch {
|
|
833
|
+
// Silently ignore if defaultValue() throws
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// Recursively check nested fields for structs and unions
|
|
838
|
+
const nestedDefaults = extractDefaultsFromAST(fieldSchema as any)
|
|
839
|
+
if (Object.keys(nestedDefaults).length > 0) {
|
|
840
|
+
// If we already have a default value for this key, merge with nested
|
|
841
|
+
if (result[key] && typeof result[key] === "object") {
|
|
842
|
+
Object.assign(result[key], nestedDefaults)
|
|
843
|
+
} else if (!result[key]) {
|
|
844
|
+
// Only set nested defaults if we don't have a default value
|
|
845
|
+
result[key] = nestedDefaults
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
return result
|
|
852
|
+
}
|
|
853
|
+
|
|
709
854
|
// Extract default values from schema constructors (e.g., withDefaultConstructor)
|
|
710
855
|
const extractSchemaDefaults = (defaultValues: Partial<From> = {}) => {
|
|
856
|
+
let result: Partial<From> = {}
|
|
857
|
+
|
|
711
858
|
try {
|
|
859
|
+
// First try to use schema.make() if available
|
|
860
|
+
// First try to use schema.make() if available
|
|
712
861
|
// Note: Partial schemas don't have .make() method yet (https://github.com/Effect-TS/effect/issues/4222)
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
}
|
|
862
|
+
const decoded = (schema as any).make(defaultValues)
|
|
863
|
+
result = S.encodeSync(partialRecursive(schema))(decoded)
|
|
716
864
|
} catch (error) {
|
|
717
|
-
|
|
718
|
-
|
|
865
|
+
// If make() fails, try to extract defaults from AST
|
|
866
|
+
if (window.location.hostname === "localhost") {
|
|
867
|
+
console.warn("schema.make() failed, extracting defaults from AST:", error)
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
const astDefaults = extractDefaultsFromAST(schema)
|
|
871
|
+
result = S.encodeSync(partialRecursive(schema))(astDefaults)
|
|
872
|
+
} catch (astError) {
|
|
873
|
+
if (window.location.hostname === "localhost") {
|
|
874
|
+
console.warn("Could not extract defaults from AST:", astError)
|
|
875
|
+
}
|
|
876
|
+
}
|
|
719
877
|
}
|
|
878
|
+
return deepMerge(result, defaultValues)
|
|
720
879
|
}
|
|
721
880
|
|
|
722
881
|
const defaultValues = computed(() => {
|
|
723
882
|
// Normalize tanstack default values at the beginning
|
|
724
|
-
const normalizedTanstackDefaults = extractSchemaDefaults(
|
|
883
|
+
const normalizedTanstackDefaults = extractSchemaDefaults(
|
|
884
|
+
normalizeDefaultValues(
|
|
885
|
+
tanstackFormOptions?.defaultValues
|
|
886
|
+
)
|
|
887
|
+
)
|
|
725
888
|
|
|
726
889
|
if (
|
|
727
890
|
normalizedTanstackDefaults
|