@effect-app/vue-components 0.0.8 → 0.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 (42) hide show
  1. package/dist/types/components/OmegaForm/InputProps.d.ts +64 -0
  2. package/dist/types/components/OmegaForm/OmegaErrors.vue.d.ts +28 -1
  3. package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +1 -1
  4. package/dist/types/components/OmegaForm/OmegaInput.vue.d.ts +16 -6
  5. package/dist/types/components/OmegaForm/OmegaInputVuetify.vue.d.ts +16 -0
  6. package/dist/types/components/OmegaForm/OmegaInternalInput.vue.d.ts +24 -3
  7. package/dist/types/components/OmegaForm/index.d.ts +1 -1
  8. package/dist/types/index.d.ts +4 -4
  9. package/dist/types/utils/index.d.ts +1 -1
  10. package/dist/vue-components.es.js +31 -618
  11. package/dist/vue-components.es10.js +25 -0
  12. package/dist/vue-components.es11.js +64 -0
  13. package/dist/vue-components.es12.js +9 -0
  14. package/dist/vue-components.es13.js +4 -0
  15. package/dist/vue-components.es14.js +90 -0
  16. package/dist/vue-components.es15.js +86 -0
  17. package/dist/vue-components.es16.js +13 -0
  18. package/dist/vue-components.es17.js +4 -0
  19. package/dist/vue-components.es18.js +134 -0
  20. package/dist/vue-components.es2.js +22 -0
  21. package/dist/vue-components.es20.js +6 -0
  22. package/dist/vue-components.es3.js +11 -0
  23. package/dist/vue-components.es4.js +30 -0
  24. package/dist/vue-components.es5.js +25 -0
  25. package/dist/vue-components.es6.js +218 -0
  26. package/dist/vue-components.es7.js +7 -0
  27. package/dist/vue-components.es8.js +48 -0
  28. package/dist/vue-components.es9.js +7 -0
  29. package/package.json +13 -4
  30. package/src/components/OmegaForm/InputProps.ts +81 -0
  31. package/src/components/OmegaForm/OmegaErrors.vue +69 -30
  32. package/src/components/OmegaForm/OmegaFormStuff.ts +2 -0
  33. package/src/components/OmegaForm/OmegaInput.vue +25 -38
  34. package/src/components/OmegaForm/OmegaInputVuetify.vue +164 -0
  35. package/src/components/OmegaForm/OmegaInternalInput.vue +43 -88
  36. package/src/components/OmegaForm/useOmegaForm.ts +3 -1
  37. package/src/components/style.css +1 -1
  38. package/src/constants/index.ts +1 -1
  39. package/src/env.d.ts +2 -2
  40. package/src/index.ts +12 -8
  41. package/src/utils/index.ts +9 -5
  42. package/dist/vue-components.css +0 -1
@@ -0,0 +1,218 @@
1
+ import { S as i, pipe as p, Option as f } from "effect-app";
2
+ import { useIntl as S } from "./vue-components.es3.js";
3
+ const y = i.NonEmptyArray(i.String), v = (e) => i.AST.isUnion(e) && e.types.find((t) => t._tag === "UndefinedKeyword" || t === i.Null.ast), x = (e) => !e || !i.AST.isUnion(e) ? !1 : e.types.find((t) => t._tag === "UndefinedKeyword") ? "undefined" : e.types.find((t) => t === i.Null.ast) ? "null" : !1, m = ({ meta: e = {}, parent: t = "", property: n, propertySignatures: a }, l = {}) => {
4
+ if (n && n._tag === "Transformation")
5
+ return m({
6
+ parent: t,
7
+ meta: e,
8
+ property: n.from
9
+ });
10
+ if ((n == null ? void 0 : n._tag) === "TypeLiteral" && "propertySignatures" in n)
11
+ return m({
12
+ meta: e,
13
+ propertySignatures: n.propertySignatures
14
+ });
15
+ if (a) {
16
+ for (const s of a) {
17
+ const u = t ? `${t}.${s.name.toString()}` : s.name.toString(), r = x(s.type), o = e.required ?? !r;
18
+ let d = s.type;
19
+ if (i.AST.isUnion(s.type) && (d = s.type.types.find(
20
+ (g) => g._tag !== "UndefinedKeyword" && g !== i.Null.ast
21
+ )), "propertySignatures" in d)
22
+ Object.assign(
23
+ l,
24
+ m({
25
+ parent: u,
26
+ propertySignatures: d.propertySignatures,
27
+ meta: { required: o, nullableOrUndefined: r }
28
+ })
29
+ );
30
+ else {
31
+ const g = m({
32
+ parent: u,
33
+ property: s.type,
34
+ meta: { required: o, nullableOrUndefined: r }
35
+ });
36
+ l[u] = g;
37
+ }
38
+ }
39
+ return l;
40
+ }
41
+ if (n) {
42
+ const s = v(n);
43
+ if (Object.hasOwnProperty.call(e, "required") || (e.required = !s), i.AST.isUnion(n)) {
44
+ const r = n.types.find(
45
+ (o) => o._tag !== "UndefinedKeyword" && o !== i.Null.ast
46
+ );
47
+ return "propertySignatures" in r ? m({
48
+ propertySignatures: r.propertySignatures,
49
+ parent: t,
50
+ meta: e
51
+ }) : n.types.every(i.AST.isLiteral) ? {
52
+ ...e,
53
+ type: "select",
54
+ members: n.types.map((o) => o.literal)
55
+ } : {
56
+ ...e,
57
+ ...m({
58
+ parent: t,
59
+ meta: e,
60
+ property: r
61
+ })
62
+ };
63
+ }
64
+ if (i.AST.isTupleType(n))
65
+ return {
66
+ ...e,
67
+ type: "multiple",
68
+ members: n.elements
69
+ };
70
+ const u = i.AST.getAnnotation(
71
+ n,
72
+ i.AST.JSONSchemaAnnotationId
73
+ ).pipe(f.getOrElse(() => ({})));
74
+ return e = { ...e, ...u }, "from" in n ? m({
75
+ parent: t,
76
+ meta: e,
77
+ property: n.from
78
+ }) : (e.type = i.AST.getAnnotation(
79
+ n,
80
+ i.AST.TitleAnnotationId
81
+ ).pipe(
82
+ f.getOrElse(() => "unknown")
83
+ ), e);
84
+ }
85
+ return l;
86
+ }, c = (e) => {
87
+ const t = e.ast, n = {};
88
+ if (t._tag === "Transformation" || t._tag === "Refinement")
89
+ return c(i.make(t.from));
90
+ if ("propertySignatures" in t) {
91
+ const a = m({
92
+ propertySignatures: t.propertySignatures
93
+ });
94
+ if (Object.values(a).every((s) => s && "type" in s))
95
+ return a;
96
+ const l = (s, u = "") => {
97
+ for (const r in s) {
98
+ const o = u ? `${u}.${r}` : r;
99
+ s[r] && typeof s[r] == "object" && "type" in s[r] ? n[o] = s[r] : s[r] && typeof s[r] == "object" && l(s[r], o);
100
+ }
101
+ };
102
+ l(a);
103
+ }
104
+ return n;
105
+ }, b = (e) => i.extend(e, i.Struct({})), A = (e) => {
106
+ const t = c(e), n = p(
107
+ e.ast,
108
+ f.liftPredicate((a) => a._tag === "Refinement" && "filter" in a),
109
+ f.flatMap((a) => i.AST.getJSONSchemaAnnotation(a)),
110
+ f.filter((a) => "items" in a),
111
+ f.filterMap(
112
+ ({ items: a }) => i.decodeUnknownOption(y)(a)
113
+ ),
114
+ f.zipWith(
115
+ i.AST.getMessageAnnotation(e.ast),
116
+ (a, l) => ({
117
+ items: a,
118
+ message: l("")
119
+ })
120
+ ),
121
+ f.getOrUndefined
122
+ );
123
+ return { schema: e, meta: t, filterItems: n };
124
+ }, O = (e) => {
125
+ const { trans: t } = S();
126
+ let n;
127
+ switch (e.type) {
128
+ case "string":
129
+ n = i.String.annotations({
130
+ message: () => t("validation.empty")
131
+ }), e.format === "email" && (n = i.compose(
132
+ n,
133
+ i.Email.annotations({
134
+ message: () => t("validation.email.invalid")
135
+ })
136
+ )), e.required && n.annotations({
137
+ message: () => t("validation.empty")
138
+ }), e.maxLength && (n = n.pipe(i.maxLength(e.maxLength)).annotations({
139
+ message: () => t("validation.string.maxLength", {
140
+ maxLength: e.maxLength
141
+ })
142
+ })), e.minLength && (n = n.pipe(i.minLength(e.minLength)).annotations({
143
+ message: () => t("validation.string.minLength", {
144
+ minLength: e.minLength
145
+ })
146
+ }));
147
+ break;
148
+ case "number":
149
+ n = i.Number.annotations({
150
+ message: () => t("validation.empty")
151
+ }), e.required && n.annotations({
152
+ message: () => t("validation.empty")
153
+ }), e.minimum && (n = n.pipe(i.greaterThanOrEqualTo(e.minimum)).annotations({
154
+ message: () => t("validation.number.min", {
155
+ minimum: e.minimum,
156
+ isExclusive: !0
157
+ })
158
+ })), e.maximum && (n = n.pipe(i.lessThanOrEqualTo(e.maximum)).annotations({
159
+ message: () => t("validation.number.max", {
160
+ maximum: e.maximum,
161
+ isExclusive: !0
162
+ })
163
+ })), e.exclusiveMinimum && (n = n.pipe(i.greaterThan(e.exclusiveMinimum)).annotations({
164
+ message: () => t("validation.number.min", {
165
+ minimum: e.exclusiveMinimum,
166
+ isExclusive: !1
167
+ })
168
+ })), e.exclusiveMaximum && (n = n.pipe(i.lessThan(e.exclusiveMaximum)).annotations({
169
+ message: () => t("validation.number.max", {
170
+ maximum: e.exclusiveMaximum,
171
+ isExclusive: !1
172
+ })
173
+ }));
174
+ break;
175
+ case "select":
176
+ n = i.Literal(...e.members).annotations({
177
+ message: () => ({
178
+ message: t("validation.not_a_valid", {
179
+ type: "select",
180
+ message: e.members.join(", ")
181
+ }),
182
+ override: !0
183
+ })
184
+ });
185
+ break;
186
+ case "multiple":
187
+ n = i.Array(i.String).annotations({
188
+ message: () => t("validation.not_a_valid", {
189
+ type: "multiple",
190
+ message: e.members.join(", ")
191
+ })
192
+ });
193
+ break;
194
+ case "boolean":
195
+ n = i.Boolean;
196
+ break;
197
+ // todo: switch must be exhaustive or have default case, otherwise falls through with schema undefined.
198
+ case "unknown":
199
+ n = i.Unknown;
200
+ break;
201
+ }
202
+ return e.required ? n.pipe(
203
+ i.annotations({
204
+ message: () => t("validation.empty")
205
+ })
206
+ ) : n = i.NullishOr(n), i.standardSchemaV1(n);
207
+ }, L = (e, t) => i.NullOr(e).pipe(
208
+ i.transform(i.typeSchema(e), {
209
+ decode: (n) => n ?? t(),
210
+ encode: (n) => n
211
+ })
212
+ );
213
+ export {
214
+ b as duplicateSchema,
215
+ O as generateInputStandardSchemaFromFieldMeta,
216
+ A as generateMetaFromSchema,
217
+ L as nullableInput
218
+ };
@@ -0,0 +1,7 @@
1
+ (function(){"use strict";try{if(typeof document<"u"){var n=document.createElement("style");if(n.appendChild(document.createTextNode("fieldset[data-v-0de09910]{display:contents}")),document.head.appendChild(n),window.customElements){const e=window.customElements.define;window.customElements.define=function(i,t){const d=t.prototype.connectedCallback;return t.prototype.connectedCallback=function(){if(d&&d.call(this),this.shadowRoot){const o=document.createElement("style");o.appendChild(document.createTextNode("fieldset[data-v-0de09910]{display:contents}")),this.shadowRoot.appendChild(o)}},e.call(window.customElements,i,t)}}}}catch(e){console.error("vite-plugin-css-injected-by-js",e)}})();
2
+ import o from "./vue-components.es11.js";
3
+ import m from "./vue-components.es12.js";
4
+ const a = /* @__PURE__ */ m(o, [["__scopeId", "data-v-0de09910"]]);
5
+ export {
6
+ a as default
7
+ };
@@ -0,0 +1,48 @@
1
+ import { defineComponent as i, computed as t, createBlock as p, openBlock as d, resolveDynamicComponent as u, withCtx as r, createVNode as f, mergeProps as c, renderSlot as v, normalizeProps as h, guardReactiveProps as g } from "vue";
2
+ import { generateInputStandardSchemaFromFieldMeta as y } from "./vue-components.es6.js";
3
+ import b from "./vue-components.es15.js";
4
+ const S = /* @__PURE__ */ i({
5
+ inheritAttrs: !1,
6
+ __name: "OmegaInput",
7
+ props: {
8
+ form: {},
9
+ name: {},
10
+ validators: {},
11
+ label: {},
12
+ options: {},
13
+ type: {}
14
+ },
15
+ setup(n) {
16
+ const o = n, a = t(() => o.form.meta[o.name]), m = t(() => {
17
+ if (!a.value)
18
+ throw new Error("Meta is undefined");
19
+ return y(a.value);
20
+ });
21
+ return (e, C) => (d(), p(u(e.form.Field), {
22
+ name: e.name,
23
+ validators: {
24
+ onChange: m.value,
25
+ ...e.validators
26
+ }
27
+ }, {
28
+ default: r(({ field: l }) => [
29
+ f(b, c({
30
+ field: l,
31
+ label: e.label,
32
+ options: e.options,
33
+ meta: a.value,
34
+ type: e.type
35
+ }, e.$attrs), {
36
+ default: r((s) => [
37
+ v(e.$slots, "default", h(g(s)))
38
+ ]),
39
+ _: 2
40
+ }, 1040, ["field", "label", "options", "meta", "type"])
41
+ ]),
42
+ _: 3
43
+ }, 8, ["name", "validators"]));
44
+ }
45
+ });
46
+ export {
47
+ S as default
48
+ };
@@ -0,0 +1,7 @@
1
+ (function(){"use strict";try{if(typeof document<"u"){var t=document.createElement("style");if(t.appendChild(document.createTextNode(".v-enter-from[data-v-fde7a2c8],.v-leave-to[data-v-fde7a2c8]{max-height:0px;grid-template-rows:0fr;opacity:0}.v-enter-active[data-v-fde7a2c8],.v-leave-active[data-v-fde7a2c8]{display:grid;transition:all .15s}.v-enter-to[data-v-fde7a2c8],.v-leave-from[data-v-fde7a2c8]{grid-template-rows:1fr;max-height:50vh;opacity:1}.error-alert[data-v-fde7a2c8]{transition-behavior:allow-discrete;display:grid;overflow:hidden;min-height:0}.error-alert>*[data-v-fde7a2c8]{min-height:0}.error-list[data-v-fde7a2c8]{container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;gap:.5em;align-items:start}@container (max-width: 28.125rem){.error-list[data-v-fde7a2c8]{grid-template-columns:auto 1fr}.error-link[data-v-fde7a2c8]{grid-column:1 / -1;justify-self:end}}@container (max-width: 18.75rem){.error-list[data-v-fde7a2c8]{grid-template-columns:1fr}.error-message[data-v-fde7a2c8]{grid-column:1 / -1}}.error-item[data-v-fde7a2c8]{display:contents}a[data-v-fde7a2c8]{min-width:min-content}.error-link[data-v-fde7a2c8]{align-items:center;color:inherit;display:inline-flex;flex-wrap:wrap;gap:.25em;padding-bottom:1em;text-decoration:none}")),document.head.appendChild(t),window.customElements){const e=window.customElements.define;window.customElements.define=function(d,a){const i=a.prototype.connectedCallback;return a.prototype.connectedCallback=function(){if(i&&i.call(this),this.shadowRoot){const r=document.createElement("style");r.appendChild(document.createTextNode(".v-enter-from[data-v-fde7a2c8],.v-leave-to[data-v-fde7a2c8]{max-height:0px;grid-template-rows:0fr;opacity:0}.v-enter-active[data-v-fde7a2c8],.v-leave-active[data-v-fde7a2c8]{display:grid;transition:all .15s}.v-enter-to[data-v-fde7a2c8],.v-leave-from[data-v-fde7a2c8]{grid-template-rows:1fr;max-height:50vh;opacity:1}.error-alert[data-v-fde7a2c8]{transition-behavior:allow-discrete;display:grid;overflow:hidden;min-height:0}.error-alert>*[data-v-fde7a2c8]{min-height:0}.error-list[data-v-fde7a2c8]{container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;gap:.5em;align-items:start}@container (max-width: 28.125rem){.error-list[data-v-fde7a2c8]{grid-template-columns:auto 1fr}.error-link[data-v-fde7a2c8]{grid-column:1 / -1;justify-self:end}}@container (max-width: 18.75rem){.error-list[data-v-fde7a2c8]{grid-template-columns:1fr}.error-message[data-v-fde7a2c8]{grid-column:1 / -1}}.error-item[data-v-fde7a2c8]{display:contents}a[data-v-fde7a2c8]{min-width:min-content}.error-link[data-v-fde7a2c8]{align-items:center;color:inherit;display:inline-flex;flex-wrap:wrap;gap:.25em;padding-bottom:1em;text-decoration:none}")),this.shadowRoot.appendChild(r)}},e.call(window.customElements,d,a)}}}}catch(e){console.error("vite-plugin-css-injected-by-js",e)}})();
2
+ import o from "./vue-components.es14.js";
3
+ import r from "./vue-components.es12.js";
4
+ const e = /* @__PURE__ */ r(o, [["__scopeId", "data-v-fde7a2c8"]]);
5
+ export {
6
+ e as default
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/vue-components",
3
- "version": "0.0.8",
3
+ "version": "0.1.0",
4
4
  "peerDependencies": {
5
5
  "@mdi/js": "^7.4.47",
6
6
  "@tanstack/vue-form": "^1.2.4",
@@ -15,11 +15,18 @@
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/node": "^22.13.14",
18
+ "@typescript-eslint/eslint-plugin": "8.29.0",
19
+ "@typescript-eslint/parser": "8.29.0",
18
20
  "@vitejs/plugin-vue": "^5.2.3",
21
+ "@vue/eslint-config-prettier": "^10.2.0",
22
+ "@vue/eslint-config-typescript": "^14.5.0",
23
+ "eslint-plugin-prettier": "^5.2.6",
24
+ "eslint-plugin-vue": "^10.0.0",
19
25
  "rimraf": "^6.0.1",
20
26
  "sass": "^1.86.0",
21
27
  "typescript": "^5.8.2",
22
28
  "vite": "^6.2.3",
29
+ "vite-plugin-css-injected-by-js": "^3.5.2",
23
30
  "vitepress": "^1.6.3",
24
31
  "vue-tsc": "^2.2.8"
25
32
  },
@@ -36,13 +43,15 @@
36
43
  "./dist/vue-components.css": "./dist/vue-components.css"
37
44
  },
38
45
  "dependencies": {
39
- "@effect-app/vue": "2.39.7",
40
- "effect-app": "2.38.3"
46
+ "@effect-app/vue": "2.39.8",
47
+ "effect-app": "2.38.4"
41
48
  },
42
49
  "scripts": {
43
50
  "build": "rimraf dist && vue-tsc && vite build",
44
51
  "docs:dev": "vitepress dev docs",
45
52
  "docs:build": "vitepress build docs",
46
- "docs:serve": "vitepress serve docs"
53
+ "docs:serve": "vitepress serve docs",
54
+ "lint": "NODE_OPTIONS=--max-old-space-size=8192 eslint src",
55
+ "autofix": "pnpm lint --fix"
47
56
  }
48
57
  }
@@ -0,0 +1,81 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import type { FieldApi, DeepValue, ValidationError } from "@tanstack/vue-form"
3
+ import { type NestedKeyOf } from "./OmegaFormStuff"
4
+
5
+ // Placeholder types for validator function shapes
6
+ type ValidatorFnSync = (opts: {
7
+ value: any
8
+ fieldApi: any
9
+ }) => ValidationError | undefined
10
+ type ValidatorFnAsync = (opts: {
11
+ value: any
12
+ fieldApi: any
13
+ }) => Promise<ValidationError | undefined>
14
+ // Assuming form validators have a similar structure but might operate on the whole form data (any for simplicity)
15
+ type FormValidatorFnSync = (opts: {
16
+ value: any
17
+ formApi: any
18
+ }) => ValidationError | undefined
19
+ type FormValidatorFnAsync = (opts: {
20
+ value: any
21
+ formApi: any
22
+ }) => Promise<ValidationError | undefined>
23
+ // Placeholder for other form-related types
24
+ type FormServerError = any
25
+ type SubmitMeta = any
26
+
27
+ // Define a more flexible Updater type that can accept direct values
28
+ type FlexibleUpdater<T> = ((prev: T) => T) | T
29
+
30
+ export type OmegaFieldInternalApi<To> = Omit<
31
+ FieldApi<
32
+ To, // TParentData
33
+ NestedKeyOf<To>, // TName
34
+ DeepValue<To, NestedKeyOf<To>>, // TData
35
+ // Field Validators (approximated typqes)
36
+ ValidatorFnSync, // TOnMount
37
+ ValidatorFnSync, // TOnChange
38
+ ValidatorFnAsync, // TOnChangeAsync
39
+ ValidatorFnSync, // TOnBlur
40
+ ValidatorFnAsync, // TOnBlurAsync
41
+ ValidatorFnSync, // TOnSubmit
42
+ ValidatorFnAsync, // TOnSubmitAsync
43
+ // Form Validators (approximated types)
44
+ FormValidatorFnSync, // TFormOnMount
45
+ FormValidatorFnSync, // TFormOnChange
46
+ FormValidatorFnAsync, // TFormOnChangeAsync
47
+ FormValidatorFnSync, // TFormOnBlur
48
+ FormValidatorFnAsync, // TFormOnBlurAsync
49
+ FormValidatorFnSync, // TFormOnSubmit
50
+ FormValidatorFnAsync, // TFormOnSubmitAsync
51
+ // Other Form types (placeholders)
52
+ FormServerError, // TFormOnServer
53
+ SubmitMeta // TParentSubmitMeta
54
+ >,
55
+ "handleChange" | "setValue"
56
+ > & {
57
+ handleChange: (
58
+ updater: FlexibleUpdater<DeepValue<To, NestedKeyOf<To>>> | any,
59
+ ) => void
60
+ setValue: (
61
+ updater: FlexibleUpdater<DeepValue<To, NestedKeyOf<To>>> | any,
62
+ ) => void
63
+ }
64
+
65
+ export type InputProps<T> = {
66
+ id: string
67
+ required?: boolean
68
+ minLength?: number | false
69
+ maxLength?: number | false
70
+ max?: number | false
71
+ min?: number | false
72
+ name: string
73
+ modelValue: unknown
74
+ errorMessages: string[]
75
+ error: boolean
76
+ field: OmegaFieldInternalApi<T>
77
+ setRealDirty: () => void
78
+ type: string
79
+ label: string
80
+ options?: { title: string; value: string }[]
81
+ }
@@ -1,32 +1,66 @@
1
1
  <template>
2
2
  <Transition>
3
- <div v-if="
4
- formSubmissionAttempts > 0 &&
5
- (errors.length || showedGeneralErrors.length)
6
- " class="error-alert">
7
- <v-alert type="error" variant="tonal" role="alert" aria-live="polite" class="mb-4">
8
- <div class="text-h6 mb-3">{{ trans("form.includes_error") }}:</div>
9
- <component :is="errors.length > 1 ? 'ul' : 'div'" v-if="errors.length" class="error-list">
10
- <component :is="errors.length > 1 ? 'li' : 'div'" v-for="error in errors" :key="error.inputId"
11
- class="error-item">
12
- <div class="font-weight-medium">{{ error.label }}</div>
13
- <div class="error-message">
14
- <component :is="error.errors.length > 1 ? 'ul' : 'div'" class="error-list">
15
- <component :is="error.errors.length > 1 ? 'li' : 'span'" v-for="e in error.errors" :key="e">
16
- {{ e }}
3
+ <div
4
+ v-if="
5
+ formSubmissionAttempts > 0 &&
6
+ (errors.length || showedGeneralErrors.length)
7
+ "
8
+ class="error-alert"
9
+ >
10
+ <slot v-bind="{ errors, showedGeneralErrors }">
11
+ <component
12
+ :is="vuetified ? 'v-alert' : 'div'"
13
+ :class="vuetified ? 'mb-4' : 'error-alert-content'"
14
+ type="error"
15
+ variant="tonal"
16
+ role="alert"
17
+ aria-live="polite"
18
+ class="mb-4"
19
+ >
20
+ <div class="text-h6 mb-3">{{ trans("form.includes_error") }}:</div>
21
+ <component
22
+ :is="errors.length > 1 ? 'ul' : 'div'"
23
+ v-if="errors.length"
24
+ class="error-list"
25
+ >
26
+ <component
27
+ :is="errors.length > 1 ? 'li' : 'div'"
28
+ v-for="error in errors"
29
+ :key="error.inputId"
30
+ class="error-item"
31
+ >
32
+ <div class="font-weight-medium">{{ error.label }}</div>
33
+ <div class="error-message">
34
+ <component
35
+ :is="error.errors.length > 1 ? 'ul' : 'div'"
36
+ class="error-list"
37
+ >
38
+ <component
39
+ :is="error.errors.length > 1 ? 'li' : 'span'"
40
+ v-for="e in error.errors"
41
+ :key="e"
42
+ >
43
+ {{ e }}
44
+ </component>
17
45
  </component>
18
- </component>
19
- </div>
20
- <a :href="`#${error.inputId}`" class="error-link">
21
- <v-icon :icon="mdiLink" />
22
- {{ trans("form.fix_input") }}
23
- </a>
46
+ </div>
47
+ <a :href="`#${error.inputId}`" class="error-link">
48
+ <component
49
+ :is="vuetified ? 'v-icon' : 'i'"
50
+ :icon="mdiLink"
51
+ aria-hidden="true"
52
+ >
53
+ <i>&#128279;</i>
54
+ </component>
55
+ {{ trans("form.fix_input") }}
56
+ </a>
57
+ </component>
24
58
  </component>
59
+ <span v-else>
60
+ {{ showedGeneralErrors[0] }}
61
+ </span>
25
62
  </component>
26
- <span v-else>
27
- {{ showedGeneralErrors[0] }}
28
- </span>
29
- </v-alert>
63
+ </slot>
30
64
  </div>
31
65
  </Transition>
32
66
  </template>
@@ -36,7 +70,10 @@ import { useOmegaErrors } from "./OmegaErrorsContext"
36
70
  import { mdiLink } from "@mdi/js"
37
71
  import { useIntl } from "../../utils"
38
72
  import type { StandardSchemaV1Issue } from "@tanstack/vue-form"
39
- import { computed } from "vue"
73
+ import { computed, getCurrentInstance } from "vue"
74
+
75
+ const instance = getCurrentInstance()
76
+ const vuetified = instance?.appContext.components["VAlert"]
40
77
 
41
78
  const { errors, formSubmissionAttempts, generalErrors } = useOmegaErrors()
42
79
 
@@ -91,7 +128,7 @@ const showedGeneralErrors = computed(() => {
91
128
  overflow: hidden;
92
129
  min-height: 0;
93
130
 
94
- >* {
131
+ > * {
95
132
  min-height: 0;
96
133
  }
97
134
  }
@@ -100,7 +137,7 @@ const showedGeneralErrors = computed(() => {
100
137
  container-type: inline-size;
101
138
  display: grid;
102
139
  grid-template-columns: auto 1fr auto;
103
- gap: 8px;
140
+ gap: 0.5em;
104
141
  align-items: start;
105
142
  }
106
143
 
@@ -112,7 +149,6 @@ const showedGeneralErrors = computed(() => {
112
149
  .error-link {
113
150
  grid-column: 1 / -1;
114
151
  justify-self: end;
115
- padding-bottom: 16px;
116
152
  }
117
153
  }
118
154
 
@@ -135,9 +171,12 @@ a {
135
171
  }
136
172
 
137
173
  .error-link {
174
+ align-items: center;
138
175
  color: inherit;
139
- text-decoration: none;
140
176
  display: inline-flex;
141
- align-items: center;
177
+ flex-wrap: wrap;
178
+ gap: 0.25em;
179
+ padding-bottom: 1em;
180
+ text-decoration: none;
142
181
  }
143
182
  </style>
@@ -23,6 +23,8 @@ export type TypeOverride =
23
23
  | "select"
24
24
  | "multiple"
25
25
  | "boolean"
26
+ | "autocomplete"
27
+ | "autocompletemultiple"
26
28
 
27
29
  export interface OmegaError {
28
30
  label: string
@@ -1,38 +1,25 @@
1
1
  <template>
2
- <component :is="form.Field" :name="name" :validators="{
3
- onChange: schema,
4
- ...validators,
5
- }">
6
- <template #default="{
7
- field,
8
- }: {
9
- // TODO: exact type
10
- field: FieldApi<
11
- any,
12
- any,
13
- any,
14
- any,
15
- any,
16
- any,
17
- any,
18
- any,
19
- any,
20
- any,
21
- any,
22
- any,
23
- any,
24
- any,
25
- any,
26
- any,
27
- any,
28
- any,
29
- any
2
+ <component
3
+ :is="form.Field"
4
+ :name="name"
5
+ :validators="{
6
+ onChange: schema,
7
+ ...validators,
8
+ }"
9
+ >
10
+ <template #default="{ field }: { field: OmegaFieldInternalApi<To> }">
11
+ <OmegaInternalInput
12
+ :field="field"
13
+ :label="label"
14
+ :options="options"
15
+ :meta="meta"
16
+ :type="type"
17
+ v-bind="$attrs"
30
18
  >
31
- }">
32
- <slot :field="field" :label="label" :options="options" :meta="meta" :type="type">
33
- <OmegaInternalInput v-bind="$attrs" :field="field" :label="label" :options="options" :meta="meta"
34
- :type="type" />
35
- </slot>
19
+ <template #default="inputProps">
20
+ <slot v-bind="inputProps" />
21
+ </template>
22
+ </OmegaInternalInput>
36
23
  </template>
37
24
  </component>
38
25
  </template>
@@ -48,11 +35,7 @@ import {
48
35
  type TypeOverride,
49
36
  } from "./OmegaFormStuff"
50
37
  import OmegaInternalInput from "./OmegaInternalInput.vue"
51
- import type { FieldApi } from "@tanstack/vue-form"
52
-
53
- defineOptions({
54
- inheritAttrs: false
55
- })
38
+ import type { OmegaFieldInternalApi } from "./InputProps"
56
39
 
57
40
  const props = defineProps<{
58
41
  form: FormType<From, To> & {
@@ -65,6 +48,10 @@ const props = defineProps<{
65
48
  type?: TypeOverride
66
49
  }>()
67
50
 
51
+ defineOptions({
52
+ inheritAttrs: false,
53
+ })
54
+
68
55
  const meta = computed(() => {
69
56
  return props.form.meta[props.name]
70
57
  })