@effect-app/vue-components 4.0.0-beta.314 → 4.0.0-beta.315

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.
@@ -9,6 +9,7 @@ export type InputProps<From extends Record<PropertyKey, any>, TName extends Deep
9
9
  maxLength?: number | false;
10
10
  max?: number | false;
11
11
  min?: number | false;
12
+ refinement?: "int";
12
13
  errorMessages: string[];
13
14
  error: boolean;
14
15
  label: string;
@@ -57,6 +57,12 @@ declare const __VLS_export: <From extends Record<PropertyKey, any>, Name extends
57
57
  id: string;
58
58
  label: string;
59
59
  }) => any;
60
+ } & {
61
+ label?: (props: {
62
+ required: boolean | undefined;
63
+ id: string;
64
+ label: string;
65
+ }) => any;
60
66
  };
61
67
  emit: {
62
68
  (e: "focus", event: Event): void;
@@ -37,6 +37,7 @@ declare const __VLS_export: <From extends Record<PropertyKey, any>, Name extends
37
37
  maxLength?: number | false;
38
38
  max?: number | false;
39
39
  min?: number | false;
40
+ refinement?: "int";
40
41
  errorMessages: string[];
41
42
  error: boolean;
42
43
  label: string;
@@ -31,20 +31,30 @@ var t = (e) => {
31
31
  }
32
32
  case "isGreaterThanOrEqualTo": return r(a.minimum === 0 ? "validation.number.positive" : "validation.number.min", {
33
33
  minimum: a.minimum,
34
- isExclusive: !0
34
+ isExclusive: !1
35
35
  });
36
36
  case "isGreaterThan": return r(a.exclusiveMinimum === 0 ? "validation.number.positive" : "validation.number.min", {
37
37
  minimum: a.exclusiveMinimum,
38
- isExclusive: !1
38
+ isExclusive: !0
39
39
  });
40
40
  case "isLessThanOrEqualTo": return r("validation.number.max", {
41
41
  maximum: a.maximum,
42
- isExclusive: !0
42
+ isExclusive: !1
43
43
  });
44
44
  case "isLessThan": return r("validation.number.max", {
45
45
  maximum: a.exclusiveMaximum,
46
- isExclusive: !1
46
+ isExclusive: !0
47
47
  });
48
+ case "isBetween": {
49
+ let e = n(i);
50
+ return typeof e == "number" && e < a.minimum ? r("validation.number.min", {
51
+ minimum: a.minimum,
52
+ isExclusive: !1
53
+ }) : r("validation.number.max", {
54
+ maximum: a.maximum,
55
+ isExclusive: !1
56
+ });
57
+ }
48
58
  default: return e.SchemaIssue.defaultCheckHook(i);
49
59
  }
50
60
  }
@@ -16,13 +16,13 @@ var b = /*@__PURE__*/ c({
16
16
  return v(() => {
17
17
  x.value && console.warn(`[OmegaForm] Unhandled input type "${b.inputProps.type}", falling back to a text input.`);
18
18
  }), (t, r) => {
19
- let v = h("v-text-field"), b = h("v-textarea"), S = h("v-radio"), C = h("v-radio-group"), w = h("v-select"), T = h("v-autocomplete");
19
+ let v = h("v-text-field"), b = h("v-textarea"), S = h("v-number-input"), C = h("v-slider"), w = h("v-radio"), T = h("v-radio-group"), E = h("v-select"), D = h("v-autocomplete");
20
20
  return f(), o("div", {
21
21
  class: "omega-input",
22
- onFocusout: r[8] ||= (e) => {
22
+ onFocusout: r[9] ||= (e) => {
23
23
  t.$emit("blur", e), c.field.handleBlur();
24
24
  },
25
- onFocusin: r[9] ||= (e) => t.$emit("focus", e)
25
+ onFocusin: r[10] ||= (e) => t.$emit("focus", e)
26
26
  }, [
27
27
  c.inputProps.type === "boolean" || c.inputProps.type === "switch" ? (f(), i(g(c.inputProps.type === "boolean" ? "v-checkbox" : "v-switch"), u({
28
28
  key: 0,
@@ -117,20 +117,57 @@ var b = /*@__PURE__*/ c({
117
117
  "error",
118
118
  "model-value"
119
119
  ])) : a("", !0),
120
- c.inputProps.type === "number" || c.inputProps.type === "range" ? (f(), i(g(c.inputProps.type === "range" ? "v-slider" : "v-text-field"), u({
120
+ c.inputProps.type === "number" ? (f(), i(S, u({
121
121
  key: 3,
122
122
  id: c.inputProps.id,
123
123
  required: c.inputProps.required,
124
- min: c.inputProps.min,
125
- max: c.inputProps.max,
126
- type: c.inputProps.type,
124
+ role: "spinbutton",
125
+ "aria-valuemin": typeof c.inputProps.min == "number" ? c.inputProps.min : void 0,
126
+ "aria-valuemax": typeof c.inputProps.max == "number" ? c.inputProps.max : void 0,
127
+ "aria-valuenow": typeof c.state.value == "number" ? c.state.value : void 0,
128
+ name: c.field.name,
129
+ label: c.inputProps.label,
130
+ "error-messages": c.inputProps.errorMessages,
131
+ error: c.inputProps.error,
132
+ precision: c.inputProps.refinement === "int" ? 0 : null,
133
+ "control-variant": "stacked"
134
+ }, t.$attrs, {
135
+ "model-value": c.state.value,
136
+ "onUpdate:modelValue": r[3] ||= (e) => c.field.handleChange(e ?? void 0)
137
+ }), s({ _: 2 }, [t.$slots.label ? {
138
+ name: "label",
139
+ fn: y(() => [m(t.$slots, "label", d(l({
140
+ required: c.inputProps.required,
141
+ id: c.inputProps.id,
142
+ label: c.inputProps.label
143
+ })))]),
144
+ key: "0"
145
+ } : void 0]), 1040, [
146
+ "id",
147
+ "required",
148
+ "aria-valuemin",
149
+ "aria-valuemax",
150
+ "aria-valuenow",
151
+ "name",
152
+ "label",
153
+ "error-messages",
154
+ "error",
155
+ "precision",
156
+ "model-value"
157
+ ])) : a("", !0),
158
+ c.inputProps.type === "range" ? (f(), i(C, u({
159
+ key: 4,
160
+ id: c.inputProps.id,
161
+ required: c.inputProps.required,
162
+ min: typeof c.inputProps.min == "number" ? c.inputProps.min : void 0,
163
+ max: typeof c.inputProps.max == "number" ? c.inputProps.max : void 0,
127
164
  name: c.field.name,
128
165
  label: c.inputProps.label,
129
166
  "error-messages": c.inputProps.errorMessages,
130
167
  error: c.inputProps.error
131
168
  }, t.$attrs, {
132
169
  "model-value": c.state.value,
133
- "onUpdate:modelValue": r[3] ||= (e) => {
170
+ "onUpdate:modelValue": r[4] ||= (e) => {
134
171
  e || e === 0 ? c.field.handleChange(Number(e)) : c.field.handleChange(void 0);
135
172
  }
136
173
  }), s({ _: 2 }, [t.$slots.label ? {
@@ -146,15 +183,14 @@ var b = /*@__PURE__*/ c({
146
183
  "required",
147
184
  "min",
148
185
  "max",
149
- "type",
150
186
  "name",
151
187
  "label",
152
188
  "error-messages",
153
189
  "error",
154
190
  "model-value"
155
191
  ])) : a("", !0),
156
- c.inputProps.type === "radio" ? (f(), i(C, u({
157
- key: 4,
192
+ c.inputProps.type === "radio" ? (f(), i(T, u({
193
+ key: 5,
158
194
  id: c.inputProps.id,
159
195
  name: c.field.name,
160
196
  label: c.inputProps.label,
@@ -162,9 +198,9 @@ var b = /*@__PURE__*/ c({
162
198
  error: c.inputProps.error
163
199
  }, t.$attrs, {
164
200
  "model-value": c.state.value,
165
- "onUpdate:modelValue": r[4] ||= (e) => c.field.handleChange(e)
201
+ "onUpdate:modelValue": r[5] ||= (e) => c.field.handleChange(e)
166
202
  }), s({
167
- default: y(() => [(f(!0), o(n, null, p(c.inputProps.options, (e) => (f(), i(S, {
203
+ default: y(() => [(f(!0), o(n, null, p(c.inputProps.options, (e) => (f(), i(w, {
168
204
  key: e.value,
169
205
  label: e.title,
170
206
  value: e.value
@@ -186,8 +222,8 @@ var b = /*@__PURE__*/ c({
186
222
  "error",
187
223
  "model-value"
188
224
  ])) : a("", !0),
189
- c.inputProps.type === "select" || c.inputProps.type === "multiple" ? (f(), i(w, u({
190
- key: 5,
225
+ c.inputProps.type === "select" || c.inputProps.type === "multiple" ? (f(), i(E, u({
226
+ key: 6,
191
227
  id: c.inputProps.id,
192
228
  clearable: c.inputProps.type === "select",
193
229
  required: c.inputProps.required,
@@ -200,7 +236,7 @@ var b = /*@__PURE__*/ c({
200
236
  error: c.inputProps.error
201
237
  }, t.$attrs, {
202
238
  "model-value": c.state.value,
203
- onClear: r[5] ||= (e) => c.field.handleChange(void 0),
239
+ onClear: r[6] ||= (e) => c.field.handleChange(void 0),
204
240
  "onUpdate:modelValue": c.field.handleChange
205
241
  }), s({ _: 2 }, [t.$slots.label ? {
206
242
  name: "label",
@@ -224,8 +260,8 @@ var b = /*@__PURE__*/ c({
224
260
  "model-value",
225
261
  "onUpdate:modelValue"
226
262
  ])) : a("", !0),
227
- c.inputProps.type === "autocomplete" || c.inputProps.type === "autocompletemultiple" ? (f(), i(T, u({
228
- key: 6,
263
+ c.inputProps.type === "autocomplete" || c.inputProps.type === "autocompletemultiple" ? (f(), i(D, u({
264
+ key: 7,
229
265
  id: c.inputProps.id,
230
266
  clearable: c.inputProps.type === "autocomplete",
231
267
  multiple: c.inputProps.type === "autocompletemultiple",
@@ -238,7 +274,7 @@ var b = /*@__PURE__*/ c({
238
274
  chips: c.inputProps.type === "autocompletemultiple"
239
275
  }, t.$attrs, {
240
276
  "model-value": c.state.value,
241
- onClear: r[6] ||= (e) => c.field.handleChange(void 0),
277
+ onClear: r[7] ||= (e) => c.field.handleChange(void 0),
242
278
  "onUpdate:modelValue": c.field.handleChange
243
279
  }), s({ _: 2 }, [t.$slots.label ? {
244
280
  name: "label",
@@ -263,7 +299,7 @@ var b = /*@__PURE__*/ c({
263
299
  "onUpdate:modelValue"
264
300
  ])) : a("", !0),
265
301
  x.value ? (f(), i(v, u({
266
- key: 7,
302
+ key: 8,
267
303
  id: c.inputProps.id,
268
304
  required: c.inputProps.required,
269
305
  type: _(e)(c.inputProps.type),
@@ -273,7 +309,7 @@ var b = /*@__PURE__*/ c({
273
309
  error: c.inputProps.error
274
310
  }, t.$attrs, {
275
311
  "model-value": c.state.value,
276
- "onUpdate:modelValue": r[7] ||= (e) => c.field.handleChange(e)
312
+ "onUpdate:modelValue": r[8] ||= (e) => c.field.handleChange(e)
277
313
  }), s({ _: 2 }, [t.$slots.label ? {
278
314
  name: "label",
279
315
  fn: y(() => [m(t.$slots, "label", d(l({
@@ -44,6 +44,7 @@ var b = /*@__PURE__*/ o({
44
44
  maxLength: b.meta?.type === "string" && b.meta?.maxLength,
45
45
  max: b.meta?.type === "number" ? b.meta?.maximum ?? (typeof b.meta?.exclusiveMaximum == "number" ? b.meta.exclusiveMaximum - 1 : void 0) : void 0,
46
46
  min: b.meta?.type === "number" ? b.meta?.minimum ?? (typeof b.meta?.exclusiveMinimum == "number" ? b.meta.exclusiveMinimum + 1 : void 0) : void 0,
47
+ refinement: b.meta?.type === "number" ? b.meta?.refinement : void 0,
47
48
  errorMessages: N.value,
48
49
  error: !!N.value.length,
49
50
  type: A.value,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/vue-components",
3
- "version": "4.0.0-beta.314",
3
+ "version": "4.0.0-beta.315",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/effect-app/libs.git",
@@ -62,8 +62,8 @@
62
62
  "highlight.js": "^11.11.1",
63
63
  "mitt": "^3.0.1",
64
64
  "vue3-highlightjs": "^1.0.5",
65
- "@effect-app/vue": "4.0.0-beta.314",
66
- "effect-app": "4.0.0-beta.314"
65
+ "@effect-app/vue": "4.0.0-beta.315",
66
+ "effect-app": "4.0.0-beta.315"
67
67
  },
68
68
  "scripts": {
69
69
  "check": "vue-tsc",
@@ -36,6 +36,7 @@ export type InputProps<From extends Record<PropertyKey, any>, TName extends Deep
36
36
  maxLength?: number | false
37
37
  max?: number | false
38
38
  min?: number | false
39
+ refinement?: "int"
39
40
  errorMessages: string[]
40
41
  error: boolean
41
42
  label: string
@@ -87,20 +87,51 @@
87
87
  />
88
88
  </template>
89
89
  </v-textarea>
90
- <component
91
- :is="inputProps.type === 'range' ? 'v-slider' : 'v-text-field'"
92
- v-if="inputProps.type === 'number' || inputProps.type === 'range'"
90
+ <!-- min/max are deliberately NOT passed as VNumberInput props: the component
91
+ silently withholds out-of-range values from the model (so schema errors
92
+ would never show) and clamps on blur. Validation stays schema-driven; the
93
+ bounds are exposed to AT via the spinbutton ARIA attrs, which fall through
94
+ to the native input. -->
95
+ <v-number-input
96
+ v-if="inputProps.type === 'number'"
93
97
  :id="inputProps.id"
94
98
  :required="inputProps.required"
95
- :min="inputProps.min"
96
- :max="inputProps.max"
97
- :type="inputProps.type"
99
+ role="spinbutton"
100
+ :aria-valuemin="typeof inputProps.min === 'number' ? inputProps.min : undefined"
101
+ :aria-valuemax="typeof inputProps.max === 'number' ? inputProps.max : undefined"
102
+ :aria-valuenow="typeof state.value === 'number' ? state.value : undefined"
98
103
  :name="field.name"
99
104
  :label="inputProps.label"
100
105
  :error-messages="inputProps.errorMessages"
101
106
  :error="inputProps.error"
107
+ :precision="inputProps.refinement === 'int' ? 0 : null"
108
+ control-variant="stacked"
102
109
  v-bind="$attrs"
103
- :model-value="state.value"
110
+ :model-value="state.value as any"
111
+ @update:model-value="(v: number | null) => field.handleChange((v ?? undefined) as any)"
112
+ >
113
+ <template
114
+ v-if="$slots.label"
115
+ #label
116
+ >
117
+ <slot
118
+ name="label"
119
+ v-bind="{ required: inputProps.required, id: inputProps.id, label: inputProps.label }"
120
+ />
121
+ </template>
122
+ </v-number-input>
123
+ <v-slider
124
+ v-if="inputProps.type === 'range'"
125
+ :id="inputProps.id"
126
+ :required="inputProps.required"
127
+ :min="typeof inputProps.min === 'number' ? inputProps.min : undefined"
128
+ :max="typeof inputProps.max === 'number' ? inputProps.max : undefined"
129
+ :name="field.name"
130
+ :label="inputProps.label"
131
+ :error-messages="inputProps.errorMessages"
132
+ :error="inputProps.error"
133
+ v-bind="$attrs"
134
+ :model-value="state.value as any"
104
135
  @update:model-value="(e: any) => {
105
136
  if (e || e === 0) {
106
137
  field.handleChange(Number(e) as any)
@@ -118,7 +149,7 @@
118
149
  v-bind="{ required: inputProps.required, id: inputProps.id, label: inputProps.label }"
119
150
  />
120
151
  </template>
121
- </component>
152
+ </v-slider>
122
153
  <template v-if="inputProps.type === 'radio'">
123
154
  <v-radio-group
124
155
  :id="inputProps.id"
@@ -191,6 +191,7 @@ const inputProps: ComputedRef<InputProps<From, Name>> = computed(() => ({
191
191
  ? (props.meta?.minimum
192
192
  ?? (typeof props.meta?.exclusiveMinimum === "number" ? props.meta.exclusiveMinimum + 1 : undefined))
193
193
  : undefined,
194
+ refinement: props.meta?.type === "number" ? props.meta?.refinement : undefined,
194
195
  errorMessages: errors.value,
195
196
  error: !!errors.value.length,
196
197
  type: fieldType.value,
@@ -13,6 +13,7 @@ type FilterMeta =
13
13
  | { readonly _tag: "isGreaterThan"; readonly exclusiveMinimum: number }
14
14
  | { readonly _tag: "isLessThanOrEqualTo"; readonly maximum: number }
15
15
  | { readonly _tag: "isLessThan"; readonly exclusiveMaximum: number }
16
+ | { readonly _tag: "isBetween"; readonly minimum: number; readonly maximum: number }
16
17
  | { readonly _tag?: undefined }
17
18
 
18
19
  /** Map filter annotations (representation since beta.107, legacy meta before) to FilterMeta. */
@@ -85,20 +86,30 @@ export const makeStandardSchemaV1Hooks = (
85
86
  const actual = input !== undefined ? String(input) : "NaN"
86
87
  return trans("validation.integer.expected", { actualValue: actual })
87
88
  }
89
+ // isExclusive semantics in the message catalog: true = strict bound
90
+ // ("greater/less than"), false = inclusive bound ("at least/at most").
88
91
  case "isGreaterThanOrEqualTo":
89
92
  return trans(
90
93
  meta.minimum === 0 ? "validation.number.positive" : "validation.number.min",
91
- { minimum: meta.minimum, isExclusive: true }
94
+ { minimum: meta.minimum, isExclusive: false }
92
95
  )
93
96
  case "isGreaterThan":
94
97
  return trans(
95
98
  meta.exclusiveMinimum === 0 ? "validation.number.positive" : "validation.number.min",
96
- { minimum: meta.exclusiveMinimum, isExclusive: false }
99
+ { minimum: meta.exclusiveMinimum, isExclusive: true }
97
100
  )
98
101
  case "isLessThanOrEqualTo":
99
- return trans("validation.number.max", { maximum: meta.maximum, isExclusive: true })
102
+ return trans("validation.number.max", { maximum: meta.maximum, isExclusive: false })
100
103
  case "isLessThan":
101
- return trans("validation.number.max", { maximum: meta.exclusiveMaximum, isExclusive: false })
104
+ return trans("validation.number.max", { maximum: meta.exclusiveMaximum, isExclusive: true })
105
+ case "isBetween": {
106
+ // Inclusive on both ends; report the side the value actually violated.
107
+ const input = reportedInput(issue)
108
+ const below = typeof input === "number" && input < meta.minimum
109
+ return below
110
+ ? trans("validation.number.min", { minimum: meta.minimum, isExclusive: false })
111
+ : trans("validation.number.max", { maximum: meta.maximum, isExclusive: false })
112
+ }
102
113
  default:
103
114
  // Fall back to the default check hook so custom S.makeFilter messages
104
115
  // (which surface as InvalidValue.annotations.message on issue.issue)