srcdev-nuxt-forms 2.1.24 → 2.1.26
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/components/forms/form-errors/InputError.vue +1 -1
- package/components/forms/form-errors/tests/InputError.spec.ts +3 -3
- package/components/forms/input-text/InputTextCore.vue +6 -2
- package/components/forms/input-text/variants/InputTextAsNumberWithLabel.vue +12 -4
- package/components/forms/input-text/variants/InputTextWithLabel.vue +13 -1
- package/package.json +10 -10
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<div class="inner-icon">
|
|
6
6
|
<Icon name="radix-icons:circle-backslash" class="icon" />
|
|
7
7
|
</div>
|
|
8
|
-
<div class="message" :id
|
|
8
|
+
<div class="message" :id>
|
|
9
9
|
<ul v-if="isArray" class="message-list">
|
|
10
10
|
<li v-for="(message, index) in errorMessage" :key="index" class="message-list-item">{{ message }}</li>
|
|
11
11
|
</ul>
|
|
@@ -7,7 +7,7 @@ import ComponentUnderTest from '../InputError.vue';
|
|
|
7
7
|
let initialPropsData = {
|
|
8
8
|
dataTestid: 'inputError',
|
|
9
9
|
errorMessage: 'Hello World',
|
|
10
|
-
|
|
10
|
+
showError: true,
|
|
11
11
|
id: 'testId',
|
|
12
12
|
styleClassPassthrough: ['testClass'],
|
|
13
13
|
compact: false,
|
|
@@ -37,7 +37,7 @@ describe('InputError Component', () => {
|
|
|
37
37
|
|
|
38
38
|
it('is not displayed by default', async () => {
|
|
39
39
|
const propData = {
|
|
40
|
-
|
|
40
|
+
showError: false,
|
|
41
41
|
};
|
|
42
42
|
wrapper = await wrapperFactory(propData);
|
|
43
43
|
|
|
@@ -46,7 +46,7 @@ describe('InputError Component', () => {
|
|
|
46
46
|
|
|
47
47
|
it('is displays a single error message', async () => {
|
|
48
48
|
const propData = {
|
|
49
|
-
|
|
49
|
+
showError: true,
|
|
50
50
|
};
|
|
51
51
|
wrapper = await wrapperFactory(propData);
|
|
52
52
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
v-model="modelValue"
|
|
20
20
|
ref="inputField"
|
|
21
21
|
:aria-invalid="fieldHasError"
|
|
22
|
-
:aria-describedby
|
|
22
|
+
:aria-describedby
|
|
23
23
|
:pattern="inputPattern"
|
|
24
24
|
:inputmode
|
|
25
25
|
@focusin="updateFocus(true)"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
<script setup lang="ts">
|
|
36
36
|
import propValidators from '../c12/prop-validators';
|
|
37
37
|
|
|
38
|
-
const { type, inputmode, maxlength, id, name, placeholder, required, fieldHasError, styleClassPassthrough, theme } = defineProps({
|
|
38
|
+
const { type, inputmode, maxlength, id, name, placeholder, required, fieldHasError, styleClassPassthrough, theme, ariaDescribedby } = defineProps({
|
|
39
39
|
type: {
|
|
40
40
|
// type: String as PropType<'text' | 'email' | 'password' | 'number' | 'tel' | 'url'>,
|
|
41
41
|
type: String,
|
|
@@ -86,6 +86,10 @@ const { type, inputmode, maxlength, id, name, placeholder, required, fieldHasErr
|
|
|
86
86
|
return propValidators.theme.includes(value);
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
|
+
ariaDescribedby: {
|
|
90
|
+
type: String,
|
|
91
|
+
default: null,
|
|
92
|
+
},
|
|
89
93
|
});
|
|
90
94
|
|
|
91
95
|
const slots = useSlots();
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="input-text-with-label" :data-form-theme="formTheme" :class="[elementClasses, { dirty: isDirty }, { active: isActive }]">
|
|
3
3
|
<label :for="id" class="input-text-label body-normal-bold">{{ label }}</label>
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
<div v-if="hasDescriptionSlot" :id="`${id}-description`">
|
|
5
6
|
<slot name="description"></slot>
|
|
6
|
-
</
|
|
7
|
+
</div>
|
|
7
8
|
|
|
8
9
|
<InputTextCore
|
|
9
10
|
v-model="modelValue"
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
:styleClassPassthrough
|
|
22
23
|
:theme
|
|
23
24
|
inputmode="numeric"
|
|
25
|
+
:ariaDescribedby
|
|
24
26
|
>
|
|
25
27
|
<template v-if="hasLeftSlot" #left>
|
|
26
28
|
<InputButtonCore
|
|
@@ -53,7 +55,7 @@
|
|
|
53
55
|
</InputButtonCore>
|
|
54
56
|
</template>
|
|
55
57
|
</InputTextCore>
|
|
56
|
-
<InputError :errorMessage="errorMessage" :showError="fieldHasError" :id :isDetached="true" />
|
|
58
|
+
<InputError :errorMessage="errorMessage" :showError="fieldHasError" :id="errorId" :isDetached="true" />
|
|
57
59
|
</div>
|
|
58
60
|
</template>
|
|
59
61
|
|
|
@@ -118,7 +120,7 @@ const { maxlength, id, name, placeholder, label, errorMessage, fieldHasError, re
|
|
|
118
120
|
});
|
|
119
121
|
|
|
120
122
|
const slots = useSlots();
|
|
121
|
-
const
|
|
123
|
+
const hasDescriptionSlot = computed(() => slots.description !== undefined);
|
|
122
124
|
const hasLeftSlot = computed(() => slots.left !== undefined);
|
|
123
125
|
const hasRightSlot = computed(() => slots.right !== undefined);
|
|
124
126
|
|
|
@@ -126,6 +128,12 @@ const formTheme = computed(() => {
|
|
|
126
128
|
return fieldHasError ? 'error' : theme;
|
|
127
129
|
});
|
|
128
130
|
|
|
131
|
+
const errorId = `${id}-error-message`;
|
|
132
|
+
const ariaDescribedby = computed(() => {
|
|
133
|
+
const ariaDescribedbyId = hasDescriptionSlot.value ? `${id}-description` : null;
|
|
134
|
+
return fieldHasError ? errorId : ariaDescribedbyId;
|
|
135
|
+
});
|
|
136
|
+
|
|
129
137
|
const modelValue = defineModel();
|
|
130
138
|
const isActive = ref<boolean>(false);
|
|
131
139
|
const isDirty = ref<boolean>(false);
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
<div class="input-text-with-label" :data-form-theme="formTheme" :class="[elementClasses, { dirty: isDirty }, { active: isActive }]">
|
|
3
3
|
<label :for="id" class="input-text-label body-normal-bold">{{ label }}</label>
|
|
4
4
|
|
|
5
|
+
<div v-if="hasDescriptionSlot" :id="`${id}-description`">
|
|
6
|
+
<slot name="description"></slot>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
5
9
|
<InputTextCore
|
|
6
10
|
v-model="modelValue"
|
|
7
11
|
v-model:isDirty="isDirty"
|
|
@@ -18,6 +22,7 @@
|
|
|
18
22
|
:required
|
|
19
23
|
:styleClassPassthrough
|
|
20
24
|
:theme
|
|
25
|
+
:ariaDescribedby
|
|
21
26
|
>
|
|
22
27
|
<template v-if="hasLeftSlot" #left>
|
|
23
28
|
<slot name="left"></slot>
|
|
@@ -26,7 +31,7 @@
|
|
|
26
31
|
<slot name="right"></slot>
|
|
27
32
|
</template>
|
|
28
33
|
</InputTextCore>
|
|
29
|
-
<InputError :errorMessage="errorMessage" :showError="fieldHasError" :id :isDetached="false" />
|
|
34
|
+
<InputError :errorMessage="errorMessage" :showError="fieldHasError" :id="`${id}-error-message`" :isDetached="false" />
|
|
30
35
|
</div>
|
|
31
36
|
</template>
|
|
32
37
|
|
|
@@ -90,6 +95,7 @@ const { type, inputmode, maxlength, id, name, placeholder, label, errorMessage,
|
|
|
90
95
|
});
|
|
91
96
|
|
|
92
97
|
const slots = useSlots();
|
|
98
|
+
const hasDescriptionSlot = computed(() => slots.description !== undefined);
|
|
93
99
|
const hasLeftSlot = computed(() => slots.left !== undefined);
|
|
94
100
|
const hasRightSlot = computed(() => slots.right !== undefined);
|
|
95
101
|
|
|
@@ -97,6 +103,12 @@ const formTheme = computed(() => {
|
|
|
97
103
|
return fieldHasError ? 'error' : theme;
|
|
98
104
|
});
|
|
99
105
|
|
|
106
|
+
const errorId = `${id}-error-message`;
|
|
107
|
+
const ariaDescribedby = computed(() => {
|
|
108
|
+
const ariaDescribedbyId = hasDescriptionSlot.value ? `${id}-description` : null;
|
|
109
|
+
return fieldHasError ? errorId : ariaDescribedbyId;
|
|
110
|
+
});
|
|
111
|
+
|
|
100
112
|
const modelValue = defineModel();
|
|
101
113
|
const isActive = ref<boolean>(false);
|
|
102
114
|
const isDirty = ref<boolean>(false);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srcdev-nuxt-forms",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.26",
|
|
5
5
|
"main": "nuxt.config.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",
|
|
@@ -23,22 +23,22 @@
|
|
|
23
23
|
"types/"
|
|
24
24
|
],
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"@nuxt/
|
|
28
|
-
"@nuxt/
|
|
26
|
+
"@iconify-json/material-symbols": "1.2.10",
|
|
27
|
+
"@nuxt/eslint-config": "0.7.2",
|
|
28
|
+
"@nuxt/icon": "1.9.1",
|
|
29
|
+
"@nuxt/test-utils": "3.15.1",
|
|
29
30
|
"@vue/test-utils": "2.4.6",
|
|
30
|
-
"eslint": "9.
|
|
31
|
-
"happy-dom": "15.11.
|
|
31
|
+
"eslint": "9.16.0",
|
|
32
|
+
"happy-dom": "15.11.7",
|
|
32
33
|
"nuxt": "3.14.1592",
|
|
33
34
|
"release-it": "17.10.0",
|
|
34
|
-
"typescript": "5.
|
|
35
|
-
"vitest": "2.1.
|
|
35
|
+
"typescript": "5.7.2",
|
|
36
|
+
"vitest": "2.1.8",
|
|
36
37
|
"vue": "3.5.13"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
40
|
"@iconify-json/carbon": "1.2.4",
|
|
40
41
|
"@iconify-json/gridicons": "1.2.1",
|
|
41
|
-
"@iconify-json/material-symbols": "1.2.6",
|
|
42
42
|
"@iconify-json/radix-icons": "1.2.1",
|
|
43
43
|
"@iconify-json/ri": "1.2.3",
|
|
44
44
|
"@nuxtjs/storybook": "8.3.2",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"@storybook/addon-interactions": "8.4.6",
|
|
47
47
|
"@storybook/addon-links": "8.4.6",
|
|
48
48
|
"@storybook/vue3": "8.4.6",
|
|
49
|
-
"modern-normalize": "3.0.1",
|
|
50
49
|
"http-proxy-middleware": "3.0.3",
|
|
50
|
+
"modern-normalize": "3.0.1",
|
|
51
51
|
"zod": "3.23.8"
|
|
52
52
|
},
|
|
53
53
|
"release-it": {
|