srcdev-nuxt-forms 2.0.3 → 2.0.5

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 (35) hide show
  1. package/composables/useZodValidation.ts +1 -1
  2. package/package.json +21 -3
  3. package/.editorconfig +0 -12
  4. package/.eslintignore +0 -7
  5. package/.eslintrc.cjs +0 -12
  6. package/.nmprc +0 -2
  7. package/.nuxtrc +0 -1
  8. package/.playground/components/scaffolding/footer/NavFooter.vue +0 -62
  9. package/.playground/components/ui/content-grid/ContentGrid.vue +0 -85
  10. package/.playground/composables/useApiRequest.ts +0 -25
  11. package/.playground/composables/useErrorMessages.ts +0 -59
  12. package/.playground/composables/useFormControl.ts +0 -248
  13. package/.playground/composables/useSleep.ts +0 -5
  14. package/.playground/composables/useStyleClassPassthrough.ts +0 -30
  15. package/.playground/composables/useZodValidation.ts +0 -120
  16. package/.playground/layouts/default.vue +0 -72
  17. package/.playground/nuxt.config.ts +0 -27
  18. package/.playground/pages/forms/examples/buttons/index.vue +0 -155
  19. package/.playground/pages/forms/examples/material/cssbattle.vue +0 -60
  20. package/.playground/pages/forms/examples/material/text-fields.vue +0 -594
  21. package/.playground/pages/index.vue +0 -33
  22. package/.playground/pages/limit-text.vue +0 -43
  23. package/.playground/pages/typography.vue +0 -83
  24. package/.playground/server/api/places/list.get.ts +0 -23
  25. package/.playground/server/api/textFields.post.ts +0 -37
  26. package/.playground/server/api/utils/index.get.ts +0 -20
  27. package/.playground/server/data/places/cities.json +0 -43
  28. package/.playground/server/data/places/countries.json +0 -55
  29. package/.playground/server/data/utils/title.json +0 -49
  30. package/.playground/types/types.forms.ts +0 -216
  31. package/.playground/types/types.places.ts +0 -8
  32. package/.playground/types/types.zodFormControl.ts +0 -21
  33. package/.prettierrc +0 -5
  34. package/.release-it.json +0 -6
  35. package/tsconfig.json +0 -3
@@ -1,6 +1,6 @@
1
1
  import { ref, reactive, toRaw, type Ref } from 'vue';
2
2
  import { z, ZodError } from 'zod';
3
- import type { IFormFieldStateObj, ApiErrorResponse } from '@/types/types.forms';
3
+ import type { IFormFieldStateObj, ApiErrorResponse } from '../types/types.forms';
4
4
 
5
5
  const useZodValidation = (formSchema: any) => {
6
6
  const zodFormControl = reactive({
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-forms",
3
3
  "type": "module",
4
- "version": "2.0.3",
5
- "main": "./nuxt.config.ts",
4
+ "version": "2.0.5",
5
+ "main": "nuxt.config.ts",
6
6
  "scripts": {
7
+ "clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",
7
8
  "reinstall": "rm -rf node_modules && npm install",
8
9
  "dev": "nuxi dev .playground",
9
10
  "build": "nuxt build .playground",
@@ -13,9 +14,17 @@
13
14
  "postinstall": "nuxt prepare .playground",
14
15
  "release": "release-it"
15
16
  },
17
+ "files": [
18
+ "assets/",
19
+ "components/",
20
+ "composables/",
21
+ "types/",
22
+ "nuxt.config.ts"
23
+ ],
16
24
  "devDependencies": {
17
25
  "@nuxt/eslint-config": "0.6.1",
18
26
  "eslint": "9.14.0",
27
+ "nuxt": "3.14.159",
19
28
  "release-it": "17.10.0",
20
29
  "typescript": "5.6.3"
21
30
  },
@@ -25,7 +34,16 @@
25
34
  "@iconify-json/radix-icons": "1.2.1",
26
35
  "@iconify-json/ri": "1.2.3",
27
36
  "@nuxt/icon": "1.7.2",
28
- "nuxt": "3.14.159",
29
37
  "zod": "3.23.8"
38
+ },
39
+ "release-it": {
40
+ "$schema": "https://unpkg.com/release-it/schema/release-it.json",
41
+ "git": {
42
+ "commitMessage": "chore(release): release v${version}"
43
+ },
44
+ "github": {
45
+ "release": true,
46
+ "releaseName": "v${version}"
47
+ }
30
48
  }
31
49
  }
package/.editorconfig DELETED
@@ -1,12 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_size = 2
5
- indent_style = space
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
9
- insert_final_newline = true
10
-
11
- [*.md]
12
- trim_trailing_whitespace = false
package/.eslintignore DELETED
@@ -1,7 +0,0 @@
1
- node_modules
2
- dist
3
- .nuxt
4
- .output
5
- coverage
6
- components.d.ts
7
- nuxt.d.ts
package/.eslintrc.cjs DELETED
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- "root": true,
3
- "extends": [
4
- "@nuxtjs/eslint-config-typescript",
5
- "plugin:prettier/recommended"
6
- ],
7
- "rules": {
8
- "vue/multi-word-component-names": "off",
9
- "vue/no-multiple-template-root": "off",
10
- "@typescript-eslint/no-unused-vars": "off"
11
- }
12
- };
package/.nmprc DELETED
@@ -1,2 +0,0 @@
1
- shamefully-hoist=true
2
- strict-peer-dependencies=false
package/.nuxtrc DELETED
@@ -1 +0,0 @@
1
- typescript.includeWorkspace = true
@@ -1,62 +0,0 @@
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>
@@ -1,85 +0,0 @@
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>
@@ -1,25 +0,0 @@
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;
@@ -1,59 +0,0 @@
1
- import type { IFormData } from '@/types/types.forms';
2
-
3
- export function useErrorMessage(name: string, formData: Ref<IFormData>) {
4
- const defaultError = ref('');
5
- const errorMessages = ref(formData.value.errorMessages);
6
-
7
- const hasCustomError = () => {
8
- return errorMessages.value[name] !== undefined && errorMessages.value[name].useCustomError;
9
- };
10
-
11
- const errorMessage = computed(() => {
12
- console.log(`errorMessage()`);
13
- if (hasCustomError()) {
14
- console.log(`errorMessage() | IF`);
15
- return errorMessages.value[name].message;
16
- } else {
17
- return defaultError.value;
18
- }
19
- });
20
-
21
- const setDefaultError = (newDefaultError: string) => {
22
- defaultError.value = newDefaultError;
23
- };
24
-
25
- const fieldHasError = computed(() => {
26
- // console.log(`fieldHasError() | name(${name})`);
27
- nextTick();
28
- if (formData.value.submitDisabled) {
29
- console.log(`fieldHasError() | name(${name}) | IF`);
30
- if (hasCustomError()) {
31
- console.log(`fieldHasError() | name(${name}) | IF | IF`);
32
-
33
- return true;
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
-
37
- return !formData.value.validityState[name];
38
- }
39
- console.log(`fieldHasError() | name(${name}) | IF | ELSE`);
40
-
41
- return false;
42
- }
43
- });
44
-
45
- const removeCustomError = (valid: boolean = false) => {
46
- console.log(`useErrorMessage | removeCustomError | name(${name}) | valid(${valid})`);
47
- // formData.value.validityState[name] = valid;
48
- // await nextTick();
49
- // delete formData.value.errorMessages[name];
50
- };
51
-
52
- return {
53
- hasCustomError,
54
- errorMessage,
55
- setDefaultError,
56
- fieldHasError,
57
- removeCustomError,
58
- };
59
- }
@@ -1,248 +0,0 @@
1
- import type { IFormData, IFieldsInitialState, IFormFieldC12, IApiErrorMessages, ICustomErrorMessage, IErrorMessagesArr } from '@/types/types.forms';
2
- import { formFieldC12 } from '@/components/forms/c12/utils';
3
-
4
- // export function useFormControl(name: string = '') {
5
- export function useFormControl(name: string = '') {
6
- let savedInitialState = {};
7
-
8
- const formData = ref<IFormData>({
9
- data: {} as IFieldsInitialState,
10
- validityState: {},
11
- dirtyFields: {},
12
- focusedField: '',
13
- isPending: false,
14
- errorCount: 0,
15
- errorMessages: {},
16
- formFieldsC12: {},
17
- hasCustomErrorMessages: false,
18
- formIsValid: false,
19
- submitAttempted: false,
20
- submitDisabled: false,
21
- submitSuccess: false,
22
- displayErrorMessages: false,
23
- });
24
-
25
- const initValidationState = async (fieldsInitialState: IFieldsInitialState | Ref<IFieldsInitialState | null>) => {
26
- const fields = Object.keys(fieldsInitialState.value || {});
27
- const state = fields.reduce((accumulatedFields, field) => {
28
- accumulatedFields[field] = false;
29
- return accumulatedFields;
30
- }, {} as Record<string, boolean>);
31
- formData.value.validityState = state;
32
- };
33
-
34
- const initFormData = async (fieldsInitialState: IFieldsInitialState | Ref<IFieldsInitialState | null>) => {
35
- initValidationState(fieldsInitialState);
36
-
37
- if (fieldsInitialState !== null) {
38
- savedInitialState = toRaw(fieldsInitialState.value) as IFieldsInitialState;
39
- formData.value.data = fieldsInitialState as IFieldsInitialState;
40
- }
41
- return;
42
- };
43
-
44
- const initFormFieldsC12 = (name: string, formFieldC12: IFormFieldC12) => {
45
- formData.value.formFieldsC12[name] = formFieldC12;
46
- return;
47
- };
48
-
49
- const updatePreviousValues = () => {
50
- console.log(`useFormControl | updatePreviousValues`);
51
-
52
- Object.keys(formData.value.data).forEach((key) => {
53
- formData.value.formFieldsC12[key].previousValue = formData.value.data[key];
54
- });
55
- };
56
-
57
- const getErrorCount = async (updateState: boolean = false) => {
58
- await nextTick();
59
-
60
- const errorCount = Object.values(formData.value.validityState).filter((value) => !value).length;
61
- formData.value.errorCount = errorCount;
62
- formData.value.formIsValid = errorCount === 0;
63
-
64
- if (updateState) {
65
- formData.value.submitDisabled = true;
66
- formData.value.displayErrorMessages = formData.value.errorCount > 0;
67
- formData.value.submitAttempted = true;
68
- }
69
-
70
- if (formData.value.submitDisabled) {
71
- formData.value.submitDisabled = !formData.value.formIsValid;
72
- }
73
-
74
- // update fieldHasError ref
75
- // if (typeof formData.value!.formFieldsC12[name] !== 'undefined') {
76
- // fieldHasError.value = formData.value!.submitAttempted && !formData.value!.formFieldsC12[name].isValid;
77
- // } else {
78
- // fieldHasError.value = false;
79
- // }
80
-
81
- return formData.value.errorCount;
82
- };
83
-
84
- // Function to count items with "useCustomError" set to true
85
- const countItemsWithCustomError = (obj: IErrorMessagesArr) => {
86
- let count = 0;
87
-
88
- for (const key in obj) {
89
- if (obj.hasOwnProperty(key) && obj[key].useCustomError === true) {
90
- count++;
91
- }
92
- }
93
-
94
- return count;
95
- };
96
-
97
- /*
98
- * Useage:
99
- *
100
- * const { updateErrorMessages } = useFormControl();
101
- *
102
- * Add/Update entry
103
- * const sampleCustomErrorEmail = {
104
- * useCustomError: true,
105
- * message: "This is a sample custom error for error EMAIL",
106
- * };
107
- * updateErrorMessages("email", sampleCustomErrorEmail);
108
- */
109
- const updateErrorMessages = async (name: string, message: string = '', valid: boolean = false) => {
110
- if (!valid) {
111
- // formData.value.validityState[name] = valid;
112
- // formData.value.errorMessages[name] = {
113
- // useCustomError: true,
114
- // message,
115
- // };
116
-
117
- formData.value.formFieldsC12[name].useCustomError = true;
118
-
119
- // if (typeof message === 'string') {
120
- // formData.value.formFieldsC12[name].customErrors = message;
121
- // } else if (typeof message === 'object') {
122
- // formData.value.formFieldsC12[name].customErrors = message;
123
- // }
124
-
125
- formData.value.formFieldsC12[name].customErrors = message;
126
- formData.value.formFieldsC12[name].isValid = valid;
127
-
128
- // formData.value.errorMessages[name].useCustomError = true;
129
- // formData.value.errorMessages[name].message = message;
130
- }
131
- formData.value.hasCustomErrorMessages = countItemsWithCustomError(formData.value.errorMessages) > 0;
132
- };
133
-
134
- const useApiErrors = async (errors: IApiErrorMessages) => {
135
- // Object.keys(errors).forEach((key) => {
136
- // updateErrorMessages(key, errors[key]);
137
- // });
138
-
139
- for (const [key, message] of Object.entries(errors)) {
140
- // console.log(`${key}: ${message}`);
141
- updateErrorMessages(key, message);
142
- }
143
- };
144
-
145
- // const resetForm = () => {
146
- // console.log('resetForm()');
147
- // formData.value.data = toRaw(fieldsInitialState.value) as IFieldsInitialState;
148
- // formData.value.validityState = {};
149
- // formData.value.errorCount = 0;
150
- // formData.value.isPending = false;
151
- // formData.value.errorMessages = {};
152
- // formData.value.formIsValid = false;
153
- // };
154
-
155
- const fieldIsDirty = (name: string) => {
156
- if (typeof formData.value.formFieldsC12[name] !== 'undefined') {
157
- return formData.value.formFieldsC12[name].isDirty;
158
- } else {
159
- return false;
160
- }
161
- };
162
-
163
- // const fieldHasError = (name: string) => {
164
- // const currentValidityState = formData.value.validityState[name];
165
-
166
- // if (formData.value.submitAttempted) {
167
- // return currentValidityState;
168
- // }
169
- // return false;
170
- // };
171
-
172
- // const fieldHasError = computed({
173
- // // getter
174
- // get() {
175
- // console.log(`fieldHasError getter: ${name}`);
176
- // if (typeof formData.value!.formFieldsC12[name] !== 'undefined') {
177
- // return !formData.value!.formFieldsC12[name].isValid;
178
- // }
179
- // return formData.value.validityState[name];
180
- // },
181
- // // setter
182
- // set(newValue) {
183
- // if (formData.value.submitAttempted) {
184
- // return newValue;
185
- // }
186
- // return false;
187
- // },
188
- // });
189
-
190
- // const fieldHasError = ref(false);
191
-
192
- const formIsValid = computed(() => {
193
- return formData.value.formIsValid;
194
- });
195
-
196
- const submitDisabled = computed(() => {
197
- return formData.value.submitDisabled;
198
- });
199
-
200
- // Keep an eye on this for performance issue
201
-
202
- // const updateFieldValidity = (name: string, valid: boolean) => {
203
- // console.log(`updateFieldValidity: name:${name} - valid:${valid}`);
204
- // console.log(formData.value);
205
- // // formData.value.formFieldsC12[name].isValid = valid;
206
- // formData.value.validityState[name] = valid;
207
- // };
208
-
209
- watch(
210
- () => formData.value.validityState,
211
- () => {
212
- getErrorCount();
213
- },
214
- { deep: true }
215
- );
216
-
217
- watch(
218
- () => formData.value.formFieldsC12,
219
- () => {
220
- formData.value.formFieldsC12;
221
- },
222
- { deep: true }
223
- );
224
-
225
- watch(
226
- () => formData.value.isPending,
227
- (newValue, oldValue) => {
228
- if (newValue) {
229
- updatePreviousValues();
230
- }
231
- }
232
- );
233
-
234
- return {
235
- formData,
236
- initFormData,
237
- initFormFieldsC12,
238
- getErrorCount,
239
- updateErrorMessages,
240
- // resetForm,
241
- formIsValid,
242
- submitDisabled,
243
- useApiErrors,
244
- // fieldHasError,
245
- fieldIsDirty,
246
- // updateFieldValidity,
247
- };
248
- }
@@ -1,5 +0,0 @@
1
- async function useSleep(ms: number) {
2
- return new Promise((resolve) => setTimeout(resolve, ms));
3
- }
4
-
5
- export default useSleep;
@@ -1,30 +0,0 @@
1
- export const useStyleClassPassthrough = (styleClassPassthrough: string[]) => {
2
- const styleClassPassthroughRef = ref(styleClassPassthrough);
3
-
4
- const elementClasses = computed(() => {
5
- return styleClassPassthroughRef.value.join(' ');
6
- });
7
-
8
- const updateElementClasses = (cssClass: string | string[]) => {
9
- let cssClasses = [] as string[];
10
- if (typeof cssClass === 'string') {
11
- cssClasses = [cssClass];
12
- } else if (Array.isArray(cssClass)) {
13
- cssClasses = cssClass;
14
- }
15
-
16
- cssClasses.forEach((cssClass) => {
17
- if (styleClassPassthroughRef.value.includes(cssClass)) {
18
- styleClassPassthroughRef.value = styleClassPassthroughRef.value.filter((className) => className !== cssClass);
19
- } else {
20
- styleClassPassthroughRef.value.push(cssClass);
21
- }
22
- });
23
- };
24
-
25
- return {
26
- elementClasses,
27
- updateElementClasses,
28
- styleClassPassthroughRef,
29
- };
30
- };