srcdev-nuxt-forms 0.0.23 → 0.1.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 (36) hide show
  1. package/.prettierrc +2 -1
  2. package/assets/styles/forms/themes/_error.css +9 -0
  3. package/assets/styles/forms/themes/_ghost.css +11 -0
  4. package/assets/styles/forms/themes/_primary.css +9 -1
  5. package/assets/styles/forms/themes/_secondary.css +11 -0
  6. package/assets/styles/forms/themes/_success.css +12 -0
  7. package/assets/styles/forms/themes/_tertiary.css +11 -0
  8. package/assets/styles/forms/themes/_warning.css +11 -0
  9. package/assets/styles/forms/themes/index.css +5 -0
  10. package/assets/styles/forms/variables/_theme.css +60 -0
  11. package/assets/styles/variables/colors/_orange.css +1 -1
  12. package/assets/styles/variables/colors/_red.css +1 -1
  13. package/components/forms/c12/prop-validators/index.ts +25 -0
  14. package/components/forms/c12/validation-patterns/en.json +1 -1
  15. package/components/forms/input-button/InputButtonCore.vue +367 -0
  16. package/components/forms/input-button/variants/InputButtonConfirm.vue +78 -0
  17. package/components/forms/input-button/variants/InputButtonSubmit.vue +74 -0
  18. package/components/forms/input-text/InputTextCore.vue +72 -66
  19. package/components/forms/input-text/variants/material/InputEmailMaterial.vue +72 -0
  20. package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +88 -0
  21. package/components/forms/input-text/variants/material/InputTextMaterial.vue +75 -0
  22. package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +258 -0
  23. package/components/forms/ui/FormField.vue +7 -2
  24. package/components/forms/ui/FormWrapper.vue +2 -2
  25. package/composables/useErrorMessages.ts +4 -4
  26. package/composables/useFormControl.ts +36 -16
  27. package/layouts/default.vue +33 -2
  28. package/nuxt.config.ts +4 -3
  29. package/package.json +3 -1
  30. package/pages/forms/examples/buttons/index.vue +154 -0
  31. package/pages/forms/examples/material/text-fields-compact.vue +136 -0
  32. package/pages/forms/examples/material/text-fields.vue +136 -0
  33. package/pages/index.vue +2 -70
  34. package/types/types.forms.ts +6 -11
  35. package/components/forms/input-text/InputTextField.vue +0 -22
  36. package/components/forms/input-text/variants/InputTextMaterial.vue +0 -192
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <InputButtonCore
3
+ type="submit"
4
+ :use-effect="useEffect"
5
+ :isPending="isPending"
6
+ :readonly
7
+ :effect="effect"
8
+ :data-test-id="dataTestId"
9
+ :size
10
+ :weight
11
+ :button-text="buttonText"
12
+ :style-class-passthrough="styleClassPassthrough"
13
+ :theme
14
+ />
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import propValidators from '../../c12/prop-validators';
19
+
20
+ const props = defineProps({
21
+ size: {
22
+ type: String as PropType<string>,
23
+ default: 'normal',
24
+ validator(value: string) {
25
+ return propValidators.size.includes(value);
26
+ },
27
+ },
28
+ weight: {
29
+ type: String as PropType<string>,
30
+ default: 'wght-400',
31
+ validator(value: string) {
32
+ return propValidators.weight.includes(value);
33
+ },
34
+ },
35
+ theme: {
36
+ type: String as PropType<string>,
37
+ default: 'primary',
38
+ validator(value: string) {
39
+ return propValidators.theme.includes(value);
40
+ },
41
+ },
42
+ useEffect: {
43
+ type: Boolean,
44
+ default: false,
45
+ },
46
+ effect: {
47
+ type: String as PropType<string>,
48
+ default: 'fancy',
49
+ validator(value: string) {
50
+ return ['fancy', 'pulse'].includes(value);
51
+ },
52
+ },
53
+ buttonText: {
54
+ type: String,
55
+ required: true,
56
+ },
57
+ dataTestId: {
58
+ type: String,
59
+ default: '',
60
+ },
61
+ styleClassPassthrough: {
62
+ type: String,
63
+ default: '',
64
+ },
65
+ isPending: {
66
+ type: Boolean,
67
+ default: false,
68
+ },
69
+ readonly: {
70
+ type: Boolean,
71
+ default: false,
72
+ },
73
+ });
74
+ </script>
@@ -1,25 +1,33 @@
1
1
  <template>
2
- <input
3
- :type
4
- :placeholder="c12.placeholder"
5
- :id
6
- :name
7
- :pattern="componentValidation.pattern"
8
- :maxlength="componentValidation.maxlength"
9
- :required
10
- :class="[
11
- 'input-text',
12
- 'text-normal',
13
- styleClassPassthrough,
14
- { active: isFocused },
15
- { dirty: isDirty },
16
- { error: fieldHasError() },
17
- ]"
18
- v-model="modelValue.data[name]"
19
- ref="inputField"
20
- @focusin="isFocused = true"
21
- @focusout="isFocused = false"
22
- />
2
+ <div class="input-text-wrapper" :class="[{ 'has-left-content': hasLeftContent }]">
3
+ <template v-if="hasLeftContent">
4
+ <span class="left-content">
5
+ <slot name="left"></slot>
6
+ </span>
7
+ </template>
8
+
9
+ <input
10
+ :type
11
+ :placeholder="c12.placeholder"
12
+ :id
13
+ :name
14
+ :pattern="componentValidation.pattern"
15
+ :maxlength="componentValidation.maxlength"
16
+ :required
17
+ :class="['input-text', 'text-normal', styleClassPassthrough, { active: isFocused }, { dirty: isDirty }, { error: fieldHasError() }]"
18
+ v-model="modelValue.data[name]"
19
+ ref="inputField"
20
+ :readonly="isPending"
21
+ @focusin="updateFocus(name, true)"
22
+ @focusout="updateFocus(name, false)"
23
+ />
24
+
25
+ <template v-if="hasRightContent">
26
+ <span class="right-content">
27
+ <slot name="right"></slot>
28
+ </span>
29
+ </template>
30
+ </div>
23
31
  </template>
24
32
 
25
33
  <script setup lang="ts">
@@ -31,9 +39,7 @@ const props = defineProps({
31
39
  // type: String as PropType<"text" | "password" | "tel" | "number" | "email" | "url">, // This breaks props setup in unit tests
32
40
  type: String,
33
41
  validator(value: string) {
34
- return ['text', 'password', 'tel', 'number', 'email', 'url'].includes(
35
- value
36
- );
42
+ return ['text', 'password', 'tel', 'number', 'email', 'url'].includes(value);
37
43
  },
38
44
  },
39
45
  id: {
@@ -43,20 +49,16 @@ const props = defineProps({
43
49
  },
44
50
  name: {
45
51
  type: String,
46
- default: null,
52
+ required: true,
47
53
  },
48
54
  validation: {
49
55
  type: String,
50
- default: '',
56
+ default: null,
51
57
  },
52
58
  required: {
53
59
  type: Boolean,
54
60
  value: false,
55
61
  },
56
- isPending: {
57
- type: Boolean,
58
- value: false,
59
- },
60
62
  c12: {
61
63
  type: Object as PropType<InpuTextC12>,
62
64
  required: true,
@@ -67,9 +69,27 @@ const props = defineProps({
67
69
  },
68
70
  });
69
71
 
72
+ const slots = useSlots();
73
+ const hasLeftContent = computed(() => slots.left !== undefined);
74
+ const hasRightContent = computed(() => slots.right !== undefined);
75
+
70
76
  const modelValue = defineModel() as Ref<IFormData>;
71
- const isFocused = defineModel('isFocused') as Ref<boolean>;
72
- const isDirty = defineModel('isDirty') as Ref<boolean>;
77
+
78
+ const updateFocus = (name: string, isFocused: boolean) => {
79
+ modelValue.value.focusedField = isFocused ? name : '';
80
+ };
81
+
82
+ const isPending = computed(() => {
83
+ return modelValue.value.isPending;
84
+ });
85
+
86
+ const isFocused = computed(() => {
87
+ return modelValue.value.focusedField == name.value;
88
+ });
89
+
90
+ const isDirty = computed(() => {
91
+ return modelValue.value.dirtyFields[name.value];
92
+ });
73
93
 
74
94
  const name = computed(() => {
75
95
  return props.name !== null ? props.name : props.id;
@@ -77,37 +97,27 @@ const name = computed(() => {
77
97
 
78
98
  const validatorLocale = toRef(useRuntimeConfig().public.validatorLocale);
79
99
 
80
- const componentValidation =
81
- validationConfig[validatorLocale.value][props.validation];
100
+ const componentValidation = validationConfig[validatorLocale.value][props.validation];
82
101
  const inputField = ref<HTMLInputElement | null>(null);
83
102
 
84
- const { hasCustomError, removeCustomError } = useErrorMessage(
85
- name.value,
86
- modelValue
87
- );
103
+ const { hasCustomError, removeCustomError } = useErrorMessage(name.value, modelValue);
88
104
 
89
105
  const fieldHasError = () => {
90
106
  const hasApiErrorMessage = hasCustomError();
91
107
  const inputBad = !inputField.value?.validity.valid;
92
108
 
93
109
  if (modelValue.value.isPending) {
94
- modelValue.value!.validityState[name.value] =
95
- inputField.value?.validity.valid ?? false;
110
+ modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
96
111
  return hasApiErrorMessage ? hasApiErrorMessage : inputBad;
97
112
  }
98
113
  return false;
99
114
  };
100
115
 
101
116
  watchEffect(() => {
102
- console.log(
103
- 'InputTextCore >> Form value changed to: ',
104
- modelValue.value.data[name.value]
105
- );
117
+ console.log('watchEffect()');
118
+ modelValue.value.dirtyFields[name.value] = modelValue.value.data[name.value] !== '';
106
119
 
107
- isDirty.value = modelValue.value.data[name.value] !== '';
108
-
109
- modelValue.value!.validityState[name.value] =
110
- inputField.value?.validity.valid ?? false;
120
+ modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
111
121
  if (hasCustomError()) {
112
122
  removeCustomError(inputField.value?.validity.valid);
113
123
  }
@@ -115,31 +125,27 @@ watchEffect(() => {
115
125
 
116
126
  const isValid = () => {
117
127
  setTimeout(() => {
118
- modelValue.value!.validityState[name.value] =
119
- inputField.value?.validity.valid ?? false;
128
+ modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
120
129
  }, 0);
121
130
  };
122
131
 
123
- // Keep an eye on this for performance issue
124
- // watch(
125
- // () => modelValue.value.data[name.value],
126
- // () => {
127
- // modelValue.value!.validityState[name.value] =
128
- // inputField.value?.validity.valid ?? false;
129
- // if (hasCustomError()) {
130
- // removeCustomError(inputField.value?.validity.valid);
131
- // }
132
- // },
133
- // { deep: true }
134
- // );
135
-
136
132
  onMounted(() => {
137
133
  isValid();
138
134
  });
139
135
  </script>
140
136
 
141
137
  <style lang="css">
142
- /* .input-text {
143
- transition: all linear 200ms;
144
- } */
138
+ .input-text-wrapper {
139
+ display: flex;
140
+ align-items: center;
141
+
142
+ &.has-left-content {
143
+ margin-left: var(--_gutter);
144
+
145
+ .left-content {
146
+ display: flex;
147
+ align-items: center;
148
+ }
149
+ }
150
+ }
145
151
  </style>
@@ -0,0 +1,72 @@
1
+ <template>
2
+ <InputTextMaterialCore type="email" :id :name :required :c12 :styleClassPassthrough :theme v-model="modelValue">
3
+ <template #input>
4
+ <InputTextCore :id :name type="email" :validation :required v-model="modelValue" :c12 :style-class-passthrough="styleClassPassthrough">
5
+ <template #left>
6
+ <Icon name="radix-icons:envelope-closed" class="icon" />
7
+ </template>
8
+ </InputTextCore>
9
+ </template>
10
+ </InputTextMaterialCore>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import type { InpuTextC12, IFormData } from '@/types/types.forms';
15
+
16
+ import propValidators from '../../../c12/prop-validators';
17
+
18
+ const props = defineProps({
19
+ size: {
20
+ type: String as PropType<string>,
21
+ default: 'normal',
22
+ validator(value: string) {
23
+ return propValidators.size.includes(value);
24
+ },
25
+ },
26
+ weight: {
27
+ type: String as PropType<string>,
28
+ default: 'wght-400',
29
+ validator(value: string) {
30
+ return propValidators.weight.includes(value);
31
+ },
32
+ },
33
+ theme: {
34
+ type: String as PropType<string>,
35
+ default: 'primary',
36
+ validator(value: string) {
37
+ return propValidators.theme.includes(value);
38
+ },
39
+ },
40
+ id: {
41
+ // type: String as PropType<string>,
42
+ type: String,
43
+ required: true,
44
+ },
45
+ name: {
46
+ type: String,
47
+ default: null,
48
+ },
49
+ validation: {
50
+ type: String,
51
+ default: '',
52
+ },
53
+ required: {
54
+ type: Boolean,
55
+ value: false,
56
+ },
57
+ c12: {
58
+ type: Object as PropType<InpuTextC12>,
59
+ required: true,
60
+ },
61
+ styleClassPassthrough: {
62
+ type: String,
63
+ default: '',
64
+ },
65
+ });
66
+
67
+ const name = computed(() => {
68
+ return props.name !== null ? props.name : props.id;
69
+ });
70
+
71
+ const modelValue = defineModel() as Ref<IFormData>;
72
+ </script>
@@ -0,0 +1,88 @@
1
+ <template>
2
+ <InputTextMaterialCore :type :id :name :required :c12 :styleClassPassthrough :theme v-model="modelValue">
3
+ <template #input>
4
+ <InputTextCore :id :name :type :validation :required v-model="modelValue" :c12 :style-class-passthrough="styleClassPassthrough">
5
+ <template #right>
6
+ <InputButtonCore @click.stop.prevent="toggleDisplayPassword" :is-pending="false" button-text="Submit" theme="ghost" size="x-small">
7
+ <template #iconOnly>
8
+ <Icon v-if="displayPassword" name="radix-icons:eye-none" class="icon" />
9
+ <Icon v-else name="radix-icons:eye-open" class="icon" />
10
+ </template>
11
+ </InputButtonCore>
12
+ </template>
13
+ </InputTextCore>
14
+ </template>
15
+ </InputTextMaterialCore>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import type { InpuTextC12, IFormData } from '@/types/types.forms';
20
+
21
+ import propValidators from '../../../c12/prop-validators';
22
+
23
+ const props = defineProps({
24
+ size: {
25
+ type: String as PropType<string>,
26
+ default: 'normal',
27
+ validator(value: string) {
28
+ return propValidators.size.includes(value);
29
+ },
30
+ },
31
+ weight: {
32
+ type: String as PropType<string>,
33
+ default: 'wght-400',
34
+ validator(value: string) {
35
+ return propValidators.weight.includes(value);
36
+ },
37
+ },
38
+ theme: {
39
+ type: String as PropType<string>,
40
+ default: 'primary',
41
+ validator(value: string) {
42
+ return propValidators.theme.includes(value);
43
+ },
44
+ },
45
+ id: {
46
+ // type: String as PropType<string>,
47
+ type: String,
48
+ required: true,
49
+ },
50
+ name: {
51
+ type: String,
52
+ default: null,
53
+ },
54
+ validation: {
55
+ type: String,
56
+ default: '',
57
+ },
58
+ required: {
59
+ type: Boolean,
60
+ value: false,
61
+ },
62
+ c12: {
63
+ type: Object as PropType<InpuTextC12>,
64
+ required: true,
65
+ },
66
+ styleClassPassthrough: {
67
+ type: String,
68
+ default: '',
69
+ },
70
+ });
71
+
72
+ const name = computed(() => {
73
+ return props.name !== null ? props.name : props.id;
74
+ });
75
+
76
+ const modelValue = defineModel() as Ref<IFormData>;
77
+
78
+ const displayPassword = ref(false);
79
+
80
+ const type = computed(() => {
81
+ // return displayPassword.value && !modelValue.value.isPending ? "text" : "password";
82
+ return displayPassword.value ? 'text' : 'password';
83
+ });
84
+
85
+ const toggleDisplayPassword = () => {
86
+ displayPassword.value = !displayPassword.value;
87
+ };
88
+ </script>
@@ -0,0 +1,75 @@
1
+ <template>
2
+ <InputTextMaterialCore :type :id :name :required :c12 :styleClassPassthrough :theme v-model="modelValue">
3
+ <template #input>
4
+ <InputTextCore :id :name type="text" :validation :required v-model="modelValue" :c12 :style-class-passthrough="styleClassPassthrough" />
5
+ </template>
6
+ </InputTextMaterialCore>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import type { InpuTextC12, IFormData } from '@/types/types.forms';
11
+
12
+ import propValidators from '../../../c12/prop-validators';
13
+
14
+ const props = defineProps({
15
+ size: {
16
+ type: String as PropType<string>,
17
+ default: 'normal',
18
+ validator(value: string) {
19
+ return propValidators.size.includes(value);
20
+ },
21
+ },
22
+ weight: {
23
+ type: String as PropType<string>,
24
+ default: 'wght-400',
25
+ validator(value: string) {
26
+ return propValidators.weight.includes(value);
27
+ },
28
+ },
29
+ theme: {
30
+ type: String as PropType<string>,
31
+ default: 'primary',
32
+ validator(value: string) {
33
+ return propValidators.theme.includes(value);
34
+ },
35
+ },
36
+ type: {
37
+ // type: String as PropType<"text" | "password" | "tel" | "number" | "email" | "url">, // This breaks props setup in unit tests
38
+ type: String,
39
+ validator(value: string) {
40
+ return ['text', 'password', 'tel', 'number', 'email', 'url'].includes(value);
41
+ },
42
+ },
43
+ id: {
44
+ // type: String as PropType<string>,
45
+ type: String,
46
+ required: true,
47
+ },
48
+ name: {
49
+ type: String,
50
+ default: null,
51
+ },
52
+ validation: {
53
+ type: String,
54
+ default: '',
55
+ },
56
+ required: {
57
+ type: Boolean,
58
+ value: false,
59
+ },
60
+ c12: {
61
+ type: Object as PropType<InpuTextC12>,
62
+ required: true,
63
+ },
64
+ styleClassPassthrough: {
65
+ type: String,
66
+ default: '',
67
+ },
68
+ });
69
+
70
+ const name = computed(() => {
71
+ return props.name !== null ? props.name : props.id;
72
+ });
73
+
74
+ const modelValue = defineModel() as Ref<IFormData>;
75
+ </script>