@effect-app/vue-components 2.11.5 → 3.0.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.
@@ -1,5 +1,5 @@
1
- import { defineComponent as r, watch as m, nextTick as o, renderSlot as u, createCommentVNode as i, normalizeProps as f, mergeProps as c } from "vue";
2
- const $ = /* @__PURE__ */ r({
1
+ import { defineComponent as m, watch as r, renderSlot as s, createCommentVNode as o, normalizeProps as i, mergeProps as f } from "vue";
2
+ const d = /* @__PURE__ */ m({
3
3
  __name: "OmegaTaggedUnionInternal",
4
4
  props: {
5
5
  state: {},
@@ -8,21 +8,14 @@ const $ = /* @__PURE__ */ r({
8
8
  form: {}
9
9
  },
10
10
  setup(e) {
11
- const a = e;
12
- return m(() => a.state, (t, n) => {
13
- t === null && a.field.setValue(null), t !== n && t && o(() => {
14
- const s = a.form.unionDefaultValues?.[t] ?? {}, l = {
15
- ...a.form.state.values,
16
- ...s,
17
- _tag: t
18
- };
19
- a.form.reset(l), setTimeout(() => {
20
- a.field.validate("change");
21
- }, 0);
22
- });
23
- }, { immediate: !0 }), (t, n) => e.state ? u(t.$slots, `${e.name ? `${e.name}.` : ""}${e.state}`, f(c({ key: 0 }, { field: e.field, state: e.state }))) : i("", !0);
11
+ const a = e, l = a.form.useStore(({ values: t }) => t);
12
+ return r(() => a.state, (t, n) => {
13
+ t === null && a.field.setValue(null), t !== n && (a.form.reset(l.value), setTimeout(() => {
14
+ a.field.validate("change");
15
+ }, 0));
16
+ }, { immediate: !0 }), (t, n) => e.state ? s(t.$slots, `${e.name ? `${e.name}.` : ""}${e.state}`, i(f({ key: 0 }, { field: e.field, state: e.state }))) : o("", !0);
24
17
  }
25
18
  });
26
19
  export {
27
- $ as default
20
+ d as default
28
21
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/vue-components",
3
- "version": "2.11.5",
3
+ "version": "3.0.0",
4
4
  "peerDependencies": {
5
5
  "@mdi/js": "^7.4.47",
6
6
  "effect": "^3.19.3",
@@ -53,8 +53,8 @@
53
53
  "highlight.js": "^11.11.1",
54
54
  "mitt": "^3.0.1",
55
55
  "vue3-highlightjs": "^1.0.5",
56
- "@effect-app/vue": "2.93.6",
57
- "effect-app": "3.15.1"
56
+ "effect-app": "3.15.1",
57
+ "@effect-app/vue": "2.93.6"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "pnpm build:run",
@@ -356,7 +356,6 @@ export const createMeta = <T = any>(
356
356
 
357
357
  if (property?._tag === "TypeLiteral" && "propertySignatures" in property) {
358
358
  return createMeta<T>({
359
- parent, // Pass parent to maintain the key prefix for nested structures
360
359
  meta,
361
360
  propertySignatures: property.propertySignatures
362
361
  })
@@ -405,13 +404,7 @@ export const createMeta = <T = any>(
405
404
  property: p.type,
406
405
  meta: { required: isRequired, nullableOrUndefined }
407
406
  })
408
- // If parentMeta is a MetaRecord (nested structure from ExtendedClass), merge it
409
- // Otherwise assign as single FieldMeta
410
- if (parentMeta && typeof parentMeta === "object" && !("type" in parentMeta)) {
411
- Object.assign(acc, parentMeta)
412
- } else {
413
- acc[key as NestedKeyOf<T>] = parentMeta as FieldMeta
414
- }
407
+ acc[key as NestedKeyOf<T>] = parentMeta as FieldMeta
415
408
  }
416
409
 
417
410
  // Process each non-null type and merge their metadata
@@ -708,17 +701,11 @@ const flattenMeta = <T>(meta: MetaRecord<T> | FieldMeta, parentKey: string = "")
708
701
 
709
702
  const metadataFromAst = <From, To>(
710
703
  schema: S.Schema<To, From, never>
711
- ): {
712
- meta: MetaRecord<To>
713
- defaultValues: Record<string, any>
714
- unionMeta: Record<string, MetaRecord<To>>
715
- unionDefaultValues: Record<string, Record<string, any>>
716
- } => {
704
+ ): { meta: MetaRecord<To>; defaultValues: Record<string, any>; unionMeta: Record<string, MetaRecord<To>> } => {
717
705
  const ast = schema.ast
718
706
  const newMeta: MetaRecord<To> = {}
719
707
  const defaultValues: Record<string, any> = {}
720
708
  const unionMeta: Record<string, MetaRecord<To>> = {}
721
- const unionDefaultValues: Record<string, Record<string, any>> = {}
722
709
 
723
710
  if (ast._tag === "Transformation" || ast._tag === "Refinement") {
724
711
  return metadataFromAst(S.make(ast.from))
@@ -763,9 +750,6 @@ const metadataFromAst = <From, To>(
763
750
  // Store per-tag metadata for reactive lookup
764
751
  if (tagValue) {
765
752
  unionMeta[tagValue] = flattenMeta<To>(memberMeta)
766
- // Create default values for this tag's schema
767
- const memberSchema = S.make(memberType)
768
- unionDefaultValues[tagValue] = defaultsValueFromSchema(memberSchema as any)
769
753
  }
770
754
 
771
755
  // Merge into result (for backward compatibility)
@@ -782,7 +766,7 @@ const metadataFromAst = <From, To>(
782
766
  } as FieldMeta
783
767
  }
784
768
 
785
- return { meta: newMeta, defaultValues, unionMeta, unionDefaultValues }
769
+ return { meta: newMeta, defaultValues, unionMeta }
786
770
  }
787
771
  }
788
772
 
@@ -792,7 +776,7 @@ const metadataFromAst = <From, To>(
792
776
  })
793
777
 
794
778
  if (Object.values(meta).every((value) => value && "type" in value)) {
795
- return { meta: meta as MetaRecord<To>, defaultValues, unionMeta, unionDefaultValues }
779
+ return { meta: meta as MetaRecord<To>, defaultValues, unionMeta }
796
780
  }
797
781
 
798
782
  const flattenObject = (
@@ -812,7 +796,7 @@ const metadataFromAst = <From, To>(
812
796
  flattenObject(meta)
813
797
  }
814
798
 
815
- return { meta: newMeta, defaultValues, unionMeta, unionDefaultValues }
799
+ return { meta: newMeta, defaultValues, unionMeta }
816
800
  }
817
801
 
818
802
  export const duplicateSchema = <From, To>(
@@ -827,11 +811,10 @@ export const generateMetaFromSchema = <From, To>(
827
811
  schema: S.Schema<To, From, never>
828
812
  meta: MetaRecord<To>
829
813
  unionMeta: Record<string, MetaRecord<To>>
830
- unionDefaultValues: Record<string, Record<string, any>>
831
814
  } => {
832
- const { meta, unionDefaultValues, unionMeta } = metadataFromAst(schema)
815
+ const { meta, unionMeta } = metadataFromAst(schema)
833
816
 
834
- return { schema, meta, unionMeta, unionDefaultValues }
817
+ return { schema, meta, unionMeta }
835
818
  }
836
819
 
837
820
  export const generateInputStandardSchemaFromFieldMeta = (
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <component
3
3
  :is="form.Field"
4
+ :key="fieldKey"
4
5
  :name="name"
5
6
  :validators="{
6
7
  onChange: schema,
@@ -75,12 +76,22 @@ const getMetaFromArray = inject<Ref<(name: string) => FieldMeta | null> | null>(
75
76
  )
76
77
 
77
78
  const meta = computed(() => {
78
- const fromArray = getMetaFromArray?.value?.(props.name as DeepKeys<From>)
79
- if (fromArray) {
80
- return fromArray
79
+ if (getMetaFromArray?.value && getMetaFromArray.value(props.name as DeepKeys<From>)) {
80
+ return getMetaFromArray.value(propsName.value)
81
81
  }
82
- const formMeta = props.form.meta[propsName.value]
83
- return formMeta
82
+ return props.form.meta[propsName.value]
83
+ })
84
+
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
+ }`
84
95
  })
85
96
 
86
97
  // Call useIntl during setup to avoid issues when computed re-evaluates
@@ -34,7 +34,6 @@ watch(
34
34
  },
35
35
  (newTag) => {
36
36
  currentTag.value = newTag ?? null
37
- return undefined
38
37
  },
39
38
  { immediate: true }
40
39
  )
@@ -12,7 +12,7 @@
12
12
  generic="From extends Record<PropertyKey, any>, To extends Record<PropertyKey, any>, Name extends DeepKeys<From>"
13
13
  >
14
14
  import { type DeepKeys, type DeepValue } from "@tanstack/vue-form"
15
- import { nextTick, watch } from "vue"
15
+ import { watch } from "vue"
16
16
  import { type OmegaFieldInternalApi } from "./InputProps"
17
17
  import { type useOmegaForm } from "./useOmegaForm"
18
18
 
@@ -23,30 +23,19 @@ const props = defineProps<{
23
23
  form: ReturnType<typeof useOmegaForm<From, To>>
24
24
  }>()
25
25
 
26
+ const values = props.form.useStore(({ values }) => values)
27
+
26
28
  // Watch for _tag changes
27
29
  watch(() => props.state, (newTag, oldTag) => {
28
30
  if (newTag === null) {
29
31
  props.field.setValue(null as DeepValue<From, Name>)
30
32
  }
31
33
 
32
- if (newTag !== oldTag && newTag) {
33
- // Use nextTick to avoid cleanup conflicts during reactive updates
34
- nextTick(() => {
35
- // Get default values for the new tag to ensure correct types
36
- const tagDefaults = (props.form as any).unionDefaultValues?.[newTag as string] ?? {}
37
- // Get current form values to preserve user's selections (e.g., carrier)
38
- const currentValues = props.form.state.values
39
- // Merge: keep current values, override with tag defaults for type correctness, set new _tag
40
- const resetValues = {
41
- ...currentValues,
42
- ...tagDefaults,
43
- _tag: newTag
44
- }
45
- props.form.reset(resetValues as any)
46
- setTimeout(() => {
47
- props.field.validate("change")
48
- }, 0)
49
- })
34
+ if (newTag !== oldTag) {
35
+ props.form.reset(values.value)
36
+ setTimeout(() => {
37
+ props.field.validate("change")
38
+ }, 0)
50
39
  }
51
40
  }, { immediate: true })
52
41
  </script>
@@ -218,7 +218,6 @@ export type OmegaConfig<T> = {
218
218
  export interface OF<From, To> extends OmegaFormApi<From, To> {
219
219
  meta: MetaRecord<From>
220
220
  unionMeta: Record<string, MetaRecord<From>>
221
- unionDefaultValues: Record<string, Record<string, any>>
222
221
  clear: () => void
223
222
  i18nNamespace?: string
224
223
  ignorePreventCloseEvents?: boolean
@@ -684,7 +683,7 @@ export const useOmegaForm = <
684
683
  const standardSchema = S.standardSchemaV1(schema)
685
684
  const decode = S.decode(schema)
686
685
 
687
- const { meta, unionDefaultValues, unionMeta } = generateMetaFromSchema(schema)
686
+ const { meta, unionMeta } = generateMetaFromSchema(schema)
688
687
 
689
688
  const persistencyKey = computed(() => {
690
689
  if (omegaConfig?.persistency?.id) {
@@ -919,7 +918,6 @@ export const useOmegaForm = <
919
918
  // Reset with current values to mark them as the new baseline
920
919
  form.reset(values.value)
921
920
  }
922
- return undefined
923
921
  })
924
922
  }
925
923
 
@@ -956,7 +954,6 @@ export const useOmegaForm = <
956
954
  ignorePreventCloseEvents: omegaConfig?.ignorePreventCloseEvents,
957
955
  meta,
958
956
  unionMeta,
959
- unionDefaultValues,
960
957
  clear,
961
958
  handleSubmit: (meta?: Record<string, any>) => {
962
959
  const span = api.trace.getSpan(api.context.active())
@@ -965,18 +962,8 @@ export const useOmegaForm = <
965
962
  // /** @experimental */
966
963
  handleSubmitEffect,
967
964
  registerField: (field: ComputedRef<{ name: string; label: string; id: string }>) => {
968
- watch(field, (f) => {
969
- fieldMap.value.set(f.name, { label: f.label, id: f.id })
970
- }, { immediate: true })
971
- onUnmounted(() => {
972
- // Only delete if this component instance still owns the registration (id matches)
973
- // This prevents the old component from removing the new component's registration
974
- // when Vue re-keys and mounts new before unmounting old
975
- const current = fieldMap.value.get(field.value.name)
976
- if (current?.id === field.value.id) {
977
- fieldMap.value.delete(field.value.name)
978
- }
979
- })
965
+ watch(field, (f) => fieldMap.value.set(f.name, { label: f.label, id: f.id }), { immediate: true })
966
+ onUnmounted(() => fieldMap.value.delete(field.value.name)) // todo; perhap only when owned (id match)
980
967
  }
981
968
  })
982
969
 
@@ -5,9 +5,7 @@ const Key = Symbol("injected") as InjectionKey<Map<string, { label: string; id:
5
5
 
6
6
  export const useRegisterField = (field: ComputedRef<{ name: string; label: string; id: string }>) => {
7
7
  const map = injectCertain(Key)
8
- watch(field, (f) => {
9
- map.set(f.name, { label: f.label, id: f.id })
10
- }, { immediate: true })
8
+ watch(field, (f) => map.set(f.name, { label: f.label, id: f.id }), { immediate: true })
11
9
  onUnmounted(() => map.delete(field.value.name)) // todo; perhap only when owned
12
10
  }
13
11