@narrative.io/jsonforms-provider-protocols 3.0.0-beta.1 → 3.0.0-beta.3
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.
- package/dist/vue/composables/useDirtyValidation.d.ts +9 -0
- package/dist/vue/composables/useDirtyValidation.d.ts.map +1 -0
- package/dist/vue/composables/useDirtyValidation.js +15 -0
- package/dist/vue/composables/useDirtyValidation.js.map +1 -0
- package/dist/vue/composables/useProjection.d.ts +6 -0
- package/dist/vue/composables/useProjection.d.ts.map +1 -1
- package/dist/vue/composables/useProjection.js +56 -3
- package/dist/vue/composables/useProjection.js.map +1 -1
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.js +2 -0
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/primevue/JfBoolean.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfBoolean.vue.js +13 -7
- package/dist/vue/primevue/JfBoolean.vue.js.map +1 -1
- package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfEnum.vue.js +10 -13
- package/dist/vue/primevue/JfEnum.vue.js.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.js +13 -8
- package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
- package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfNumber.vue.js +11 -14
- package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
- package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfText.vue.js +18 -22
- package/dist/vue/primevue/JfText.vue.js.map +1 -1
- package/dist/vue/primevue/JfTextArea.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfTextArea.vue.js +14 -10
- package/dist/vue/primevue/JfTextArea.vue.js.map +1 -1
- package/package.json +3 -1
- package/src/vue/composables/useDirtyValidation.ts +20 -0
- package/src/vue/composables/useProjection.ts +114 -1
- package/src/vue/index.ts +1 -0
- package/src/vue/primevue/JfBoolean.vue +13 -5
- package/src/vue/primevue/JfEnum.vue +11 -16
- package/src/vue/primevue/JfEnumArray.vue +15 -8
- package/src/vue/primevue/JfNumber.vue +12 -17
- package/src/vue/primevue/JfText.vue +16 -21
- package/src/vue/primevue/JfTextArea.vue +16 -12
|
@@ -42,10 +42,11 @@ export default {
|
|
|
42
42
|
import type { JsonSchema } from "@jsonforms/core";
|
|
43
43
|
import type { ControlProps } from "@jsonforms/vue";
|
|
44
44
|
import { useJsonFormsControl } from "@jsonforms/vue";
|
|
45
|
-
import { computed,
|
|
45
|
+
import { computed, inject, getCurrentInstance, watch } from "vue";
|
|
46
46
|
import { useProvider } from "../composables/useProvider";
|
|
47
47
|
import { useDerive } from "../composables/useDerive";
|
|
48
48
|
import { useProjection } from "../composables/useProjection";
|
|
49
|
+
import { useDirtyValidation } from "../composables/useDirtyValidation";
|
|
49
50
|
import { shouldAutoSelect } from "../utils/autoSelect";
|
|
50
51
|
import Dropdown from "primevue/dropdown";
|
|
51
52
|
|
|
@@ -53,7 +54,7 @@ import Dropdown from "primevue/dropdown";
|
|
|
53
54
|
const instance = getCurrentInstance()!;
|
|
54
55
|
const props = instance.props as unknown as ControlProps;
|
|
55
56
|
const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
|
|
56
|
-
const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
|
|
57
|
+
const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
|
|
57
58
|
|
|
58
59
|
type Opt = { label: string; value: unknown };
|
|
59
60
|
const toOptions = (schema?: JsonSchema): Opt[] => {
|
|
@@ -160,44 +161,38 @@ watch(
|
|
|
160
161
|
{ immediate: true }
|
|
161
162
|
);
|
|
162
163
|
|
|
163
|
-
// Track user interaction
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
const showErrors = computed(() => hasInteracted.value && control.value.errors);
|
|
164
|
+
// Track user interaction — errors only show after blur
|
|
165
|
+
const { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);
|
|
167
166
|
|
|
168
167
|
const onSelect = (val: unknown) => {
|
|
169
168
|
handleChange(control.value.path, val);
|
|
170
169
|
};
|
|
171
|
-
|
|
172
|
-
const onBlur = () => {
|
|
173
|
-
hasInteracted.value = true;
|
|
174
|
-
};
|
|
175
170
|
</script>
|
|
176
171
|
|
|
177
172
|
<template>
|
|
178
173
|
<div class="flex flex-column gap-2">
|
|
179
|
-
<label v-if="
|
|
180
|
-
|
|
174
|
+
<label v-if="projectedLabel" class="text-color text-left">{{
|
|
175
|
+
projectedLabel
|
|
181
176
|
}}</label>
|
|
182
177
|
<div v-if="control.description" class="text-color-secondary text-left">
|
|
183
178
|
{{ control.description }}
|
|
184
179
|
</div>
|
|
185
180
|
<Dropdown
|
|
186
|
-
class="w-full"
|
|
181
|
+
:class="['w-full', { 'p-invalid': showErrors }]"
|
|
187
182
|
:options="options"
|
|
188
183
|
option-label="label"
|
|
189
184
|
option-value="value"
|
|
190
185
|
:model-value="projectedData ?? null"
|
|
191
186
|
:placeholder="placeholder"
|
|
192
187
|
:disabled="!control.enabled || loading"
|
|
193
|
-
:aria-invalid="
|
|
188
|
+
:aria-invalid="showErrors || undefined"
|
|
194
189
|
:show-clear="true"
|
|
195
190
|
@update:model-value="onSelect"
|
|
196
|
-
@blur="
|
|
191
|
+
@blur="markDirty"
|
|
197
192
|
/>
|
|
198
193
|
<small v-if="error" class="p-error" role="alert"
|
|
199
194
|
>Failed to load: {{ error }}</small
|
|
200
195
|
>
|
|
201
|
-
<small v-else-if="showErrors" class="p-error">{{
|
|
196
|
+
<small v-else-if="showErrors" class="p-error">{{ projectedErrors }}</small>
|
|
202
197
|
</div>
|
|
203
198
|
</template>
|
|
@@ -45,6 +45,7 @@ import { computed, inject, getCurrentInstance, watch } from "vue";
|
|
|
45
45
|
import { useProvider } from "../composables/useProvider";
|
|
46
46
|
import { useDerive } from "../composables/useDerive";
|
|
47
47
|
import { useProjection } from "../composables/useProjection";
|
|
48
|
+
import { useDirtyValidation } from "../composables/useDirtyValidation";
|
|
48
49
|
import { shouldAutoSelectMulti } from "../utils/autoSelect";
|
|
49
50
|
import MultiSelect from "primevue/multiselect";
|
|
50
51
|
|
|
@@ -52,7 +53,7 @@ import MultiSelect from "primevue/multiselect";
|
|
|
52
53
|
const instance = getCurrentInstance()!;
|
|
53
54
|
const props = instance.props as unknown as ControlProps;
|
|
54
55
|
const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
|
|
55
|
-
const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
|
|
56
|
+
const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
|
|
56
57
|
|
|
57
58
|
type Opt = { label: string; value: unknown };
|
|
58
59
|
const toOptions = (schema?: JsonSchema): Opt[] => {
|
|
@@ -132,6 +133,9 @@ const options = computed(() => {
|
|
|
132
133
|
// Add derive functionality
|
|
133
134
|
useDerive({ control, handleChange, data: projectedData });
|
|
134
135
|
|
|
136
|
+
// Track user interaction — errors only show after first change
|
|
137
|
+
const { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);
|
|
138
|
+
|
|
135
139
|
// Auto-select when provider returns only one item (opt-in for multiselect)
|
|
136
140
|
watch(
|
|
137
141
|
[providerItems, loading],
|
|
@@ -177,15 +181,18 @@ const model = computed<unknown[]>({
|
|
|
177
181
|
set(val) {
|
|
178
182
|
const next = Array.isArray(val) ? [...val] : [];
|
|
179
183
|
const curr = Array.isArray(projectedData.value) ? projectedData.value : [];
|
|
180
|
-
if (!sameSet(curr, next))
|
|
184
|
+
if (!sameSet(curr, next)) {
|
|
185
|
+
markDirty();
|
|
186
|
+
handleChange(control.value.path, next);
|
|
187
|
+
}
|
|
181
188
|
},
|
|
182
189
|
});
|
|
183
190
|
</script>
|
|
184
191
|
|
|
185
192
|
<template>
|
|
186
193
|
<div class="flex flex-column gap-2">
|
|
187
|
-
<label v-if="
|
|
188
|
-
|
|
194
|
+
<label v-if="projectedLabel" class="text-color text-left">{{
|
|
195
|
+
projectedLabel
|
|
189
196
|
}}</label>
|
|
190
197
|
<div v-if="control.description" class="text-color-secondary text-left">
|
|
191
198
|
{{ control.description }}
|
|
@@ -193,22 +200,22 @@ const model = computed<unknown[]>({
|
|
|
193
200
|
|
|
194
201
|
<MultiSelect
|
|
195
202
|
v-model="model"
|
|
196
|
-
class="w-full"
|
|
203
|
+
:class="['w-full', { 'p-invalid': showErrors }]"
|
|
197
204
|
:options="options"
|
|
198
205
|
option-label="label"
|
|
199
206
|
option-value="value"
|
|
200
207
|
data-key="value"
|
|
201
208
|
display="chip"
|
|
202
209
|
:disabled="!control.enabled || loading"
|
|
203
|
-
:aria-invalid="
|
|
210
|
+
:aria-invalid="showErrors || undefined"
|
|
204
211
|
:placeholder="placeholder"
|
|
205
212
|
/>
|
|
206
213
|
|
|
207
214
|
<small v-if="error" class="p-error" role="alert"
|
|
208
215
|
>Failed to load: {{ error }}</small
|
|
209
216
|
>
|
|
210
|
-
<small v-else-if="
|
|
211
|
-
|
|
217
|
+
<small v-else-if="showErrors" class="p-error">{{
|
|
218
|
+
projectedErrors
|
|
212
219
|
}}</small>
|
|
213
220
|
</div>
|
|
214
221
|
</template>
|
|
@@ -40,16 +40,17 @@ export default {
|
|
|
40
40
|
<script setup lang="ts">
|
|
41
41
|
import type { ControlProps } from "@jsonforms/vue";
|
|
42
42
|
import { useJsonFormsControl } from "@jsonforms/vue";
|
|
43
|
-
import { computed,
|
|
43
|
+
import { computed, getCurrentInstance } from "vue";
|
|
44
44
|
import { useDerive } from "../composables/useDerive";
|
|
45
45
|
import { useProjection } from "../composables/useProjection";
|
|
46
|
+
import { useDirtyValidation } from "../composables/useDirtyValidation";
|
|
46
47
|
import InputNumber from "primevue/inputnumber";
|
|
47
48
|
|
|
48
49
|
// Access props from the component instance
|
|
49
50
|
const instance = getCurrentInstance()!;
|
|
50
51
|
const props = instance.props as unknown as ControlProps;
|
|
51
52
|
const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
|
|
52
|
-
const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
|
|
53
|
+
const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
|
|
53
54
|
|
|
54
55
|
const options = computed(
|
|
55
56
|
() =>
|
|
@@ -100,31 +101,25 @@ const useGrouping = computed(() => {
|
|
|
100
101
|
return options.value.useGrouping === true;
|
|
101
102
|
});
|
|
102
103
|
|
|
103
|
-
// Track user interaction
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const showErrors = computed(() => hasInteracted.value && control.value.errors);
|
|
104
|
+
// Track user interaction — errors only show after blur
|
|
105
|
+
const { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);
|
|
107
106
|
|
|
108
107
|
const onNumber = (val: number | null) => {
|
|
109
108
|
handleChange(control.value.path, val ?? undefined);
|
|
110
109
|
};
|
|
111
|
-
|
|
112
|
-
const onBlur = () => {
|
|
113
|
-
hasInteracted.value = true;
|
|
114
|
-
};
|
|
115
110
|
</script>
|
|
116
111
|
|
|
117
112
|
<template>
|
|
118
113
|
<div class="flex flex-column gap-2">
|
|
119
|
-
<label v-if="
|
|
120
|
-
|
|
114
|
+
<label v-if="projectedLabel" class="text-color text-left">{{
|
|
115
|
+
projectedLabel
|
|
121
116
|
}}</label>
|
|
122
117
|
<div v-if="control.description" class="text-color-secondary text-left">
|
|
123
118
|
{{ control.description }}
|
|
124
119
|
</div>
|
|
125
120
|
<InputNumber
|
|
126
|
-
class="w-full"
|
|
127
|
-
input-class="w-full"
|
|
121
|
+
:class="['w-full', { 'p-invalid': showErrors }]"
|
|
122
|
+
:input-class="['w-full', { 'p-invalid': showErrors }]"
|
|
128
123
|
:use-grouping="useGrouping"
|
|
129
124
|
:mode="mode"
|
|
130
125
|
:currency="currency"
|
|
@@ -133,10 +128,10 @@ const onBlur = () => {
|
|
|
133
128
|
:model-value="typeof projectedData === 'number' ? projectedData : null"
|
|
134
129
|
:placeholder="placeholder"
|
|
135
130
|
:disabled="!control.enabled"
|
|
136
|
-
:aria-invalid="
|
|
131
|
+
:aria-invalid="showErrors || undefined"
|
|
137
132
|
@update:model-value="onNumber"
|
|
138
|
-
@blur="
|
|
133
|
+
@blur="markDirty"
|
|
139
134
|
/>
|
|
140
|
-
<small v-if="showErrors" class="p-error">{{
|
|
135
|
+
<small v-if="showErrors" class="p-error">{{ projectedErrors }}</small>
|
|
141
136
|
</div>
|
|
142
137
|
</template>
|
|
@@ -44,6 +44,7 @@ import { computed, ref, inject, watch, getCurrentInstance } from "vue";
|
|
|
44
44
|
import { useProvider } from "../composables/useProvider";
|
|
45
45
|
import { useDerive } from "../composables/useDerive";
|
|
46
46
|
import { useProjection } from "../composables/useProjection";
|
|
47
|
+
import { useDirtyValidation } from "../composables/useDirtyValidation";
|
|
47
48
|
import InputText from "primevue/inputtext";
|
|
48
49
|
import AutoComplete from "primevue/autocomplete";
|
|
49
50
|
|
|
@@ -51,7 +52,7 @@ import AutoComplete from "primevue/autocomplete";
|
|
|
51
52
|
const instance = getCurrentInstance()!;
|
|
52
53
|
const props = instance.props as unknown as ControlProps;
|
|
53
54
|
const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
|
|
54
|
-
const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
|
|
55
|
+
const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
|
|
55
56
|
|
|
56
57
|
// Provider support for autocomplete functionality
|
|
57
58
|
const binding = computed(() => {
|
|
@@ -117,11 +118,8 @@ const isAutocomplete = computed(() => !!binding.value);
|
|
|
117
118
|
// Add derive functionality
|
|
118
119
|
useDerive({ control, handleChange, data: projectedData });
|
|
119
120
|
|
|
120
|
-
// Track user interaction
|
|
121
|
-
const
|
|
122
|
-
const hasFocused = ref(false);
|
|
123
|
-
|
|
124
|
-
const showErrors = computed(() => hasInteracted.value && control.value.errors);
|
|
121
|
+
// Track user interaction — errors only show after blur
|
|
122
|
+
const { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);
|
|
125
123
|
|
|
126
124
|
function onInput(val: string | undefined) {
|
|
127
125
|
// Convert empty strings to undefined for proper required field validation
|
|
@@ -132,15 +130,14 @@ function onInput(val: string | undefined) {
|
|
|
132
130
|
}
|
|
133
131
|
|
|
134
132
|
function onBlur() {
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
markDirty();
|
|
134
|
+
// Normalize empty strings to undefined so required validation fires
|
|
135
|
+
const val = projectedData.value;
|
|
136
|
+
if (typeof val === "string" && val.trim() === "") {
|
|
137
|
+
handleChange(control.value.path, undefined);
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
function onFocus() {
|
|
141
|
-
hasFocused.value = true;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
141
|
// Autocomplete specific handlers
|
|
145
142
|
const onComplete = (event: { query: string }) => {
|
|
146
143
|
query.value = event.query;
|
|
@@ -154,42 +151,40 @@ const onSelect = (event: { value?: { value?: unknown } | unknown }) => {
|
|
|
154
151
|
|
|
155
152
|
<template>
|
|
156
153
|
<div class="flex flex-column gap-2">
|
|
157
|
-
<label v-if="
|
|
158
|
-
|
|
154
|
+
<label v-if="projectedLabel" class="text-color text-left">{{
|
|
155
|
+
projectedLabel
|
|
159
156
|
}}</label>
|
|
160
157
|
<div v-if="control.description" class="text-color-secondary text-left">
|
|
161
158
|
{{ control.description }}
|
|
162
159
|
</div>
|
|
163
160
|
<AutoComplete
|
|
164
161
|
v-if="isAutocomplete"
|
|
165
|
-
class="w-full"
|
|
162
|
+
:class="['w-full', { 'p-invalid': showErrors }]"
|
|
166
163
|
:model-value="projectedData ?? ''"
|
|
167
164
|
:suggestions="items"
|
|
168
165
|
option-label="label"
|
|
169
166
|
:placeholder="placeholder"
|
|
170
167
|
:disabled="!control.enabled"
|
|
171
|
-
:aria-invalid="
|
|
168
|
+
:aria-invalid="showErrors || undefined"
|
|
172
169
|
@complete="onComplete"
|
|
173
170
|
@item-select="onSelect"
|
|
174
171
|
@update:model-value="onInput"
|
|
175
172
|
@blur="onBlur"
|
|
176
|
-
@focus="onFocus"
|
|
177
173
|
/>
|
|
178
174
|
<InputText
|
|
179
175
|
v-else
|
|
180
|
-
class="w-full"
|
|
176
|
+
:class="['w-full', { 'p-invalid': showErrors }]"
|
|
181
177
|
:model-value="(projectedData as string) ?? ''"
|
|
182
178
|
:disabled="!control.enabled"
|
|
183
|
-
:aria-invalid="
|
|
179
|
+
:aria-invalid="showErrors || undefined"
|
|
184
180
|
:placeholder="placeholder"
|
|
185
181
|
autocapitalize="off"
|
|
186
182
|
autocomplete="off"
|
|
187
183
|
spellcheck="false"
|
|
188
184
|
@update:model-value="onInput"
|
|
189
185
|
@blur="onBlur"
|
|
190
|
-
@focus="onFocus"
|
|
191
186
|
/>
|
|
192
187
|
<small v-if="error" class="p-error" role="alert">Failed: {{ error }}</small>
|
|
193
|
-
<small v-else-if="showErrors" class="p-error">{{
|
|
188
|
+
<small v-else-if="showErrors" class="p-error">{{ projectedErrors }}</small>
|
|
194
189
|
</div>
|
|
195
190
|
</template>
|
|
@@ -40,15 +40,16 @@ export default {
|
|
|
40
40
|
<script setup lang="ts">
|
|
41
41
|
import type { ControlProps } from "@jsonforms/vue";
|
|
42
42
|
import { useJsonFormsControl } from "@jsonforms/vue";
|
|
43
|
-
import { computed,
|
|
43
|
+
import { computed, getCurrentInstance } from "vue";
|
|
44
44
|
import { useProjection } from "../composables/useProjection";
|
|
45
|
+
import { useDirtyValidation } from "../composables/useDirtyValidation";
|
|
45
46
|
import Textarea from "primevue/textarea";
|
|
46
47
|
|
|
47
48
|
// Access props from the component instance
|
|
48
49
|
const instance = getCurrentInstance()!;
|
|
49
50
|
const props = instance.props as unknown as ControlProps;
|
|
50
51
|
const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
|
|
51
|
-
const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
|
|
52
|
+
const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
|
|
52
53
|
|
|
53
54
|
const placeholder = computed<string | undefined>(
|
|
54
55
|
() =>
|
|
@@ -56,10 +57,8 @@ const placeholder = computed<string | undefined>(
|
|
|
56
57
|
?.placeholder ?? control.value.description,
|
|
57
58
|
);
|
|
58
59
|
|
|
59
|
-
// Track user interaction
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const showErrors = computed(() => hasInteracted.value && control.value.errors);
|
|
60
|
+
// Track user interaction — errors only show after blur
|
|
61
|
+
const { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);
|
|
63
62
|
|
|
64
63
|
function onInput(val: string | undefined) {
|
|
65
64
|
// Convert empty strings to undefined for proper required field validation
|
|
@@ -70,29 +69,34 @@ function onInput(val: string | undefined) {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
function onBlur() {
|
|
73
|
-
|
|
72
|
+
markDirty();
|
|
73
|
+
// Normalize empty strings to undefined so required validation fires
|
|
74
|
+
const val = projectedData.value;
|
|
75
|
+
if (typeof val === "string" && val.trim() === "") {
|
|
76
|
+
handleChange(control.value.path, undefined);
|
|
77
|
+
}
|
|
74
78
|
}
|
|
75
79
|
</script>
|
|
76
80
|
|
|
77
81
|
<template>
|
|
78
82
|
<div class="flex flex-column gap-2">
|
|
79
|
-
<label v-if="
|
|
80
|
-
|
|
83
|
+
<label v-if="projectedLabel" class="text-color text-left">{{
|
|
84
|
+
projectedLabel
|
|
81
85
|
}}</label>
|
|
82
86
|
<div v-if="control.description" class="text-color-secondary text-left">
|
|
83
87
|
{{ control.description }}
|
|
84
88
|
</div>
|
|
85
89
|
<Textarea
|
|
86
|
-
class="w-full"
|
|
90
|
+
:class="['w-full', { 'p-invalid': showErrors }]"
|
|
87
91
|
:model-value="(projectedData as string) ?? ''"
|
|
88
92
|
:disabled="!control.enabled"
|
|
89
|
-
:aria-invalid="
|
|
93
|
+
:aria-invalid="showErrors || undefined"
|
|
90
94
|
:placeholder="placeholder"
|
|
91
95
|
:rows="4"
|
|
92
96
|
:auto-resize="true"
|
|
93
97
|
@update:model-value="onInput"
|
|
94
98
|
@blur="onBlur"
|
|
95
99
|
/>
|
|
96
|
-
<small v-if="showErrors" class="p-error">{{
|
|
100
|
+
<small v-if="showErrors" class="p-error">{{ projectedErrors }}</small>
|
|
97
101
|
</div>
|
|
98
102
|
</template>
|