srcdev-nuxt-forms 0.1.0 → 1.0.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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/assets/styles/brand/_brand.css +150 -0
  3. package/assets/styles/brand/_brand_dark.css +152 -0
  4. package/assets/styles/brand/_palette_dark.css +148 -0
  5. package/assets/styles/brand/_palette_light.css +148 -0
  6. package/assets/styles/brand/_typography.css +176 -0
  7. package/assets/styles/brand/index.css +1 -0
  8. package/assets/styles/forms/index.css +1 -1
  9. package/assets/styles/forms/themes/_default.css +3 -0
  10. package/assets/styles/forms/themes/_error.css +45 -11
  11. package/assets/styles/forms/themes/_ghost.css +42 -10
  12. package/assets/styles/forms/themes/_primary.css +42 -10
  13. package/assets/styles/forms/themes/_secondary.css +42 -10
  14. package/assets/styles/forms/themes/_success.css +42 -11
  15. package/assets/styles/forms/themes/_tertiary.css +42 -10
  16. package/assets/styles/forms/themes/_warning.css +42 -10
  17. package/assets/styles/forms/themes/index.css +1 -0
  18. package/assets/styles/forms/variables/_palette.css +104 -0
  19. package/assets/styles/forms/variables/_theme.css +12 -18
  20. package/assets/styles/forms/variables/index.css +2 -0
  21. package/assets/styles/main.css +2 -0
  22. package/assets/styles/scaffolding/_margin-helpers.css +308 -0
  23. package/assets/styles/scaffolding/_padding-helpers.css +308 -0
  24. package/assets/styles/scaffolding/_page.css +23 -0
  25. package/assets/styles/scaffolding/index.css +3 -0
  26. package/assets/styles/variables/colors/_blue.css +2 -2
  27. package/assets/styles/variables/colors/_gray.css +2 -1
  28. package/assets/styles/variables/colors/_green.css +2 -2
  29. package/assets/styles/variables/colors/_orange.css +2 -2
  30. package/assets/styles/variables/colors/_red.css +2 -2
  31. package/assets/styles/variables/colors/_yellow.css +1 -1
  32. package/components/forms/c12/prop-validators/index.ts +8 -20
  33. package/components/forms/c12/utils.ts +14 -0
  34. package/components/forms/c12/validation-patterns/en.json +12 -0
  35. package/components/forms/form-errors/InputError.vue +177 -0
  36. package/components/forms/input-button/InputButtonCore.vue +33 -109
  37. package/components/forms/input-button/variants/InputButtonConfirm.vue +1 -1
  38. package/components/forms/input-button/variants/InputButtonSubmit.vue +1 -1
  39. package/components/forms/input-checkbox/InputCheckboxCore.vue +263 -0
  40. package/components/forms/input-checkbox/InputCheckboxWithLabel.vue +116 -0
  41. package/components/forms/input-checkbox/variants/MultipleCheckboxes.vue +167 -0
  42. package/components/forms/input-checkbox/variants/SingleCheckbox.vue +172 -0
  43. package/components/forms/input-number/InputNumberCore.vue +184 -0
  44. package/components/forms/input-number/variants/InputNumberDefault.vue +155 -0
  45. package/components/forms/input-radio/InputRadiobuttonCore.vue +212 -0
  46. package/components/forms/input-radio/InputRadiobuttonWithLabel.vue +103 -0
  47. package/components/forms/input-radio/variants/MultipleRadiobuttons.vue +166 -0
  48. package/components/forms/input-range/InputRangeCore.vue +153 -0
  49. package/components/forms/input-range/variants/InputRangeDefault.vue +159 -0
  50. package/components/forms/input-text/InputTextCore.vue +149 -87
  51. package/components/forms/input-text/variants/material/InputPasswordWithLabel.vue +99 -0
  52. package/components/forms/input-text/variants/material/InputTextAsNumberWithLabel.vue +142 -0
  53. package/components/forms/input-text/variants/material/InputTextWithLabel.vue +125 -0
  54. package/components/forms/input-textarea/InputTextareaCore.vue +161 -0
  55. package/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +106 -0
  56. package/components/scaffolding/footer/NavFooter.vue +62 -0
  57. package/components/ui/content-grid/ContentGrid.vue +85 -0
  58. package/composables/useApiRequest.ts +25 -0
  59. package/composables/useErrorMessages.ts +17 -5
  60. package/composables/useFormControl.ts +149 -37
  61. package/composables/useSleep.ts +2 -2
  62. package/composables/useStyleClassPassthrough.ts +30 -0
  63. package/composables/useZodValidation.ts +120 -0
  64. package/layouts/default.vue +26 -16
  65. package/nuxt.config.ts +22 -0
  66. package/package.json +13 -8
  67. package/pages/forms/examples/buttons/index.vue +14 -13
  68. package/pages/forms/examples/material/cssbattle.vue +60 -0
  69. package/pages/forms/examples/material/text-fields.vue +551 -93
  70. package/pages/index.vue +2 -2
  71. package/pages/limit-text.vue +43 -0
  72. package/pages/typography.vue +83 -0
  73. package/server/api/places/list.get.ts +23 -0
  74. package/server/api/textFields.post.ts +37 -0
  75. package/server/api/utils/index.get.ts +20 -0
  76. package/server/data/places/cities.json +43 -0
  77. package/server/data/places/countries.json +55 -0
  78. package/server/data/utils/title.json +49 -0
  79. package/types/types.forms.ts +135 -3
  80. package/types/types.places.ts +8 -0
  81. package/types/types.zodFormControl.ts +21 -0
  82. package/components/forms/input-text/variants/material/InputEmailMaterial.vue +0 -72
  83. package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +0 -88
  84. package/components/forms/input-text/variants/material/InputTextMaterial.vue +0 -75
  85. package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +0 -258
  86. package/composables/useUpdateStyleClassPassthrough.ts +0 -29
  87. package/pages/forms/examples/material/text-fields-compact.vue +0 -136
@@ -0,0 +1,125 @@
1
+ <template>
2
+ <div class="input-text-with-label" :data-form-theme="formTheme" :class="[elementClasses, { dirty: isDirty }, { active: isActive }]">
3
+ <label :for="id" class="input-text-label body-normal-bold">{{ label }}</label>
4
+
5
+ <InputTextCore
6
+ v-model="modelValue"
7
+ v-model:isDirty="isDirty"
8
+ v-model:isActive="isActive"
9
+ :type
10
+ :maxlength
11
+ :id
12
+ :name
13
+ :placeholder
14
+ :label
15
+ :errorMessage
16
+ :fieldHasError
17
+ :required
18
+ :styleClassPassthrough
19
+ :theme
20
+ >
21
+ <template v-if="hasLeftSlot" #left>
22
+ <slot name="left"></slot>
23
+ </template>
24
+ <template v-if="hasRightSlot" #right>
25
+ <slot name="right"></slot>
26
+ </template>
27
+ </InputTextCore>
28
+ <InputError :errorMessage="errorMessage" :fieldHasError :id :isDetached="false" />
29
+ </div>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import propValidators from '../../../c12/prop-validators';
34
+ const { type, maxlength, id, name, placeholder, label, errorMessage, fieldHasError, required, styleClassPassthrough, theme } = defineProps({
35
+ maxlength: {
36
+ type: Number,
37
+ default: 255,
38
+ },
39
+ type: {
40
+ type: String,
41
+ required: true,
42
+ },
43
+ id: {
44
+ type: String,
45
+ required: true,
46
+ },
47
+ name: {
48
+ type: String,
49
+ required: true,
50
+ },
51
+ placeholder: {
52
+ type: String,
53
+ default: '',
54
+ },
55
+ label: {
56
+ type: String,
57
+ required: true,
58
+ },
59
+ errorMessage: {
60
+ type: [Object, String],
61
+ required: true,
62
+ },
63
+ fieldHasError: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
67
+ required: {
68
+ type: Boolean,
69
+ default: false,
70
+ },
71
+ styleClassPassthrough: {
72
+ type: Array as PropType<string[]>,
73
+ default: () => [],
74
+ },
75
+ theme: {
76
+ type: String as PropType<string>,
77
+ default: 'primary',
78
+ validator(value: string) {
79
+ return propValidators.theme.includes(value);
80
+ },
81
+ },
82
+ });
83
+
84
+ const slots = useSlots();
85
+ const hasLeftSlot = computed(() => slots.left !== undefined);
86
+ const hasRightSlot = computed(() => slots.right !== undefined);
87
+
88
+ const formTheme = computed(() => {
89
+ return fieldHasError ? 'error' : theme;
90
+ });
91
+
92
+ const modelValue = defineModel();
93
+ const isActive = ref<boolean>(false);
94
+ const isDirty = ref<boolean>(false);
95
+
96
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
97
+
98
+ const testDirty = () => {
99
+ const watchValue = modelValue.value ?? '';
100
+
101
+ if (!isDirty.value && typeof watchValue === 'string' && watchValue.length > 0) {
102
+ isDirty.value = true;
103
+ }
104
+ };
105
+
106
+ onMounted(() => {
107
+ testDirty();
108
+ });
109
+
110
+ watch(
111
+ () => modelValue.value,
112
+ () => {
113
+ testDirty();
114
+ }
115
+ );
116
+ </script>
117
+
118
+ <style lang="css">
119
+ .input-text-with-label {
120
+ .input-text-label {
121
+ display: block;
122
+ margin-block: 8px;
123
+ }
124
+ }
125
+ </style>
@@ -0,0 +1,161 @@
1
+ <template>
2
+ <div
3
+ class="input-textarea-wrapper"
4
+ :data-form-theme="formTheme"
5
+ :class="[{ dirty: isDirty }, { active: isActive }, { error: fieldHasError }, { 'has-left-slot': hasLeftSlot }, { 'has-right-slot': hasRightSlot }]"
6
+ >
7
+ <span v-if="hasLeftSlot" class="slot left-slot">
8
+ <slot name="left"></slot>
9
+ </span>
10
+
11
+ <textarea
12
+ :maxlength
13
+ :placeholder
14
+ :id
15
+ :name
16
+ :required
17
+ :class="['input-text-core', 'text-normal', elementClasses, { dirty: isDirty }, { active: isActive }]"
18
+ v-model="modelValue"
19
+ ref="inputField"
20
+ :aria-invalid="fieldHasError"
21
+ :aria-describedby="`${id}-error-message`"
22
+ @focusin="updateFocus(true)"
23
+ @focusout="updateFocus(false)"
24
+ ></textarea>
25
+
26
+ <span v-if="hasRightSlot" class="slot right-slot">
27
+ <slot name="right"></slot>
28
+ </span>
29
+ </div>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import propValidators from '../c12/prop-validators';
34
+ const { maxlength, id, name, placeholder, fieldHasError, required, styleClassPassthrough, theme } = defineProps({
35
+ maxlength: {
36
+ type: Number,
37
+ default: 255,
38
+ },
39
+ id: {
40
+ type: String,
41
+ required: true,
42
+ },
43
+ name: {
44
+ type: String,
45
+ required: true,
46
+ },
47
+ placeholder: {
48
+ type: String,
49
+ default: '',
50
+ },
51
+ fieldHasError: {
52
+ type: Boolean,
53
+ default: false,
54
+ },
55
+ required: {
56
+ type: Boolean,
57
+ default: false,
58
+ },
59
+ styleClassPassthrough: {
60
+ type: Array as PropType<string[]>,
61
+ default: () => [],
62
+ },
63
+ theme: {
64
+ type: String as PropType<string>,
65
+ default: 'primary',
66
+ validator(value: string) {
67
+ return propValidators.theme.includes(value);
68
+ },
69
+ },
70
+ });
71
+
72
+ const slots = useSlots();
73
+ const hasLeftSlot = computed(() => slots.left !== undefined);
74
+ const hasRightSlot = computed(() => slots.right !== undefined);
75
+
76
+ const formTheme = computed(() => {
77
+ return fieldHasError ? 'error' : theme;
78
+ });
79
+
80
+ const modelValue = defineModel<string | number | readonly string[] | null | undefined>();
81
+ const isDirty = defineModel('isDirty');
82
+ const isActive = defineModel('isActive');
83
+
84
+ const updateFocus = (isFocused: boolean) => {
85
+ isActive.value = isFocused;
86
+ };
87
+
88
+ const inputField = ref<HTMLInputElement | null>(null);
89
+
90
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
91
+
92
+ onMounted(() => {
93
+ updateElementClasses(['deep-bristol', 'deep-london', 'deep-bath']);
94
+ });
95
+ </script>
96
+
97
+ <style lang="css">
98
+ .input-textarea-wrapper {
99
+ --_gutter: 12px;
100
+ --_border-width: var(--input-border-width-thin);
101
+ --_outline-width: var(--input-border-width-thin);
102
+
103
+ display: flex;
104
+ align-items: center;
105
+
106
+ background-color: var(--theme-form-input-bg);
107
+ border-radius: var(--input-border-width-default);
108
+ border: var(--_border-width) solid var(--theme-form-input-border);
109
+
110
+ &:focus-within {
111
+ border: var(--_border-width) solid var(--theme-form-input-border-focus);
112
+ outline: var(--_outline-width) solid hsl(from var(--theme-form-input-outline-focus) h s 50%);
113
+ box-shadow: var(--theme-form-focus-box-shadow);
114
+ }
115
+
116
+ .slot {
117
+ display: inline-block;
118
+ padding-inline: 8px;
119
+
120
+ .icon {
121
+ color: var(--theme-form-input-text);
122
+ }
123
+ }
124
+
125
+ &.has-left-slot {
126
+ .left-slot {
127
+ display: flex;
128
+ align-items: center;
129
+ }
130
+ }
131
+
132
+ &.has-right-slot {
133
+ .right-slot {
134
+ display: flex;
135
+ align-items: center;
136
+ }
137
+ }
138
+
139
+ .input-text-core {
140
+ background-color: transparent;
141
+ border: none;
142
+ outline: none;
143
+ box-shadow: none;
144
+ flex-grow: 1;
145
+
146
+ color: var(--theme-form-input-text);
147
+ font-family: var(--font-family);
148
+ font-size: var(--theme-form-button-font-size-normal);
149
+ line-height: var(--line-height);
150
+ padding: 8px 12px;
151
+
152
+ &::placeholder,
153
+ &::-webkit-input-placeholder {
154
+ font-family: var(--font-family);
155
+ font-size: var(--font-size);
156
+ font-style: italic;
157
+ font-weight: 400;
158
+ }
159
+ }
160
+ }
161
+ </style>
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <div class="input-textarea-with-label" :data-form-theme="formTheme" :class="[elementClasses, { dirty: isDirty }, { active: isActive }]">
3
+ <label :for="id" class="input-textarea-label body-normal-semibold">{{ label }}</label>
4
+
5
+ <InputTextareaCore v-model="modelValue" v-model:isDirty="isDirty" v-model:isActive="isActive" :maxlength :id :name :placeholder :label :fieldHasError :required :styleClassPassthrough :theme>
6
+ <template v-if="hasLeftSlot" #left>
7
+ <slot name="left"></slot>
8
+ </template>
9
+ <template v-if="hasRightSlot" #right>
10
+ <slot name="right"></slot>
11
+ </template>
12
+ </InputTextareaCore>
13
+ <InputError :errorMessage :fieldHasError :id :isDetached="false" />
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import propValidators from '../../c12/prop-validators';
19
+ const { maxlength, id, name, placeholder, label, errorMessage, fieldHasError, required, styleClassPassthrough, theme } = defineProps({
20
+ maxlength: {
21
+ type: Number,
22
+ default: 255,
23
+ },
24
+ id: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ name: {
29
+ type: String,
30
+ required: true,
31
+ },
32
+ placeholder: {
33
+ type: String,
34
+ default: '',
35
+ },
36
+ label: {
37
+ type: String,
38
+ required: true,
39
+ },
40
+ errorMessage: {
41
+ type: [Object, String],
42
+ required: true,
43
+ },
44
+ fieldHasError: {
45
+ type: Boolean,
46
+ default: false,
47
+ },
48
+ required: {
49
+ type: Boolean,
50
+ default: false,
51
+ },
52
+ styleClassPassthrough: {
53
+ type: Array as PropType<string[]>,
54
+ default: () => [],
55
+ },
56
+ theme: {
57
+ type: String as PropType<string>,
58
+ default: 'primary',
59
+ validator(value: string) {
60
+ return propValidators.theme.includes(value);
61
+ },
62
+ },
63
+ });
64
+
65
+ const slots = useSlots();
66
+ const hasLeftSlot = computed(() => slots.left !== undefined);
67
+ const hasRightSlot = computed(() => slots.right !== undefined);
68
+
69
+ const formTheme = computed(() => {
70
+ return fieldHasError ? 'error' : theme;
71
+ });
72
+
73
+ const modelValue = defineModel<string | number | readonly string[] | null | undefined>();
74
+ const isActive = ref<boolean>(false);
75
+ const isDirty = ref<boolean>(false);
76
+
77
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
78
+
79
+ const testDirty = () => {
80
+ const watchValue = modelValue.value ?? '';
81
+
82
+ if (!isDirty.value && typeof watchValue === 'string' && watchValue.length > 0) {
83
+ isDirty.value = true;
84
+ }
85
+ };
86
+
87
+ onMounted(() => {
88
+ testDirty();
89
+ });
90
+
91
+ watch(
92
+ () => modelValue.value,
93
+ () => {
94
+ testDirty();
95
+ }
96
+ );
97
+ </script>
98
+
99
+ <style lang="css">
100
+ .input-textarea-with-label {
101
+ .input-textarea-label {
102
+ display: block;
103
+ margin-block: 8px;
104
+ }
105
+ }
106
+ </style>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <footer>
3
+ <ul class="footer-list">
4
+ <li class="footer-item">
5
+ <Icon name="material-symbols-light:mail-rounded" class="icon" />
6
+ <span class="text">email@address.com</span>
7
+ </li>
8
+ <li class="footer-item">
9
+ <Icon name="ph:building-office-light" class="icon" />
10
+ <span class="text">Company number: 12345678</span>
11
+ </li>
12
+ <li class="footer-item">
13
+ <Icon name="material-symbols:call" class="icon" />
14
+ <span class="text">+44 (0) 1223 123 123</span>
15
+ </li>
16
+ <li class="footer-item">
17
+ <Icon name="material-symbols:location-on" class="icon" />
18
+ <span class="text">Some address, City, Postcode</span>
19
+ </li>
20
+ </ul>
21
+ </footer>
22
+ </template>
23
+ <script setup lang="ts"></script>
24
+
25
+ <style lang="css">
26
+ footer {
27
+ display: none;
28
+ padding: 1rem;
29
+ text-align: center;
30
+ background: white;
31
+ margin-bottom: 50px;
32
+
33
+ .footer-list {
34
+ display: inline-grid;
35
+ gap: 10px;
36
+ grid-template-columns: 280px 456px;
37
+ margin-inline: auto;
38
+ padding: 0;
39
+ }
40
+
41
+ .footer-item {
42
+ list-style-type: none;
43
+ gap: 10px;
44
+ display: grid;
45
+ grid-template-columns: 40px auto;
46
+ align-items: center;
47
+
48
+ .icon {
49
+ display: block;
50
+ font-size: 30px;
51
+ text-align: center;
52
+ min-width: 40px;
53
+ }
54
+ .text {
55
+ font-family: 'Poppins', Sans-serif;
56
+ font-family: var(--font-family);
57
+ font-size: var(--step-1);
58
+ text-align: start;
59
+ }
60
+ }
61
+ }
62
+ </style>
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <div class="ui-content-grid" :class="[applyClasses]" :data-testid="dataTestid">
3
+ <div v-if="hasSlot1" class="col-1">
4
+ <slot name="slot1"></slot>
5
+ </div>
6
+ <div v-if="hasSlot2" class="col-2">
7
+ <slot name="slot2"></slot>
8
+ </div>
9
+ </div>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ const props = defineProps({
14
+ dataTestid: {
15
+ type: String,
16
+ default: 'ui-content-grid',
17
+ },
18
+ applyClasses: {
19
+ type: String,
20
+ default: '',
21
+ },
22
+ });
23
+
24
+ const slots = useSlots();
25
+ const hasSlot1 = ref(slots.slot1 !== undefined);
26
+ const hasSlot2 = ref(slots.slot2 !== undefined);
27
+ </script>
28
+
29
+ <style lang="css">
30
+ .ui-content-grid {
31
+ --_margin-inline: 0;
32
+ --_grid-template-columns: repeat(4, 1fr);
33
+ --_grid-template-rows: repeat(2, auto);
34
+ --_grid-gap: 16px;
35
+
36
+ display: grid;
37
+ gap: var(--_grid-gap);
38
+ grid-template-columns: var(--_grid-template-columns);
39
+ grid-template-rows: var(--_grid-template-rows);
40
+ margin-inline: var(--_margin-inline);
41
+
42
+ @container content (min-width: 768px) {
43
+ --_margin-inline: 0;
44
+ --_grid-template-columns: repeat(6, 1fr);
45
+ --_grid-gap: 32px;
46
+ }
47
+
48
+ @container content (min-width: 1024px) {
49
+ --_margin-inline: 0;
50
+ --_grid-template-columns: repeat(12, 1fr);
51
+ --_grid-template-rows: initial;
52
+ }
53
+
54
+ .col-1 {
55
+ --_grid-column: 1 / span 4;
56
+ --_grid-row: 1;
57
+ grid-column: var(--_grid-column);
58
+ grid-row: var(--_grid-row);
59
+
60
+ @container content (min-width: 768px) {
61
+ --_grid-column: 1 / span 6;
62
+ }
63
+
64
+ @container content (min-width: 1024px) {
65
+ --_grid-column: 1 / span 6;
66
+ }
67
+ }
68
+
69
+ .col-2 {
70
+ --_grid-column: 1 / span 4;
71
+ --_grid-row: 2;
72
+ grid-column: var(--_grid-column);
73
+ grid-row: var(--_grid-row);
74
+
75
+ @container content (min-width: 768px) {
76
+ --_grid-column: 1 / span 6;
77
+ }
78
+
79
+ @container content (min-width: 1024px) {
80
+ --_grid-column: 7 / span 6;
81
+ --_grid-row: 1;
82
+ }
83
+ }
84
+ }
85
+ </style>
@@ -0,0 +1,25 @@
1
+ class CustomError extends Error {
2
+ // name = "CustomError";
3
+ override name = 'CustomError';
4
+ extraProp = 'Error: test';
5
+ }
6
+
7
+ async function useApiRequest<T, E extends new (message?: string) => Error>(promise: Promise<T>, errorsToCatch?: E[]): Promise<[undefined, T] | [InstanceType<E>]> {
8
+ return promise
9
+ .then((data) => {
10
+ return [undefined, data] as [undefined, T];
11
+ })
12
+ .catch((error) => {
13
+ if (errorsToCatch == undefined) {
14
+ return [error];
15
+ }
16
+
17
+ if (errorsToCatch.some((errorType) => error instanceof errorType)) {
18
+ return [error];
19
+ }
20
+
21
+ throw error;
22
+ });
23
+ }
24
+
25
+ export default useApiRequest;
@@ -2,15 +2,17 @@ import type { IFormData } from '@/types/types.forms';
2
2
 
3
3
  export function useErrorMessage(name: string, formData: Ref<IFormData>) {
4
4
  const defaultError = ref('');
5
- const customErrorMessages = ref(toRaw(formData.value.customErrorMessages));
5
+ const errorMessages = ref(formData.value.errorMessages);
6
6
 
7
7
  const hasCustomError = () => {
8
- return customErrorMessages.value[name] !== undefined && customErrorMessages.value[name].useCustomError;
8
+ return errorMessages.value[name] !== undefined && errorMessages.value[name].useCustomError;
9
9
  };
10
10
 
11
11
  const errorMessage = computed(() => {
12
+ console.log(`errorMessage()`);
12
13
  if (hasCustomError()) {
13
- return customErrorMessages.value[name].message;
14
+ console.log(`errorMessage() | IF`);
15
+ return errorMessages.value[name].message;
14
16
  } else {
15
17
  return defaultError.value;
16
18
  }
@@ -21,20 +23,30 @@ export function useErrorMessage(name: string, formData: Ref<IFormData>) {
21
23
  };
22
24
 
23
25
  const fieldHasError = computed(() => {
26
+ // console.log(`fieldHasError() | name(${name})`);
27
+ nextTick();
24
28
  if (formData.value.submitDisabled) {
29
+ console.log(`fieldHasError() | name(${name}) | IF`);
25
30
  if (hasCustomError()) {
31
+ console.log(`fieldHasError() | name(${name}) | IF | IF`);
32
+
26
33
  return true;
27
34
  } else if (Object.keys(formData.value.validityState).length > 0 && formData.value.validityState[name] !== undefined) {
35
+ console.log(`fieldHasError() | name(${name}) | IF | ELSE IF`);
36
+
28
37
  return !formData.value.validityState[name];
29
38
  }
39
+ console.log(`fieldHasError() | name(${name}) | IF | ELSE`);
40
+
30
41
  return false;
31
42
  }
32
43
  });
33
44
 
34
45
  const removeCustomError = (valid: boolean = false) => {
35
- formData.value.validityState[name] = valid;
46
+ console.log(`useErrorMessage | removeCustomError | name(${name}) | valid(${valid})`);
47
+ // formData.value.validityState[name] = valid;
36
48
  // await nextTick();
37
- delete formData.value.customErrorMessages[name];
49
+ // delete formData.value.errorMessages[name];
38
50
  };
39
51
 
40
52
  return {