@effect-app/vue-components 4.0.0-beta.244 → 4.0.0-beta.245

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,20 +1,37 @@
1
1
  import type { CommandBase, Progress } from "@effect-app/vue/makeClient";
2
+ import * as Option from "effect-app/Option";
2
3
  import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
3
4
  import type { VBtn } from "vuetify/components";
4
5
  export type VBtnProps = VBtn["$props"];
5
6
  export interface ButtonProps extends /* @vue-ignore */ VBtnProps {
6
7
  }
7
- /** Command Button is an easy way to connect commands and have it execute on click, while keeping track of disabled/loading states automatically */
8
+ /**
9
+ * CommandButton connects a command to a button and tracks disabled / loading state.
10
+ *
11
+ * Input variants:
12
+ * - `input`: pass a validated value; button enabled when command + disabled allow it.
13
+ * - `optionalInput`: pass an `Option<I>`. `Some` → enabled, click fires with the value.
14
+ * `None` → disabled. Use this when the input is gated by a `computed` instead of
15
+ * a `v-if` on the button itself.
16
+ * - neither: command takes no input.
17
+ */
8
18
  declare const _default: typeof __VLS_export;
9
19
  export default _default;
10
20
  declare const __VLS_export: <I = never, RA = unknown, RE = unknown>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
11
21
  props: import("vue").PublicProps & __VLS_PrettifyLocal<({
12
22
  input: NoInfer<I>;
23
+ optionalInput?: undefined;
24
+ command: CommandBase<I, any, RA, RE>;
25
+ empty?: boolean;
26
+ } | {
27
+ optionalInput: Option.Option<NoInfer<I>>;
28
+ input?: undefined;
13
29
  command: CommandBase<I, any, RA, RE>;
14
30
  empty?: boolean;
15
31
  } | {
16
32
  command: CommandBase<any, any, RA, RE>;
17
33
  input?: undefined;
34
+ optionalInput?: undefined;
18
35
  empty?: boolean;
19
36
  }) & {
20
37
  disabled?: ButtonProps["disabled"];
@@ -1,12 +1,12 @@
1
1
  import { isNullableOrUndefined as e, unwrapDeclaration as t } from "./vue-components14.es.js";
2
- import * as n from "effect-app/Schema";
3
- import * as r from "effect-app/Effect";
4
- import * as i from "effect-app/Option";
2
+ import * as n from "effect-app/Option";
3
+ import * as r from "effect-app/Schema";
4
+ import * as i from "effect-app/Effect";
5
5
  //#region src/components/OmegaForm/meta/defaults.ts
6
6
  var a = (e) => {
7
7
  if (e?.transformation?.decode?.run) try {
8
- let t = r.runSync(e.transformation.decode.run(i.none()));
9
- return i.isSome(t) ? t.value : void 0;
8
+ let t = i.runSync(e.transformation.decode.run(n.none()));
9
+ return n.isSome(t) ? t.value : void 0;
10
10
  } catch {
11
11
  return;
12
12
  }
@@ -19,33 +19,33 @@ var a = (e) => {
19
19
  function s(e) {
20
20
  return e && "members" in e && Array.isArray(e.members);
21
21
  }
22
- var c = (e) => typeof e == "object" && !!e && !Array.isArray(e), l = (e) => n.AST.isNull(e) || n.AST.isUndefined(e), u = (e) => {
23
- let r = t(e);
24
- return n.AST.isUnion(r) ? r.types.flatMap(u) : [r];
22
+ var c = (e) => typeof e == "object" && !!e && !Array.isArray(e), l = (e) => r.AST.isNull(e) || r.AST.isUndefined(e), u = (e) => {
23
+ let n = t(e);
24
+ return r.AST.isUnion(n) ? n.types.flatMap(u) : [n];
25
25
  }, d = (e) => {
26
- let r = t(e);
27
- if (n.AST.isLiteral(r)) return r.literal;
28
- if (n.AST.isUnion(r) && r.types.length === 1) return d(r.types[0]);
26
+ let n = t(e);
27
+ if (r.AST.isLiteral(n)) return n.literal;
28
+ if (r.AST.isUnion(n) && n.types.length === 1) return d(n.types[0]);
29
29
  }, f = (e, t) => {
30
30
  if (!(!c(t) || t._tag === void 0)) return e.find((e) => {
31
31
  let n = e.propertySignatures.find((e) => e.name.toString() === "_tag");
32
32
  return n ? d(n.type) === t._tag : !1;
33
33
  });
34
- }, p = (r, i = {}) => {
35
- let a = r.ast, c = o(a);
34
+ }, p = (n, i = {}) => {
35
+ let a = n.ast, c = o(a);
36
36
  if (c !== void 0) return c;
37
- if (e(r.ast) === "null") return null;
38
- if (e(r.ast) === "undefined") return;
39
- let l = n.AST.isObjects(a) ? a : n.AST.isDeclaration(a) ? t(a) : void 0;
40
- if (l && n.AST.isObjects(l)) {
37
+ if (e(n.ast) === "null") return null;
38
+ if (e(n.ast) === "undefined") return;
39
+ let l = r.AST.isObjects(a) ? a : r.AST.isDeclaration(a) ? t(a) : void 0;
40
+ if (l && r.AST.isObjects(l)) {
41
41
  let t = {};
42
- for (let r of l.propertySignatures) {
43
- let a = r.name.toString(), s = r.type, c = o(s);
42
+ for (let n of l.propertySignatures) {
43
+ let a = n.name.toString(), s = n.type, c = o(s);
44
44
  if (c !== void 0) {
45
45
  t[a] = c;
46
46
  continue;
47
47
  }
48
- let l = p(n.make(s), i[a] || {});
48
+ let l = p(r.make(s), i[a] || {});
49
49
  l === void 0 ? e(s) === "undefined" && (t[a] = void 0) : t[a] = l;
50
50
  }
51
51
  return {
@@ -53,31 +53,31 @@ var c = (e) => typeof e == "object" && !!e && !Array.isArray(e), l = (e) => n.AS
53
53
  ...i
54
54
  };
55
55
  }
56
- let u = n.AST.isUnion(a) ? a.types : s(r) ? r.members.map((e) => e.ast) : void 0;
56
+ let u = r.AST.isUnion(a) ? a.types : s(n) ? n.members.map((e) => e.ast) : void 0;
57
57
  if (u) {
58
58
  let e = {};
59
- for (let r of u) {
60
- let i = t(r);
61
- if (n.AST.isObjects(i)) for (let t of i.propertySignatures) {
59
+ for (let n of u) {
60
+ let i = t(n);
61
+ if (r.AST.isObjects(i)) for (let t of i.propertySignatures) {
62
62
  let n = t.name.toString(), r = o(t.type), i = e[n] ? o(e[n].ast) : void 0;
63
63
  (!e[n] || r !== void 0 && i === void 0) && (e[n] = { ast: t.type });
64
64
  }
65
65
  }
66
- return Object.keys(e).length === 0 ? Object.keys(i).length > 0 ? i : void 0 : Object.entries(e).reduce((e, [t, { ast: r }]) => (e[t] = p(n.make(r), i[t] || {}), e), i);
66
+ return Object.keys(e).length === 0 ? Object.keys(i).length > 0 ? i : void 0 : Object.entries(e).reduce((e, [t, { ast: n }]) => (e[t] = p(r.make(n), i[t] || {}), e), i);
67
67
  }
68
68
  if (Object.keys(i).length === 0) {
69
- if (n.AST.isString(a)) return "";
70
- if (n.AST.isBoolean(a)) return !1;
69
+ if (r.AST.isString(a)) return "";
70
+ if (r.AST.isBoolean(a)) return !1;
71
71
  }
72
- }, m = (r, i, a = !1) => {
73
- let s = t(r);
72
+ }, m = (n, i, a = !1) => {
73
+ let s = t(n);
74
74
  switch (s._tag) {
75
75
  case "Union": {
76
76
  if (i == null) return i;
77
- let e = u(s), t = e.filter(n.AST.isObjects);
77
+ let e = u(s), t = e.filter(r.AST.isObjects);
78
78
  if (t.length === 0) return i;
79
- let r = e.some(l), o = f(t, i);
80
- return o ? m(o, i, a || r) : r && t.length === 1 ? m(t[0], i, !0) : i;
79
+ let n = e.some(l), o = f(t, i);
80
+ return o ? m(o, i, a || n) : n && t.length === 1 ? m(t[0], i, !0) : i;
81
81
  }
82
82
  case "Arrays": {
83
83
  if (!Array.isArray(i)) return i;
@@ -1,5 +1,5 @@
1
- import * as e from "effect-app/Schema";
2
- import * as t from "effect-app/Option";
1
+ import * as e from "effect-app/Option";
2
+ import * as t from "effect-app/Schema";
3
3
  //#region src/components/OmegaForm/validation/localized.ts
4
4
  var n = (n) => ({
5
5
  leafHook: (r) => {
@@ -9,18 +9,18 @@ var n = (n) => ({
9
9
  case "MissingKey": return n("validation.empty");
10
10
  case "InvalidType": {
11
11
  let i = r.ast;
12
- return t.isNone(r.actual) || t.isSome(r.actual) && r.actual.value === void 0 || e.AST.isString(i) ? n("validation.empty") : e.AST.isBoolean(i) ? n("validation.not_a_valid", { type: "boolean" }) : e.AST.isNumber(i) ? n("validation.number.expected", { actualValue: t.isSome(r.actual) ? String(r.actual.value) : "NaN" }) : n("validation.not_a_valid");
12
+ return e.isNone(r.actual) || e.isSome(r.actual) && r.actual.value === void 0 || t.AST.isString(i) ? n("validation.empty") : t.AST.isBoolean(i) ? n("validation.not_a_valid", { type: "boolean" }) : t.AST.isNumber(i) ? n("validation.number.expected", { actualValue: e.isSome(r.actual) ? String(r.actual.value) : "NaN" }) : n("validation.not_a_valid");
13
13
  }
14
14
  default: return n("validation.not_a_valid");
15
15
  }
16
16
  },
17
- checkHook: (t) => {
18
- if (t.filter.annotations?.identifier === "Email") return n("validation.email.invalid");
19
- let r = t.filter.annotations?.meta ?? {};
17
+ checkHook: (e) => {
18
+ if (e.filter.annotations?.identifier === "Email") return n("validation.email.invalid");
19
+ let r = e.filter.annotations?.meta ?? {};
20
20
  switch (r._tag) {
21
21
  case "isMinLength": return r.minLength === 1 ? n("validation.empty") : n("validation.string.minLength", { minLength: r.minLength });
22
22
  case "isMaxLength": return n("validation.string.maxLength", { maxLength: r.maxLength });
23
- case "isInt": return n("validation.integer.expected", { actualValue: t.actual === void 0 ? "NaN" : String(t.actual) });
23
+ case "isInt": return n("validation.integer.expected", { actualValue: e.actual === void 0 ? "NaN" : String(e.actual) });
24
24
  case "isGreaterThanOrEqualTo": return n(r.minimum === 0 ? "validation.number.positive" : "validation.number.min", {
25
25
  minimum: r.minimum,
26
26
  isExclusive: !0
@@ -37,57 +37,57 @@ var n = (n) => ({
37
37
  maximum: r.exclusiveMaximum,
38
38
  isExclusive: !1
39
39
  });
40
- default: return e.SchemaIssue.defaultCheckHook(t);
40
+ default: return t.SchemaIssue.defaultCheckHook(e);
41
41
  }
42
42
  }
43
- }), r = (t, r) => {
43
+ }), r = (e, r) => {
44
44
  let { checkHook: i, leafHook: a } = n(r);
45
- return e.toStandardSchemaV1(t, {
45
+ return t.toStandardSchemaV1(e, {
46
46
  leafHook: a,
47
47
  checkHook: i
48
48
  });
49
- }, i = (t) => e.AST.isUnion(t) && t.types.every(e.AST.isLiteral), a = (t, n) => {
50
- if (i(t)) {
51
- if (t.annotations?.message !== void 0) return t;
52
- let r = t.types.map((e) => e.literal);
53
- return new e.AST.Union(t.types, t.mode, {
54
- ...t.annotations,
49
+ }, i = (e) => t.AST.isUnion(e) && e.types.every(t.AST.isLiteral), a = (e, n) => {
50
+ if (i(e)) {
51
+ if (e.annotations?.message !== void 0) return e;
52
+ let r = e.types.map((e) => e.literal);
53
+ return new t.AST.Union(e.types, e.mode, {
54
+ ...e.annotations,
55
55
  message: n("validation.not_a_valid", {
56
56
  type: "select",
57
57
  message: r.join(", ")
58
58
  })
59
- }, t.checks, t.encoding, t.context);
59
+ }, e.checks, e.encoding, e.context);
60
60
  }
61
- if (e.AST.isUnion(t)) {
62
- let r = t.types.map((e) => a(e, n));
63
- return r.some((e, n) => e !== t.types[n]) ? new e.AST.Union(r, t.mode, t.annotations, t.checks, t.encoding, t.context) : t;
61
+ if (t.AST.isUnion(e)) {
62
+ let r = e.types.map((e) => a(e, n));
63
+ return r.some((t, n) => t !== e.types[n]) ? new t.AST.Union(r, e.mode, e.annotations, e.checks, e.encoding, e.context) : e;
64
64
  }
65
- if (e.AST.isArrays(t)) {
66
- let r = t.rest.map((e) => a(e, n)), o = t.elements.map((e) => a(e, n)), s = t.annotations;
67
- if (t.annotations?.message === void 0 && t.rest.length === 1 && i(t.rest[0])) {
68
- let e = t.rest[0].types.map((e) => e.literal);
65
+ if (t.AST.isArrays(e)) {
66
+ let r = e.rest.map((e) => a(e, n)), o = e.elements.map((e) => a(e, n)), s = e.annotations;
67
+ if (e.annotations?.message === void 0 && e.rest.length === 1 && i(e.rest[0])) {
68
+ let t = e.rest[0].types.map((e) => e.literal);
69
69
  s = {
70
- ...t.annotations,
70
+ ...e.annotations,
71
71
  message: n("validation.not_a_valid", {
72
72
  type: "multiple",
73
- message: e.join(", ")
73
+ message: t.join(", ")
74
74
  })
75
75
  };
76
76
  }
77
- let c = r.some((e, n) => e !== t.rest[n]), l = o.some((e, n) => e !== t.elements[n]);
78
- return !c && !l && s === t.annotations ? t : new e.AST.Arrays(t.isMutable, o, r, s, t.checks, t.encoding, t.context);
77
+ let c = r.some((t, n) => t !== e.rest[n]), l = o.some((t, n) => t !== e.elements[n]);
78
+ return !c && !l && s === e.annotations ? e : new t.AST.Arrays(e.isMutable, o, r, s, e.checks, e.encoding, e.context);
79
79
  }
80
- if (e.AST.isObjects(t)) {
81
- let r = t.propertySignatures.map((t) => {
82
- let r = a(t.type, n);
83
- return r === t.type ? t : new e.AST.PropertySignature(t.name, r);
80
+ if (t.AST.isObjects(e)) {
81
+ let r = e.propertySignatures.map((e) => {
82
+ let r = a(e.type, n);
83
+ return r === e.type ? e : new t.AST.PropertySignature(e.name, r);
84
84
  });
85
- return r.some((e, n) => e !== t.propertySignatures[n]) ? new e.AST.Objects(r, t.indexSignatures, t.annotations, t.checks, t.encoding, t.context) : t;
85
+ return r.some((t, n) => t !== e.propertySignatures[n]) ? new t.AST.Objects(r, e.indexSignatures, e.annotations, e.checks, e.encoding, e.context) : e;
86
86
  }
87
- return t;
88
- }, o = (t, n) => {
89
- let r = a(t.ast, n);
90
- return r === t.ast ? t : e.make(r);
87
+ return e;
88
+ }, o = (e, n) => {
89
+ let r = a(e.ast, n);
90
+ return r === e.ast ? e : t.make(r);
91
91
  };
92
92
  //#endregion
93
93
  export { o as annotateLiteralUnionMessages, n as makeStandardSchemaV1Hooks, r as toLocalizedStandardSchemaV1 };
@@ -1,9 +1,11 @@
1
1
  import { computed as e, createBlock as t, createCommentVNode as n, createElementVNode as r, createSlots as i, createTextVNode as a, createVNode as o, defineComponent as s, mergeProps as c, openBlock as l, renderSlot as u, resolveComponent as d, toDisplayString as f, withCtx as p } from "vue";
2
+ import * as m from "effect-app/Option";
2
3
  //#region src/components/CommandButton.vue?vue&type=script&setup=true&lang.ts
3
- var m = { class: "ml-2" }, h = { class: "ml-2" }, g = /* @__PURE__ */ s({
4
+ var h = { class: "ml-2" }, g = { class: "ml-2" }, _ = /* @__PURE__ */ s({
4
5
  name: "CommandButton",
5
6
  props: {
6
7
  input: {},
8
+ optionalInput: {},
7
9
  command: {},
8
10
  empty: { type: Boolean },
9
11
  disabled: {},
@@ -11,70 +13,80 @@ var m = { class: "ml-2" }, h = { class: "ml-2" }, g = /* @__PURE__ */ s({
11
13
  mapProgress: { type: Function }
12
14
  },
13
15
  setup(s) {
14
- let g = s, _ = e(() => g.command.blocked || g.disabled), v = e(() => {
15
- if (g.mapProgress) {
16
- let e = g.command.result;
17
- return e === void 0 ? void 0 : g.mapProgress(e);
16
+ let _ = s, v = e(() => "optionalInput" in _ && _.optionalInput !== void 0 ? m.isSome(_.optionalInput) ? {
17
+ _tag: "ready",
18
+ value: _.optionalInput.value
19
+ } : { _tag: "missing" } : "input" in _ && _.input !== void 0 ? {
20
+ _tag: "ready",
21
+ value: _.input
22
+ } : { _tag: "void" }), y = e(() => _.command.blocked || _.disabled || v.value._tag === "missing"), b = e(() => {
23
+ if (_.mapProgress) {
24
+ let e = _.command.result;
25
+ return e === void 0 ? void 0 : _.mapProgress(e);
18
26
  }
19
- return g.command.progress;
20
- }), y = e(() => {
21
- let e = v.value;
27
+ return _.command.progress;
28
+ }), x = e(() => {
29
+ let e = b.value;
22
30
  if (e !== void 0) return typeof e == "string" ? e : e.text;
23
- }), b = e(() => {
24
- let e = v.value;
31
+ }), S = e(() => {
32
+ let e = b.value;
25
33
  return typeof e == "object" && e ? e.percentage : void 0;
26
- }), x = () => {
27
- if (_.value) return;
28
- let e = "input" in g && g.input ? g.input : void 0, t = g.command.handle;
29
- t(e);
34
+ }), C = () => {
35
+ if (y.value) return;
36
+ let e = v.value, t = _.command.handle;
37
+ e._tag === "ready" ? t(e.value) : e._tag === "void" && t(void 0);
30
38
  };
31
- return (e, g) => {
32
- let v = d("v-progress-circular"), S = d("v-btn");
33
- return s.command.allowed && !s.empty ? (l(), t(S, c({ key: 0 }, e.$attrs, {
39
+ return (e, m) => {
40
+ let _ = d("v-progress-circular"), v = d("v-btn");
41
+ return s.command.allowed && !s.empty ? (l(), t(v, c({ key: 0 }, e.$attrs, {
34
42
  loading: s.command.waiting,
35
- "aria-disabled": _.value,
43
+ disabled: y.value,
44
+ "aria-disabled": y.value,
36
45
  title: s.title ?? s.command.action,
37
- class: { "v-btn--disabled": _.value },
38
- onClick: x
46
+ class: { "v-btn--disabled": y.value },
47
+ onClick: C
39
48
  }), i({
40
49
  default: p(() => [u(e.$slots, "default", {
41
50
  loading: s.command.waiting,
42
- disabled: _.value,
51
+ disabled: y.value,
43
52
  label: s.command.label,
44
53
  title: s.title ?? s.command.action
45
54
  }, () => [a(f(s.command.label), 1)])]),
46
55
  _: 2
47
- }, [y.value === void 0 ? void 0 : {
56
+ }, [x.value === void 0 ? void 0 : {
48
57
  name: "loader",
49
- fn: p(() => [o(v, {
50
- indeterminate: b.value === void 0,
51
- "model-value": b.value,
58
+ fn: p(() => [o(_, {
59
+ indeterminate: S.value === void 0,
60
+ "model-value": S.value,
52
61
  size: "20",
53
62
  width: "2"
54
- }, null, 8, ["indeterminate", "model-value"]), r("span", m, f(y.value), 1)]),
63
+ }, null, 8, ["indeterminate", "model-value"]), r("span", h, f(x.value), 1)]),
55
64
  key: "0"
56
65
  }]), 1040, [
57
66
  "loading",
67
+ "disabled",
58
68
  "aria-disabled",
59
69
  "title",
60
70
  "class"
61
- ])) : s.command.allowed ? (l(), t(S, c({ key: 1 }, e.$attrs, {
71
+ ])) : s.command.allowed ? (l(), t(v, c({ key: 1 }, e.$attrs, {
62
72
  loading: s.command.waiting,
63
- "aria-disabled": _.value,
73
+ disabled: y.value,
74
+ "aria-disabled": y.value,
64
75
  title: s.title ?? s.command.action,
65
- class: { "v-btn--disabled": _.value },
66
- onClick: x
67
- }), i({ _: 2 }, [y.value === void 0 ? void 0 : {
76
+ class: { "v-btn--disabled": y.value },
77
+ onClick: C
78
+ }), i({ _: 2 }, [x.value === void 0 ? void 0 : {
68
79
  name: "loader",
69
- fn: p(() => [o(v, {
70
- indeterminate: b.value === void 0,
71
- "model-value": b.value,
80
+ fn: p(() => [o(_, {
81
+ indeterminate: S.value === void 0,
82
+ "model-value": S.value,
72
83
  size: "20",
73
84
  width: "2"
74
- }, null, 8, ["indeterminate", "model-value"]), r("span", h, f(y.value), 1)]),
85
+ }, null, 8, ["indeterminate", "model-value"]), r("span", g, f(x.value), 1)]),
75
86
  key: "0"
76
87
  }]), 1040, [
77
88
  "loading",
89
+ "disabled",
78
90
  "aria-disabled",
79
91
  "title",
80
92
  "class"
@@ -83,4 +95,4 @@ var m = { class: "ml-2" }, h = { class: "ml-2" }, g = /* @__PURE__ */ s({
83
95
  }
84
96
  });
85
97
  //#endregion
86
- export { g as default };
98
+ export { _ as default };
@@ -1,21 +1,21 @@
1
1
  import { context as e } from "./vue-components64.es.js";
2
2
  import { trace as t } from "./vue-components66.es.js";
3
- import * as n from "effect-app/Effect";
4
- import * as r from "effect-app/Option";
3
+ import * as n from "effect-app/Option";
4
+ import * as r from "effect-app/Effect";
5
5
  import { runtimeFiberAsPromise as i } from "effect-app/utils";
6
6
  import * as a from "effect/Data";
7
7
  import * as o from "effect/Fiber";
8
8
  //#region src/components/OmegaForm/submit.ts
9
- var s = class extends a.TaggedError("FormErrors") {}, c = (n, r) => n ? e.with(t.setSpan(e.active(), n), r) : r(), l = (e, t, r) => {
9
+ var s = class extends a.TaggedError("FormErrors") {}, c = (n, r) => n ? e.with(t.setSpan(e.active(), n), r) : r(), l = (e, t, n) => {
10
10
  if (e) return ({ formApi: a, meta: s, value: l }) => c(s?.currentSpan, async () => {
11
11
  let c = e({
12
12
  formApi: a,
13
13
  meta: s,
14
- value: await r(t(l))
14
+ value: await n(t(l))
15
15
  });
16
16
  if (o.isFiber(c)) return await i(c);
17
- if (n.isEffect(c)) {
18
- let e = await r(c);
17
+ if (r.isEffect(c)) {
18
+ let e = await n(c);
19
19
  return o.isFiber(e) ? await i(e) : e;
20
20
  }
21
21
  return c;
@@ -24,15 +24,15 @@ var s = class extends a.TaggedError("FormErrors") {}, c = (n, r) => n ? e.with(t
24
24
  let a = i.handleSubmit.bind(i), o = async (e) => await a(e), c = (n) => o({
25
25
  currentSpan: t.getSpan(e.active()),
26
26
  ...n
27
- }), l = (e) => n.currentSpan.pipe(n.option, n.flatMap((t) => n.promise(() => o(r.isSome(t) ? {
27
+ }), l = (e) => r.currentSpan.pipe(r.option, r.flatMap((t) => r.promise(() => o(n.isSome(t) ? {
28
28
  currentSpan: t.value,
29
29
  ...e
30
30
  } : e))));
31
31
  return {
32
32
  handleSubmit: c,
33
- handleSubmitEffect: (e) => e?.checkErrors ? l(e?.meta).pipe(n.flatMap(n.fnUntraced(function* () {
33
+ handleSubmitEffect: (e) => e?.checkErrors ? l(e?.meta).pipe(r.flatMap(r.fnUntraced(function* () {
34
34
  let e = i.getAllErrors();
35
- if (Object.keys(e.fields).length || e.form.errors.length) return yield* n.fail(new s({
35
+ if (Object.keys(e.fields).length || e.form.errors.length) return yield* r.fail(new s({
36
36
  form: e.form,
37
37
  fields: e.fields
38
38
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/vue-components",
3
- "version": "4.0.0-beta.244",
3
+ "version": "4.0.0-beta.245",
4
4
  "peerDependencies": {
5
5
  "@mdi/js": "^7.4.47",
6
6
  "effect": "^4.0.0-beta.70",
@@ -57,8 +57,8 @@
57
57
  "highlight.js": "^11.11.1",
58
58
  "mitt": "^3.0.1",
59
59
  "vue3-highlightjs": "^1.0.5",
60
- "@effect-app/vue": "4.0.0-beta.244",
61
- "effect-app": "4.0.0-beta.244"
60
+ "@effect-app/vue": "4.0.0-beta.245",
61
+ "effect-app": "4.0.0-beta.245"
62
62
  },
63
63
  "scripts": {
64
64
  "check": "vue-tsc",
@@ -4,6 +4,7 @@
4
4
  generic="I = never, RA = unknown, RE = unknown"
5
5
  >
6
6
  import type { CommandBase, Progress } from "@effect-app/vue/makeClient"
7
+ import * as Option from "effect-app/Option"
7
8
  import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
8
9
  import { computed } from "vue"
9
10
  import type { VBtn } from "vuetify/components"
@@ -15,12 +16,20 @@ const props = defineProps<
15
16
  & (
16
17
  | {
17
18
  input: NoInfer<I>
19
+ optionalInput?: undefined
20
+ command: CommandBase<I, any, RA, RE>
21
+ empty?: boolean
22
+ }
23
+ | {
24
+ optionalInput: Option.Option<NoInfer<I>>
25
+ input?: undefined
18
26
  command: CommandBase<I, any, RA, RE>
19
27
  empty?: boolean
20
28
  }
21
29
  | {
22
30
  command: CommandBase<any, any, RA, RE>
23
31
  input?: undefined
32
+ optionalInput?: undefined
24
33
  empty?: boolean
25
34
  }
26
35
  )
@@ -32,7 +41,23 @@ const props = defineProps<
32
41
  & ButtonProps
33
42
  >()
34
43
 
35
- 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
+ })
55
+
56
+ const isDisabled = computed(() =>
57
+ props.command.blocked
58
+ || props.disabled
59
+ || resolvedInput.value._tag === "missing"
60
+ )
36
61
 
37
62
  const resolvedProgress = computed(() => {
38
63
  if (props.mapProgress) {
@@ -54,21 +79,26 @@ const progressPercentage = computed(() => {
54
79
  })
55
80
 
56
81
  const handleClick = () => {
57
- // Block execution if button is disabled
58
- if (isDisabled.value) {
59
- return
60
- }
61
-
62
- const input = ("input" in props && props.input
63
- ? props.input
64
- : undefined) as unknown as I
65
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- command.handle has a generic signature mismatched by erased input type
82
+ if (isDisabled.value) return
83
+ const ri = resolvedInput.value
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
85
  const handle = props.command.handle as any
67
- handle(input)
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
68
89
  }
69
90
  </script>
70
91
  <script lang="ts">
71
- /** 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
+ */
72
102
  export default {
73
103
  name: "CommandButton"
74
104
  }
@@ -78,6 +108,7 @@ export default {
78
108
  v-if="command.allowed && !empty"
79
109
  v-bind="$attrs"
80
110
  :loading="command.waiting"
111
+ :disabled="isDisabled"
81
112
  :aria-disabled="isDisabled"
82
113
  :title="title ?? command.action"
83
114
  :class="{ 'v-btn--disabled': isDisabled }"
@@ -108,6 +139,7 @@ export default {
108
139
  v-else-if="command.allowed"
109
140
  v-bind="$attrs"
110
141
  :loading="command.waiting"
142
+ :disabled="isDisabled"
111
143
  :aria-disabled="isDisabled"
112
144
  :title="title ?? command.action"
113
145
  :class="{ 'v-btn--disabled': isDisabled }"