srcdev-nuxt-forms 2.1.24 → 2.1.25

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.
@@ -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="`${id}-error-message`">
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
- fieldHasError: true,
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
- fieldHasError: false,
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
- fieldHasError: true,
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="`${id}-error-message`"
22
+ :ariaDescribedby
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
- <template v-if="hasDescription">
4
+
5
+ <div v-if="hasDescriptionSlot" :id="`${id}-description`">
5
6
  <slot name="description"></slot>
6
- </template>
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 hasDescription = computed(() => slots.description !== undefined);
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 ariaDescribedby = hasDescriptionSlot ? `${id}-description` : null;
134
+ return fieldHasError ? errorId : ariaDescribedby;
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 ariaDescribedby = hasDescriptionSlot ? `${id}-description` : null;
109
+ return fieldHasError ? errorId : ariaDescribedby;
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.24",
4
+ "version": "2.1.25",
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
- "@nuxt/eslint-config": "0.6.1",
27
- "@nuxt/icon": "1.7.5",
28
- "@nuxt/test-utils": "3.14.4",
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.15.0",
31
- "happy-dom": "15.11.6",
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.6.3",
35
- "vitest": "2.1.5",
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": {