@effect-app/vue-components 2.0.0 → 2.1.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.
Files changed (75) hide show
  1. package/dist/types/components/OmegaForm/InputProps.d.ts +24 -0
  2. package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +1 -1
  3. package/dist/types/components/OmegaForm/OmegaInternalInput.vue.d.ts +2 -2
  4. package/dist/types/components/OmegaForm/OmegaTaggedUnion.vue.d.ts +34 -0
  5. package/dist/types/components/OmegaForm/OmegaTaggedUnionInternal.vue.d.ts +32 -0
  6. package/dist/types/components/OmegaForm/index.d.ts +3 -1
  7. package/dist/types/components/OmegaForm/useOmegaForm.d.ts +26 -0
  8. package/dist/vue-components.es.js +30 -26
  9. package/dist/vue-components.es10.js +223 -341
  10. package/dist/vue-components.es11.js +29 -33
  11. package/dist/vue-components.es12.js +357 -2
  12. package/dist/vue-components.es13.js +34 -2
  13. package/dist/vue-components.es14.js +2 -10
  14. package/dist/vue-components.es15.js +2 -5
  15. package/dist/vue-components.es16.js +10 -54
  16. package/dist/vue-components.es17.js +5 -68
  17. package/dist/vue-components.es18.js +54 -6
  18. package/dist/vue-components.es19.js +68 -6
  19. package/dist/vue-components.es2.js +20 -16
  20. package/dist/vue-components.es20.js +6 -3
  21. package/dist/vue-components.es21.js +6 -3
  22. package/dist/vue-components.es22.js +3 -2
  23. package/dist/vue-components.es23.js +3 -2
  24. package/dist/vue-components.es24.js +2 -17
  25. package/dist/vue-components.es25.js +2 -11
  26. package/dist/vue-components.es26.js +2 -136
  27. package/dist/vue-components.es27.js +4 -0
  28. package/dist/vue-components.es28.js +17 -42
  29. package/dist/vue-components.es29.js +11 -2
  30. package/dist/vue-components.es30.js +136 -2
  31. package/dist/vue-components.es32.js +44 -0
  32. package/dist/vue-components.es33.js +2 -7
  33. package/dist/vue-components.es34.js +2 -32
  34. package/dist/vue-components.es37.js +7 -23
  35. package/dist/vue-components.es38.js +32 -5
  36. package/dist/vue-components.es40.js +4 -30
  37. package/dist/vue-components.es41.js +20 -19
  38. package/dist/vue-components.es42.js +5 -12
  39. package/dist/vue-components.es43.js +21 -5
  40. package/dist/vue-components.es44.js +29 -18
  41. package/dist/vue-components.es45.js +22 -9
  42. package/dist/vue-components.es46.js +7 -26
  43. package/dist/vue-components.es47.js +5 -48
  44. package/dist/vue-components.es48.js +19 -26
  45. package/dist/vue-components.es49.js +9 -11
  46. package/dist/vue-components.es5.js +2 -2
  47. package/dist/vue-components.es50.js +26 -60
  48. package/dist/vue-components.es51.js +37 -45
  49. package/dist/vue-components.es52.js +26 -17
  50. package/dist/vue-components.es53.js +10 -32
  51. package/dist/vue-components.es54.js +65 -29
  52. package/dist/vue-components.es55.js +45 -31
  53. package/dist/vue-components.es56.js +17 -2
  54. package/dist/vue-components.es57.js +29 -40
  55. package/dist/vue-components.es58.js +29 -2
  56. package/dist/vue-components.es59.js +44 -0
  57. package/dist/vue-components.es6.js +9 -9
  58. package/dist/vue-components.es60.js +4 -0
  59. package/dist/vue-components.es61.js +46 -0
  60. package/dist/vue-components.es62.js +4 -0
  61. package/dist/vue-components.es7.js +26 -25
  62. package/dist/vue-components.es8.js +51 -198
  63. package/dist/vue-components.es9.js +17 -30
  64. package/package.json +1 -1
  65. package/src/components/OmegaForm/InputProps.ts +32 -0
  66. package/src/components/OmegaForm/OmegaFormStuff.ts +22 -3
  67. package/src/components/OmegaForm/OmegaInput.vue +4 -1
  68. package/src/components/OmegaForm/OmegaInternalInput.vue +35 -13
  69. package/src/components/OmegaForm/OmegaTaggedUnion.vue +73 -0
  70. package/src/components/OmegaForm/OmegaTaggedUnionInternal.vue +38 -0
  71. package/src/components/OmegaForm/index.ts +3 -1
  72. package/src/components/OmegaForm/useOmegaForm.ts +178 -11
  73. package/dist/vue-components.es36.js +0 -6
  74. package/dist/vue-components.es39.js +0 -23
  75. /package/dist/{vue-components.es31.js → vue-components.es35.js} +0 -0
@@ -0,0 +1,46 @@
1
+ import { VERSION as d } from "./vue-components.es60.js";
2
+ var h = /^(\d+)\.(\d+)\.(\d+)(-(.+))?$/;
3
+ function s(c) {
4
+ var m = /* @__PURE__ */ new Set([c]), f = /* @__PURE__ */ new Set(), t = c.match(h);
5
+ if (!t)
6
+ return function() {
7
+ return !1;
8
+ };
9
+ var e = {
10
+ major: +t[1],
11
+ minor: +t[2],
12
+ patch: +t[3],
13
+ prerelease: t[4]
14
+ };
15
+ if (e.prerelease != null)
16
+ return function(r) {
17
+ return r === c;
18
+ };
19
+ function a(n) {
20
+ return f.add(n), !1;
21
+ }
22
+ function p(n) {
23
+ return m.add(n), !0;
24
+ }
25
+ return function(r) {
26
+ if (m.has(r))
27
+ return !0;
28
+ if (f.has(r))
29
+ return !1;
30
+ var i = r.match(h);
31
+ if (!i)
32
+ return a(r);
33
+ var u = {
34
+ major: +i[1],
35
+ minor: +i[2],
36
+ patch: +i[3],
37
+ prerelease: i[4]
38
+ };
39
+ return u.prerelease != null || e.major !== u.major ? a(r) : e.major === 0 ? e.minor === u.minor && e.patch <= u.patch ? p(r) : a(r) : e.minor <= u.minor ? p(r) : a(r);
40
+ };
41
+ }
42
+ var v = s(d);
43
+ export {
44
+ s as _makeCompatibilityCheck,
45
+ v as isCompatible
46
+ };
@@ -0,0 +1,4 @@
1
+ var o = typeof globalThis == "object" ? globalThis : typeof self == "object" ? self : typeof window == "object" ? window : typeof global == "object" ? global : {};
2
+ export {
3
+ o as _globalThis
4
+ };
@@ -1,7 +1,7 @@
1
1
  (function(){"use strict";try{if(typeof document<"u"){var i=document.createElement("style");if(i.appendChild(document.createTextNode(".omega-input .v-input__details:has(.v-messages:empty){grid-template-rows:0fr;transition:all .2s}.omega-input .v-messages:empty{min-height:0}.omega-input .v-input__details:has(.v-messages){transition:all .2s;overflow:hidden;min-height:0;display:grid;grid-template-rows:1fr}.omega-input .v-messages{transition:all .2s}.omega-input .v-messages>*{transition-duration:0s!important}.omega-input [role=alert]:has(.v-messages:empty){padding:0}.omega-input .v-btn{cursor:pointer;width:auto;appearance:none;box-shadow:none;display:block;min-width:auto;height:auto;padding:.5em .5em .5em 1em}")),document.head.appendChild(i),window.customElements){const e=window.customElements.define;window.customElements.define=function(s,t){const n=t.prototype.connectedCallback;return t.prototype.connectedCallback=function(){if(n&&n.call(this),this.shadowRoot){const a=document.createElement("style");a.appendChild(document.createTextNode(".omega-input .v-input__details:has(.v-messages:empty){grid-template-rows:0fr;transition:all .2s}.omega-input .v-messages:empty{min-height:0}.omega-input .v-input__details:has(.v-messages){transition:all .2s;overflow:hidden;min-height:0;display:grid;grid-template-rows:1fr}.omega-input .v-messages{transition:all .2s}.omega-input .v-messages>*{transition-duration:0s!important}.omega-input [role=alert]:has(.v-messages:empty){padding:0}.omega-input .v-btn{cursor:pointer;width:auto;appearance:none;box-shadow:none;display:block;min-width:auto;height:auto;padding:.5em .5em .5em 1em}")),this.shadowRoot.appendChild(a)}},e.call(window.customElements,s,t)}}}}catch(e){console.error("vite-plugin-css-injected-by-js",e)}})();
2
- import { defineComponent as C, computed as n, getCurrentInstance as x, useId as _, onMounted as P, renderSlot as M, normalizeProps as m, guardReactiveProps as N, createElementVNode as $, normalizeClass as q, createBlock as B, createCommentVNode as V, unref as k, openBlock as I, mergeProps as L } from "vue";
3
- import { useStore as S } from "@tanstack/vue-form";
4
- import w from "./vue-components.es26.js";
2
+ import { defineComponent as C, computed as a, getCurrentInstance as x, useId as V, onMounted as _, renderSlot as P, normalizeProps as m, guardReactiveProps as M, createElementVNode as N, normalizeClass as $, createBlock as q, createCommentVNode as B, unref as O, openBlock as k, mergeProps as I } from "vue";
3
+ import { useStore as L } from "@tanstack/vue-form";
4
+ import S from "./vue-components.es30.js";
5
5
 
6
6
  const E = /* @__PURE__ */ C({
7
7
  inheritAttrs: !1,
@@ -18,53 +18,54 @@ const E = /* @__PURE__ */ C({
18
18
  options: { default: void 0 }
19
19
  },
20
20
  setup(d) {
21
- const e = d, l = n(() => e.required ?? e?.meta?.required), p = x()?.appContext.components.VTextField, s = _(), o = e.field, i = S(o.store, (t) => t), f = n(() => e.type ? e.type : e.meta?.type === "string" ? e.meta.format === "email" ? "email" : "string" : e.meta?.type || "unknown");
22
- e.register(n(() => ({ name: e.field.name, label: e.label, id: s })));
23
- const c = n(() => i.value.value), g = n(() => i.value.meta.errors ?? []), u = n(
21
+ const e = d, i = a(() => e.required ?? e?.meta?.required), f = x()?.appContext.components.VTextField, o = V(), r = e.field, s = L(r.store, (t) => t), p = a(() => e.type ? e.type : e.meta?.type === "string" ? e.meta.format === "email" ? "email" : "string" : e.meta?.type || "unknown");
22
+ e.register(a(() => ({ name: e.field.name, label: e.label, id: o })));
23
+ const c = a(() => s.value.value), g = a(() => s.value.meta.errors ?? []), u = a(
24
24
  () => (
25
25
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
26
  g.value.map((t) => t?.message).filter(Boolean)
27
27
  )
28
28
  ), v = (t) => t == null || t === !1 || t === "" || Number.isNaN(t), y = (t) => {
29
- v(t) && e.meta?.type !== "boolean" ? e.field.handleChange(
30
- e.meta?.nullableOrUndefined === "undefined" ? void 0 : null
31
- ) : e.field.handleChange(t), e.field.setMeta((r) => ({ ...r, errorMap: { ...r.errorMap, onSubmit: void 0 } }));
29
+ v(t) && e.meta?.type !== "boolean" && e.meta?.nullableOrUndefined ? e.field.handleChange(
30
+ e.meta.nullableOrUndefined === "undefined" ? void 0 : null
31
+ ) : e.field.handleChange(t), e.field.setMeta((n) => ({ ...n, errorMap: { ...n.errorMap, onSubmit: void 0 } }));
32
32
  };
33
- P(() => {
34
- if (!c.value && !l.value && e.meta?.nullableOrUndefined === "null") {
35
- const t = i.value.meta.isDirty;
36
- o.setValue(null), o.setMeta((r) => ({ ...r, isDirty: t }));
33
+ _(() => {
34
+ if (c.value === void 0) {
35
+ const t = s.value.meta.isDirty;
36
+ if (r.setMeta((n) => ({ ...n, isDirty: t })), i.value) return;
37
+ e.meta?.nullableOrUndefined === "null" ? r.setValue(null) : e.meta?.nullableOrUndefined === "undefined" ? r.setValue(void 0) : e.meta?.type === "string" ? r.setValue("") : e.meta?.type === "number" || e.meta?.type === "boolean" && r.setValue(!1);
37
38
  }
38
39
  });
39
40
  const h = (t) => {
40
- const r = {
41
- get(R, b, z) {
41
+ const n = {
42
+ get(F, b, R) {
42
43
  return b === "handleChange" ? y : Reflect.get(...arguments);
43
44
  }
44
45
  };
45
- return new Proxy(t, r);
46
- }, a = n(() => ({
46
+ return new Proxy(t, n);
47
+ }, l = a(() => ({
47
48
  inputProps: {
48
- id: s,
49
- required: l.value,
49
+ id: o,
50
+ required: i.value,
50
51
  minLength: e.meta?.type === "string" && e.meta?.minLength,
51
52
  maxLength: e.meta?.type === "string" && e.meta?.maxLength,
52
53
  max: e.meta?.type === "number" && e.meta?.maximum,
53
54
  min: e.meta?.type === "number" && e.meta?.minimum,
54
55
  errorMessages: u.value,
55
56
  error: !!u.value.length,
56
- type: f.value,
57
- label: `${e.label}${l.value ? " *" : ""}`,
57
+ type: p.value,
58
+ label: `${e.label}${i.value ? " *" : ""}`,
58
59
  options: e.options
59
60
  },
60
61
  state: e.state,
61
62
  field: h(e.field)
62
63
  }));
63
- return (t, r) => M(t.$slots, "default", m(N({ ...a.value.inputProps, field: a.value.field, state: a.value.state })), () => [
64
- $("div", {
65
- class: q(t.$attrs.class)
64
+ return (t, n) => P(t.$slots, "default", m(M({ ...l.value.inputProps, field: l.value.field, state: l.value.state })), () => [
65
+ N("div", {
66
+ class: $(t.$attrs.class)
66
67
  }, [
67
- k(p) ? (I(), B(w, m(L({ key: 0 }, { ...t.$attrs, ...a.value })), null, 16)) : V("", !0)
68
+ O(f) ? (k(), q(S, m(I({ key: 0 }, { ...t.$attrs, ...l.value })), null, 16)) : B("", !0)
68
69
  ], 2)
69
70
  ]);
70
71
  }
@@ -1,201 +1,54 @@
1
- import { useForm as q } from "@tanstack/vue-form";
2
- import { Data as K, S as I, Effect as l, Fiber as F, Option as M, Array as P } from "effect-app";
3
- import { runtimeFiberAsPromise as B } from "./vue-components.es14.js";
4
- import { isObject as G } from "./vue-components.es15.js";
5
- import { computed as j, onUnmounted as N, onMounted as T, onBeforeUnmount as W, ref as k, watch as z, h as R } from "vue";
6
- import Q from "./vue-components.es16.js";
7
- import X from "./vue-components.es17.js";
8
- import Y from "./vue-components.es18.js";
9
- import { generateMetaFromSchema as Z } from "./vue-components.es10.js";
10
- import C from "./vue-components.es6.js";
11
- import ee from "./vue-components.es19.js";
12
- import { trace as _ } from "./vue-components.es20.js";
13
- import { context as V } from "./vue-components.es21.js";
14
- class re extends K.TaggedError("FormErrors") {
15
- }
16
- const w = (c) => function(n) {
17
- return {
18
- render() {
19
- return R(n, {
20
- form: c,
21
- ...this.$attrs
22
- }, this.$slots);
23
- }
24
- };
25
- }, te = (c) => function(n) {
26
- return {
27
- setup() {
28
- const { fieldMap: f, form: m } = c, p = m.useStore((a) => a.errors), u = m.useStore((a) => a.fieldMeta), b = j(
29
- () => P.filterMap(
30
- Object.entries(u.value),
31
- ([a, v]) => (v.errors ?? []).length && f.value.get(a)?.id ? M.some({
32
- label: f.value.get(a).label,
33
- inputId: f.value.get(a).id,
34
- errors: (v.errors ?? []).map((y) => y.message).filter(Boolean)
35
- }) : M.none()
36
- )
37
- );
38
- return {
39
- generalErrors: p,
40
- errors: b
41
- };
42
- },
43
- render({ errors: f, generalErrors: m }) {
44
- return R(n, {
45
- errors: f,
46
- generalErrors: m,
47
- ...this.$attrs
48
- }, this.$slots);
49
- }
50
- };
51
- }, Se = (c, i, n) => {
52
- if (!c) throw new Error("Schema is required");
53
- const f = I.standardSchemaV1(c), m = I.decode(c), { meta: p } = Z(c), u = j(() => {
54
- if (n?.persistency?.id)
55
- return n.persistency.id;
56
- const e = window.location.pathname, r = Object.keys(p);
57
- return `${e}-${r.join("-")}`;
58
- }), b = () => {
59
- const e = new URLSearchParams(window.location.search);
60
- e.delete(u.value);
61
- const r = new URL(window.location.href);
62
- r.search = e.toString(), window.history.replaceState({}, "", r.toString());
63
- };
64
- function a(e, r) {
65
- for (const t in r)
66
- r[t] && G(r[t]) ? (e[t] || (e[t] = {}), a(e[t], r[t])) : e[t] = r[t];
67
- return e;
68
- }
69
- const v = j(() => {
70
- if (i?.defaultValues && !n?.persistency?.overrideDefaultValues)
71
- return i?.defaultValues;
72
- let e;
73
- const r = n?.persistency;
74
- if (!r?.policies || r.policies.length === 0) return {};
75
- if (r.policies.includes("querystring"))
76
- try {
77
- const s = new URLSearchParams(window.location.search).get(u.value);
78
- b(), s && (e = JSON.parse(s));
79
- } catch (t) {
80
- console.error(t);
81
- }
82
- if (
83
- // query string has higher priority than local/session storage
84
- !e && (r.policies.includes("local") || r.policies.includes("session"))
85
- ) {
86
- const t = r.policies.includes("local") ? localStorage : sessionStorage;
87
- if (t)
88
- try {
89
- const s = JSON.parse(
90
- t.getItem(u.value) || "{}"
91
- );
92
- t.removeItem(u.value), e = s;
93
- } catch (s) {
94
- console.error(s);
1
+ import { defineComponent as d, onMounted as c, createElementBlock as p, openBlock as g, Fragment as v, createVNode as m, unref as i, withCtx as u, renderSlot as f, createCommentVNode as V, createSlots as b, renderList as y, normalizeProps as F, guardReactiveProps as $ } from "vue";
2
+ import k from "./vue-components.es9.js";
3
+ const B = /* @__PURE__ */ d({
4
+ __name: "OmegaTaggedUnion",
5
+ props: {
6
+ name: {},
7
+ form: {},
8
+ type: {},
9
+ options: {},
10
+ label: {}
11
+ },
12
+ setup(n) {
13
+ const e = n;
14
+ return c(() => {
15
+ const t = e.form.getFieldValue(e.name), o = e.form.meta[e.name];
16
+ if (t === void 0)
17
+ if (o?.nullableOrUndefined === "null" || !o?.required)
18
+ e.form.setFieldValue(e.name, null);
19
+ else {
20
+ const a = e.options.find((l) => l.value !== null);
21
+ a && a.value && e.form.setFieldValue(e.name, {
22
+ _tag: a.value
23
+ });
95
24
  }
96
- }
97
- if (e ??= {}, i?.defaultValues == null)
98
- return e;
99
- {
100
- const t = i?.defaultValues;
101
- return a(t, e);
102
- }
103
- }), y = (e, r) => e ? V.with(_.setSpan(V.active(), e), r) : r(), d = q({
104
- ...i,
105
- validators: {
106
- onSubmit: f,
107
- ...i?.validators || {}
108
- },
109
- onSubmit: i?.onSubmit ? ({ formApi: e, meta: r, value: t }) => y(r?.currentSpan, async () => {
110
- const s = await l.runPromise(m(t)), o = i.onSubmit({
111
- formApi: e,
112
- meta: r,
113
- value: s
114
- });
115
- return F.isFiber(o) && F.isRuntimeFiber(o) ? await B(o) : l.isEffect(o) ? await l.runPromise(
116
- o.pipe(
117
- // meta?.currentSpan
118
- // ? Effect.withParentSpan(meta.currentSpan)
119
- // : (_) => _,
120
- l.flatMap((S) => F.join(S))
121
- )
122
- ) : o;
123
- }) : void 0,
124
- defaultValues: v.value
125
- }), x = () => {
126
- Object.keys(p).forEach((e) => {
127
- d.setFieldValue(e, void 0);
128
- });
129
- }, O = (e) => e.reduce((r, t) => {
130
- const s = t.split(".");
131
- return s.reduce((o, S, J) => (J === s.length - 1 ? o[S] = d.getFieldValue(t) : o[S] = o[S] ?? {}, o[S]), r), r;
132
- }, {}), U = (e) => {
133
- if (e) {
134
- if (P.isArray(e.keys))
135
- return O(e.keys);
136
- if (P.isArray(e.banKeys)) {
137
- const r = Object.keys(p).filter((t) => e.banKeys?.includes(t));
138
- return O(r);
139
- }
140
- return d.store.state.values;
141
- }
142
- }, g = () => {
143
- const e = n?.persistency;
144
- if (!(!e?.policies || e.policies.length === 0) && (e.policies.includes("local") || e.policies.includes("session"))) {
145
- const r = e.policies.includes("local") ? localStorage : sessionStorage;
146
- if (!r) return;
147
- const t = U(e);
148
- return r.setItem(u.value, JSON.stringify(t));
149
- }
150
- }, L = () => {
151
- const e = n?.persistency;
152
- if (!(!e?.policies || e.policies.length === 0) && e.policies.includes("querystring")) {
153
- const r = U(e), t = new URLSearchParams(window.location.search);
154
- t.set(u.value, JSON.stringify(r));
155
- const s = new URL(window.location.href);
156
- s.search = t.toString(), window.history.replaceState({}, "", s.toString());
157
- }
158
- };
159
- N(g), T(() => {
160
- window.addEventListener("beforeunload", g), window.addEventListener("blur", L);
161
- }), W(() => {
162
- window.removeEventListener("beforeunload", g), window.removeEventListener("blur", L);
163
- });
164
- const $ = (e) => l.currentSpan.pipe(
165
- l.option,
166
- l.flatMap(
167
- (r) => l.promise(() => d.handleSubmit(M.isSome(r) ? { currentSpan: r.value, ...e } : e))
168
- )
169
- ), D = (e) => e?.checkErrors ? $(e?.meta).pipe(l.flatMap(l.fnUntraced(function* () {
170
- const r = d.getAllErrors();
171
- if (Object.keys(r.fields).length || r.form.errors.length)
172
- return yield* new re({ form: r.form, fields: r.fields });
173
- }))) : $(e?.meta), H = d.handleSubmit, E = k(/* @__PURE__ */ new Map()), h = Object.assign(d, {
174
- i18nNamespace: n?.i18nNamespace,
175
- ignorePreventCloseEvents: n?.ignorePreventCloseEvents,
176
- meta: p,
177
- clear: x,
178
- handleSubmit: (e) => {
179
- const r = _.getSpan(V.active());
180
- return H({ currentSpan: r, ...e });
181
- },
182
- // /** @experimental */
183
- handleSubmitEffect: D,
184
- registerField: (e) => {
185
- z(e, (r) => E.value.set(r.name, { label: r.label, id: r.id }), { immediate: !0 }), N(() => E.value.delete(e.value.name));
186
- }
187
- }), A = { form: h, fieldMap: E };
188
- return Object.assign(h, {
189
- errorContext: A,
190
- Form: w(h)(ee),
191
- Input: w(h)(n?.input ?? C),
192
- Field: d.Field,
193
- Errors: te(A)(Y),
194
- Array: w(h)(Q),
195
- AutoGen: w(h)(X)
196
- });
197
- };
25
+ }), (t, o) => (g(), p(v, null, [
26
+ m(i(n.form).Input, {
27
+ name: `${n.name}._tag`,
28
+ label: n.label,
29
+ type: n.type ?? "select",
30
+ options: n.options
31
+ }, null, 8, ["name", "label", "type", "options"]),
32
+ m(i(n.form).Field, { name: n.name }, {
33
+ default: u(({ field: a, state: l }) => [
34
+ l.value ? f(t.$slots, "default", { key: 0 }) : V("", !0),
35
+ m(k, {
36
+ field: a,
37
+ state: l.value
38
+ }, b({ _: 2 }, [
39
+ y(t.$slots, (C, r) => ({
40
+ name: r,
41
+ fn: u((s) => [
42
+ f(t.$slots, r, F($(s)))
43
+ ])
44
+ }))
45
+ ]), 1032, ["field", "state"])
46
+ ]),
47
+ _: 3
48
+ }, 8, ["name"])
49
+ ], 64));
50
+ }
51
+ });
198
52
  export {
199
- re as FormErrors,
200
- Se as useOmegaForm
53
+ B as default
201
54
  };
@@ -1,32 +1,19 @@
1
- import l from "./vue-components.es24.js";
2
- import { inject as c, provide as u } from "vue";
3
- import { onMountedWithCleanup as f } from "./vue-components.es25.js";
4
- const p = () => l(), i = Symbol("DialogBus"), r = () => c(i, null), g = () => {
5
- const n = p();
6
- return u(i, n), n;
7
- }, d = (n) => {
8
- const o = r();
9
- if (!o)
10
- return;
11
- const s = n();
12
- f(() => {
13
- const e = (t) => {
14
- s.value && (confirm("Es sind ungespeicherte Änderungen vorhanden. Wirklich schließen?") || (t.prevent = !0));
15
- };
16
- return o.on("dialog-closing", e), () => o.off("dialog-closing", e);
17
- });
18
- }, h = (n) => {
19
- let o = r();
20
- return o || (o = g()), () => {
21
- const e = {};
22
- o.emit("dialog-closing", e), e.prevent ? typeof e.prevent == "object" && "then" in e.prevent && e.prevent.then((t) => {
23
- t !== !1 && n();
24
- }) : n();
25
- };
26
- };
1
+ import { defineComponent as l, watch as s, renderSlot as i, createCommentVNode as o, normalizeProps as r, mergeProps as d } from "vue";
2
+ const m = /* @__PURE__ */ l({
3
+ __name: "OmegaTaggedUnionInternal",
4
+ props: {
5
+ state: {},
6
+ field: {}
7
+ },
8
+ setup(e) {
9
+ const a = e;
10
+ return s(() => a.state?._tag, (t, n) => {
11
+ t === null && a.field.setValue(null), t !== n && setTimeout(() => {
12
+ a.field.validate("change");
13
+ }, 0);
14
+ }), (t, n) => e.state?._tag ? i(t.$slots, e.state?._tag, r(d({ key: 0 }, { field: e.field, state: e.state }))) : o("", !0);
15
+ }
16
+ });
27
17
  export {
28
- r as injectBus,
29
- g as provideBus,
30
- h as useOnClose,
31
- d as usePreventClose
18
+ m as default
32
19
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/vue-components",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "peerDependencies": {
5
5
  "@mdi/js": "^7.4.47",
6
6
  "effect": "^3.18.0",
@@ -55,3 +55,35 @@ export type VuetifyInputProps<From extends Record<PropertyKey, any>, TName exten
55
55
  options?: { title: string; value: unknown }[]
56
56
  }
57
57
  } & Pick<InputProps<From, TName>, "field" | "state">
58
+
59
+ // Utility type to extract _tag literal values from a discriminated union
60
+ // For a union like { _tag: "A", ... } | { _tag: "B", ... }, this returns "A" | "B"
61
+ // For nullable unions like { _tag: "A" } | { _tag: "B" } | null, this still returns "A" | "B" (excluding null)
62
+ export type ExtractTagValue<From extends Record<PropertyKey, any>, TName extends DeepKeys<From>> =
63
+ DeepValue<From, TName> extends infer U ? U extends { _tag: infer Tag } ? Tag
64
+ : never
65
+ : never
66
+
67
+ // Utility type to extract a specific branch from a discriminated union based on _tag value
68
+ // For union { _tag: "A", foo: string } | { _tag: "B", bar: number } and Tag="A", returns { _tag: "A", foo: string }
69
+ export type ExtractUnionBranch<T, Tag> = T extends { _tag: Tag } ? T
70
+ : never
71
+
72
+ // Option type for TaggedUnion component with strongly-typed value
73
+ // The value can be either one of the _tag values OR null (for the placeholder)
74
+ export type TaggedUnionOption<From extends Record<PropertyKey, any>, TName extends DeepKeys<From>> = {
75
+ readonly title: string
76
+ readonly value: ExtractTagValue<From, TName> | null
77
+ }
78
+
79
+ // Options array must ALWAYS start with a null option (placeholder), followed by the actual options
80
+ export type TaggedUnionOptionsArray<From extends Record<PropertyKey, any>, TName extends DeepKeys<From>> = readonly [
81
+ { readonly title: string; readonly value: null },
82
+ ...ReadonlyArray<{ readonly title: string; readonly value: ExtractTagValue<From, TName> }>
83
+ ]
84
+
85
+ // Props for TaggedUnion component
86
+ export type TaggedUnionProps<From extends Record<PropertyKey, any>, TName extends DeepKeys<From>> = {
87
+ name: TName
88
+ options: TaggedUnionOptionsArray<From, TName>
89
+ }
@@ -7,7 +7,7 @@ import { getTransformationFrom, useIntl } from "../../utils"
7
7
  import { type OmegaFieldInternalApi } from "./InputProps"
8
8
  import { type OF, type OmegaFormReturn } from "./useOmegaForm"
9
9
 
10
- type Leaves<T, Path extends string = ""> = T extends ReadonlyArray<infer U> ? Leaves<U, `${Path}[number]`> & {}
10
+ export type Leaves<T, Path extends string = ""> = T extends ReadonlyArray<infer U> ? Leaves<U, `${Path}[number]`> & {}
11
11
  : {
12
12
  [K in keyof T]: T[K] extends string | boolean | number | null | undefined | symbol | bigint
13
13
  ? `${Path extends "" ? "" : `${Path}.`}${K & string}`
@@ -344,7 +344,21 @@ export const createMeta = <T = any>(
344
344
  for (const p of propertySignatures) {
345
345
  const key = parent ? `${parent}.${p.name.toString()}` : p.name.toString()
346
346
  const nullableOrUndefined = isNullableOrUndefined(p.type)
347
- const isRequired = !nullableOrUndefined
347
+
348
+ // Determine if this field should be required:
349
+ // - For nullable discriminated unions, only _tag should be non-required
350
+ // - All other fields should calculate their required status normally
351
+ let isRequired: boolean
352
+ if (meta._isNullableDiscriminatedUnion && p.name.toString() === "_tag") {
353
+ // _tag in a nullable discriminated union is not required
354
+ isRequired = false
355
+ } else if (meta.required === false) {
356
+ // Explicitly set to non-required (legacy behavior for backwards compatibility)
357
+ isRequired = false
358
+ } else {
359
+ // Calculate from the property itself
360
+ isRequired = !nullableOrUndefined
361
+ }
348
362
 
349
363
  const typeToProcess = p.type
350
364
  if (S.AST.isUnion(p.type)) {
@@ -375,12 +389,17 @@ export const createMeta = <T = any>(
375
389
  // Process each non-null type and merge their metadata
376
390
  for (const nonNullType of nonNullTypes) {
377
391
  if ("propertySignatures" in nonNullType) {
392
+ // For discriminated unions (multiple branches):
393
+ // - If the parent union is nullable, only _tag should be non-required
394
+ // - All other fields maintain their normal required status based on their own types
395
+ const isNullableDiscriminatedUnion = nullableOrUndefined && nonNullTypes.length > 1
396
+
378
397
  Object.assign(
379
398
  acc,
380
399
  createMeta<T>({
381
400
  parent: key,
382
401
  propertySignatures: nonNullType.propertySignatures,
383
- meta: { required: isRequired, nullableOrUndefined }
402
+ meta: isNullableDiscriminatedUnion ? { _isNullableDiscriminatedUnion: true } : {}
384
403
  })
385
404
  )
386
405
  }
@@ -76,7 +76,10 @@ const humanize = (str: string) => {
76
76
  .replace(/^./, (char) => char.toUpperCase()) // Capitalize the first letter
77
77
  .trim() // Remove leading/trailing spaces
78
78
  }
79
- const fallback = () => formatMessage({ id: `general.fields.${propsName.value}`, defaultMessage: humanize(props.name) })
79
+ const fallback = () =>
80
+ formatMessage
81
+ ? formatMessage({ id: `general.fields.${propsName.value}`, defaultMessage: humanize(props.name) })
82
+ : humanize(props.name)
80
83
  const i18n = () =>
81
84
  props.form.i18nNamespace
82
85
  ? formatMessage({ id: `${props.form.i18nNamespace}.fields.${propsName.value}`, defaultMessage: fallback() })
@@ -14,7 +14,7 @@
14
14
  lang="ts"
15
15
  generic="From extends Record<PropertyKey, any>, Name extends DeepKeys<From>"
16
16
  >
17
- import { type DeepKeys, useStore } from "@tanstack/vue-form"
17
+ import { type DeepKeys, type DeepValue, useStore } from "@tanstack/vue-form"
18
18
  import { computed, type ComputedRef, getCurrentInstance, onMounted, useId } from "vue"
19
19
  import type { InputProps, OmegaFieldInternalApi } from "./InputProps"
20
20
  import type { FieldValidators, MetaRecord, NestedKeyOf, TypeOverride } from "./OmegaFormStuff"
@@ -91,12 +91,18 @@ const isFalsyButNotZero = (value: unknown): boolean => {
91
91
  // convert nullish value to null or undefined based on schema
92
92
  const handleChange: OmegaFieldInternalApi<From, Name>["handleChange"] = (value) => {
93
93
  if (isFalsyButNotZero(value) && props.meta?.type !== "boolean") {
94
- props.field.handleChange(
95
- props.meta?.nullableOrUndefined === "undefined"
96
- ? undefined
97
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
- : null as any
99
- )
94
+ // Only convert to null/undefined if the field is actually nullable or optional
95
+ if (props.meta?.nullableOrUndefined) {
96
+ props.field.handleChange(
97
+ props.meta.nullableOrUndefined === "undefined"
98
+ ? undefined
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ : null as any
101
+ )
102
+ } else {
103
+ // Keep the actual value (e.g., empty string for S.String fields)
104
+ props.field.handleChange(value)
105
+ }
100
106
  } else {
101
107
  props.field.handleChange(value)
102
108
  }
@@ -108,15 +114,31 @@ const handleChange: OmegaFieldInternalApi<From, Name>["handleChange"] = (value)
108
114
 
109
115
  // TODO: it would be cleaner when default values are handled in the form initialization via Schema or by the one using the form component..
110
116
  onMounted(() => {
111
- if (
112
- !fieldValue.value
113
- && !isRequired.value
114
- && props.meta?.nullableOrUndefined === "null"
115
- ) {
117
+ // Initialize field value on mount if it doesn't exist
118
+ if (fieldValue.value === undefined) {
116
119
  const isDirty = fieldState.value.meta.isDirty
117
- fieldApi.setValue(null as any)
118
120
  // make sure we restore the previous dirty state..
119
121
  fieldApi.setMeta((_) => ({ ..._, isDirty }))
122
+
123
+ if (isRequired.value) return
124
+
125
+ // Set appropriate default value based on field type and nullability
126
+ if (props.meta?.nullableOrUndefined === "null") {
127
+ fieldApi.setValue(null as DeepValue<From, Name>)
128
+ } else if (props.meta?.nullableOrUndefined === "undefined") {
129
+ fieldApi.setValue(undefined as DeepValue<From, Name>)
130
+ } else {
131
+ // For required fields, initialize with appropriate empty value
132
+ if (props.meta?.type === "string") {
133
+ fieldApi.setValue("" as DeepValue<From, Name>)
134
+ } else if (props.meta?.type === "number") {
135
+ // Don't initialize number fields to avoid setting them to 0
136
+ // Leave as undefined so validation will catch it
137
+ } else if (props.meta?.type === "boolean") {
138
+ fieldApi.setValue(false as DeepValue<From, Name>)
139
+ }
140
+ // For other types, leave undefined so validation will catch missing required fields
141
+ }
120
142
  }
121
143
  })
122
144