srcdev-nuxt-forms 0.2.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 (77) hide show
  1. package/assets/styles/brand/_brand.css +150 -0
  2. package/assets/styles/brand/_brand_dark.css +152 -0
  3. package/assets/styles/brand/_palette_dark.css +148 -0
  4. package/assets/styles/brand/_palette_light.css +148 -0
  5. package/assets/styles/brand/_typography.css +176 -0
  6. package/assets/styles/brand/index.css +1 -0
  7. package/assets/styles/forms/index.css +1 -2
  8. package/assets/styles/forms/themes/_default.css +3 -0
  9. package/assets/styles/forms/themes/_error.css +45 -11
  10. package/assets/styles/forms/themes/_ghost.css +42 -10
  11. package/assets/styles/forms/themes/_primary.css +42 -12
  12. package/assets/styles/forms/themes/_secondary.css +42 -12
  13. package/assets/styles/forms/themes/_success.css +42 -11
  14. package/assets/styles/forms/themes/_tertiary.css +42 -10
  15. package/assets/styles/forms/themes/_warning.css +42 -10
  16. package/assets/styles/forms/themes/index.css +1 -0
  17. package/assets/styles/forms/variables/_palette.css +104 -0
  18. package/assets/styles/forms/variables/_theme.css +1 -1
  19. package/assets/styles/forms/variables/index.css +2 -0
  20. package/assets/styles/main.css +2 -0
  21. package/assets/styles/scaffolding/_margin-helpers.css +308 -0
  22. package/assets/styles/scaffolding/_padding-helpers.css +308 -0
  23. package/assets/styles/scaffolding/_page.css +23 -0
  24. package/assets/styles/scaffolding/index.css +3 -0
  25. package/assets/styles/variables/colors/_blue.css +2 -2
  26. package/assets/styles/variables/colors/_gray.css +1 -1
  27. package/assets/styles/variables/colors/_green.css +2 -2
  28. package/assets/styles/variables/colors/_orange.css +2 -2
  29. package/assets/styles/variables/colors/_red.css +2 -2
  30. package/assets/styles/variables/colors/_yellow.css +1 -1
  31. package/components/forms/form-errors/InputError.vue +82 -37
  32. package/components/forms/input-button/InputButtonCore.vue +25 -104
  33. package/components/forms/input-checkbox/InputCheckboxCore.vue +37 -181
  34. package/components/forms/input-checkbox/InputCheckboxWithLabel.vue +42 -51
  35. package/components/forms/input-checkbox/variants/MultipleCheckboxes.vue +42 -69
  36. package/components/forms/input-checkbox/variants/SingleCheckbox.vue +126 -111
  37. package/components/forms/input-number/InputNumberCore.vue +184 -0
  38. package/components/forms/input-number/variants/InputNumberDefault.vue +155 -0
  39. package/components/forms/input-radio/InputRadiobuttonCore.vue +212 -0
  40. package/components/forms/input-radio/InputRadiobuttonWithLabel.vue +103 -0
  41. package/components/forms/input-radio/variants/MultipleRadiobuttons.vue +166 -0
  42. package/components/forms/input-range/InputRangeCore.vue +70 -88
  43. package/components/forms/input-range/variants/InputRangeDefault.vue +74 -46
  44. package/components/forms/input-text/InputTextCore.vue +141 -109
  45. package/components/forms/input-text/variants/material/InputPasswordWithLabel.vue +99 -0
  46. package/components/forms/input-text/variants/material/InputTextAsNumberWithLabel.vue +142 -0
  47. package/components/forms/input-text/variants/material/InputTextWithLabel.vue +125 -0
  48. package/components/forms/input-textarea/InputTextareaCore.vue +96 -105
  49. package/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +106 -0
  50. package/components/scaffolding/footer/NavFooter.vue +62 -0
  51. package/composables/useApiRequest.ts +25 -0
  52. package/composables/useFormControl.ts +2 -0
  53. package/composables/useSleep.ts +2 -2
  54. package/composables/useStyleClassPassthrough.ts +30 -0
  55. package/composables/useZodValidation.ts +120 -0
  56. package/layouts/default.vue +21 -5
  57. package/package.json +13 -9
  58. package/pages/forms/examples/material/cssbattle.vue +60 -0
  59. package/pages/forms/examples/material/text-fields.vue +375 -153
  60. package/pages/index.vue +2 -2
  61. package/pages/typography.vue +83 -0
  62. package/server/data/places/cities.json +7 -1
  63. package/types/types.forms.ts +102 -0
  64. package/types/types.zodFormControl.ts +21 -0
  65. package/assets/styles/forms/utils/_a11y.css +0 -5
  66. package/assets/styles/forms/utils/index.css +0 -1
  67. package/components/forms/input-radio/InputRadioCore.vue +0 -226
  68. package/components/forms/input-radio/InputRadioWithLabel.vue +0 -118
  69. package/components/forms/input-radio/variants/MultipleRadio.vue +0 -183
  70. package/components/forms/input-radio/variants/SingleRadio.vue +0 -131
  71. package/components/forms/input-text/variants/material/InputEmailMaterial.vue +0 -72
  72. package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +0 -114
  73. package/components/forms/input-text/variants/material/InputTextMaterial.vue +0 -68
  74. package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +0 -313
  75. package/components/forms/input-textarea/variants/material/InputTextareaMaterial.vue +0 -75
  76. package/components/forms/input-textarea/variants/material/InputTextareaMaterialCore.vue +0 -290
  77. package/composables/useUpdateStyleClassPassthrough.ts +0 -29
@@ -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;
@@ -47,6 +47,8 @@ export function useFormControl(name: string = '') {
47
47
  };
48
48
 
49
49
  const updatePreviousValues = () => {
50
+ console.log(`useFormControl | updatePreviousValues`);
51
+
50
52
  Object.keys(formData.value.data).forEach((key) => {
51
53
  formData.value.formFieldsC12[key].previousValue = formData.value.data[key];
52
54
  });
@@ -1,5 +1,5 @@
1
- const useSleep = (ms: number) => {
1
+ async function useSleep(ms: number) {
2
2
  return new Promise((resolve) => setTimeout(resolve, ms));
3
- };
3
+ }
4
4
 
5
5
  export default useSleep;
@@ -0,0 +1,30 @@
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
+ };
@@ -0,0 +1,120 @@
1
+ import { z, ZodError } from 'zod';
2
+ import type { IFormFieldStateObj, ApiErrorResponse } from '@/types/types.forms';
3
+
4
+ const useZodValidation = (formSchema: any) => {
5
+ const zodFormControl = reactive({
6
+ errorCount: 0,
7
+ displayLoader: false,
8
+ submitDisabled: false,
9
+ submitAttempted: false,
10
+ submitSuccessful: false,
11
+ formIsValid: false,
12
+ isPending: false,
13
+ isDisabled: false,
14
+ previousState: {} as Record<string, any>,
15
+ });
16
+
17
+ type formSchema = z.infer<typeof formSchema>;
18
+ const zodErrorObj = ref<z.ZodFormattedError<formSchema> | null>(null);
19
+
20
+ const resetPreviousValues = () => {
21
+ for (const [field] of Object.entries(formSchema.shape)) {
22
+ const previousValue = {
23
+ value: null,
24
+ message: '',
25
+ };
26
+
27
+ zodFormControl.previousState[field] = previousValue;
28
+ }
29
+ };
30
+
31
+ const initZodForm = () => {
32
+ resetPreviousValues();
33
+ };
34
+
35
+ const getErrorCount = (zodErrorObj: Ref<z.ZodFormattedError<formSchema> | null>) => {
36
+ const zodCountErrors = zodErrorObj.value ?? [];
37
+ // @ts-ignore
38
+ delete zodCountErrors._errors;
39
+ const errorCount = Object.keys(zodCountErrors ?? []).length;
40
+ return errorCount;
41
+ };
42
+
43
+ const transformErrorMessages = (errors: any) => {
44
+ const apiErrors = ref({}) as any;
45
+ for (const [key, value] of Object.entries(errors)) {
46
+ const fieldPath = key.split('.').map((key: string) => key.charAt(0).toLowerCase() + key.slice(1));
47
+ apiErrors.value[fieldPath.join('.')] = value;
48
+ }
49
+
50
+ return apiErrors.value;
51
+ };
52
+
53
+ const updatePreviousValue = async (field: string, message: string, state: Record<string, any>) => {
54
+ const previousValue = {
55
+ value: state[field],
56
+ message: message,
57
+ };
58
+ zodFormControl.previousState[field] = previousValue;
59
+ };
60
+
61
+ const pushCustomErrors = async (apiErrorResponse: ApiErrorResponse, state: Record<string, any>) => {
62
+ const apiErrors = transformErrorMessages(apiErrorResponse.data.errors);
63
+
64
+ // 1: Create a ZodError object to hold the issues
65
+ const zodError = new ZodError([]);
66
+
67
+ // 2: Reset previous state values
68
+ resetPreviousValues();
69
+
70
+ // 3: Add issues to the ZodError object
71
+ for (const [path, message] of Object.entries(apiErrors)) {
72
+ zodError.addIssue({
73
+ path: path.split('.'),
74
+ message: message as string,
75
+ code: z.ZodIssueCode.custom,
76
+ });
77
+ await updatePreviousValue(path, message as string, state);
78
+ }
79
+
80
+ zodErrorObj.value = zodError.format();
81
+ zodFormControl.errorCount = getErrorCount(zodErrorObj);
82
+ zodFormControl.formIsValid = zodFormControl.errorCount === 0;
83
+ zodFormControl.displayLoader = false;
84
+ zodFormControl.submitAttempted = true;
85
+ return zodErrorObj.value;
86
+ };
87
+
88
+ const doZodValidate = async (state: Record<string, any>) => {
89
+ const valid = formSchema.safeParse(toRaw(state));
90
+ if (!valid.success) {
91
+ zodErrorObj.value = valid.error.format();
92
+ } else {
93
+ zodErrorObj.value = null;
94
+ }
95
+
96
+ zodFormControl.errorCount = getErrorCount(zodErrorObj);
97
+ zodFormControl.formIsValid = valid.success;
98
+
99
+ return valid.success;
100
+ };
101
+
102
+ const fieldMaxLength = (name: string) => {
103
+ const fieldSchema = formSchema.shape[name];
104
+ if (fieldSchema instanceof z.ZodString) {
105
+ return fieldSchema._def.checks.find((check) => check.kind === 'max')?.value || null;
106
+ }
107
+ return null;
108
+ };
109
+
110
+ return {
111
+ initZodForm,
112
+ zodFormControl,
113
+ zodErrorObj,
114
+ pushCustomErrors,
115
+ doZodValidate,
116
+ fieldMaxLength,
117
+ };
118
+ };
119
+
120
+ export default useZodValidation;
@@ -4,10 +4,13 @@
4
4
  <h1><NuxtLink to="/">Home</NuxtLink></h1>
5
5
  <ul class="flex-group">
6
6
  <li>
7
- <NuxtLink to="/forms/examples/material/text-fields">Material UI text fields</NuxtLink>
7
+ <NuxtLink to="/typography" class="link-normal">Typography</NuxtLink>
8
8
  </li>
9
9
  <li>
10
- <NuxtLink to="/forms/examples/buttons">Buttons</NuxtLink>
10
+ <NuxtLink to="/forms/examples/material/text-fields" class="link-normal">Material UI text fields</NuxtLink>
11
+ </li>
12
+ <li>
13
+ <NuxtLink to="/forms/examples/buttons" class="link-normal">Buttons</NuxtLink>
11
14
  </li>
12
15
  </ul>
13
16
  </div>
@@ -16,9 +19,7 @@
16
19
  <slot name="layout-content"></slot>
17
20
  </div>
18
21
 
19
- <div>
20
- <h1>Footer</h1>
21
- </div>
22
+ <NavFooter />
22
23
  </div>
23
24
  </template>
24
25
 
@@ -28,6 +29,21 @@ useHead({
28
29
  class: 'body-default',
29
30
  id: 'body',
30
31
  },
32
+ // link: [
33
+ // {
34
+ // rel: 'preconnect',
35
+ // href: 'https://fonts.googleapis.com',
36
+ // },
37
+ // {
38
+ // rel: 'preconnect',
39
+ // href: 'https://fonts.gstatic.com',
40
+ // crossorigin: 'use-credentials',
41
+ // },
42
+ // {
43
+ // href: 'https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap',
44
+ // rel: 'stylesheet',
45
+ // },
46
+ // ],
31
47
  });
32
48
  </script>
33
49
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-forms",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "1.0.0",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "reinstall": "rm -rf node_modules && npm install",
@@ -14,13 +14,17 @@
14
14
  "release": "release-it"
15
15
  },
16
16
  "devDependencies": {
17
- "@iconify-json/material-symbols": "^1.1.88",
18
- "@iconify-json/radix-icons": "^1.1.15",
19
- "@nuxt/eslint-config": "^0.5.0",
20
- "@nuxt/icon": "^1.4.5",
21
- "eslint": "^9.9.0",
22
- "nuxt": "^3.12.4",
23
- "release-it": "^17.6.0",
24
- "typescript": "^5.5.4"
17
+ "@iconify-json/gridicons": "1.2.1",
18
+ "@iconify-json/material-symbols": "1.2.5",
19
+ "@iconify-json/radix-icons": "1.2.1",
20
+ "@nuxt/eslint-config": "0.6.1",
21
+ "@nuxt/icon": "1.6.1",
22
+ "eslint": "9.13.0",
23
+ "nuxt": "3.13.2",
24
+ "release-it": "17.10.0",
25
+ "typescript": "5.6.3"
26
+ },
27
+ "dependencies": {
28
+ "zod": "3.23.8"
25
29
  }
26
30
  }
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div>
3
+ <i a></i>
4
+ <i b></i>
5
+ <i c></i>
6
+ </div>
7
+ </template>
8
+ <script setup lang="ts">
9
+ definePageMeta({
10
+ layout: false,
11
+ });
12
+
13
+ useHead({
14
+ title: 'CSS Battle',
15
+ meta: [{ name: 'description', content: 'CSS Battle' }],
16
+ bodyAttrs: {
17
+ class: '',
18
+ },
19
+ });
20
+ </script>
21
+
22
+ <style scoped lang="css">
23
+ html * {
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+ div {
28
+ height: 300px;
29
+ width: 400px;
30
+ background: #0b2429;
31
+ display: grid;
32
+ grid-template-areas: stack;
33
+ place-content: center;
34
+
35
+ i {
36
+ grid-area: stack;
37
+ margin: auto;
38
+ }
39
+
40
+ i[a] {
41
+ background: #998235;
42
+ height: 300px;
43
+ width: 90px;
44
+ }
45
+
46
+ i[b] {
47
+ background: #0b2429;
48
+ height: 130px;
49
+ width: 100%;
50
+ }
51
+
52
+ i[c] {
53
+ background: #f3ac3c;
54
+ height: 90px;
55
+ width: 130px;
56
+ border-radius: 50px;
57
+ outline: 10px solid #0b2429;
58
+ }
59
+ }
60
+ </style>