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
@@ -1,88 +0,0 @@
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>
@@ -1,75 +0,0 @@
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>
@@ -1,258 +0,0 @@
1
- <template>
2
- <div class="input-text-material" :class="[`theme-${theme}`, { error: fieldHasError }, { compact: compact }]">
3
- <label class="label" :class="[{ active: isFocused }, { error: fieldHasError }, { dirty: isDirty }, { compact: compact }]" :for="id">
4
- <span>{{ labelText }}</span>
5
- </label>
6
- <div class="input-text-container" :class="[{ active: isFocused }, { error: fieldHasError }, { dirty: isDirty }, { compact: compact }]">
7
- <slot name="input"></slot>
8
- </div>
9
- </div>
10
- </template>
11
-
12
- <script setup lang="ts">
13
- import type { InpuTextC12, IFormData } from '@/types/types.forms';
14
-
15
- import propValidators from '../../../c12/prop-validators';
16
-
17
- const props = defineProps({
18
- size: {
19
- type: String as PropType<string>,
20
- default: 'normal',
21
- validator(value: string) {
22
- return propValidators.size.includes(value);
23
- },
24
- },
25
- weight: {
26
- type: String as PropType<string>,
27
- default: 'wght-400',
28
- validator(value: string) {
29
- return propValidators.weight.includes(value);
30
- },
31
- },
32
- theme: {
33
- type: String as PropType<string>,
34
- default: 'primary',
35
- validator(value: string) {
36
- return propValidators.theme.includes(value);
37
- },
38
- },
39
- type: {
40
- type: String,
41
- validator(value: string) {
42
- return ['text', 'password', 'tel', 'number', 'email', 'url'].includes(value);
43
- },
44
- },
45
- id: {
46
- type: String,
47
- required: true,
48
- },
49
- name: {
50
- type: String,
51
- default: null,
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
- compact: {
66
- type: Boolean,
67
- value: false,
68
- },
69
- });
70
-
71
- const labelText = computed(() => {
72
- return fieldHasError.value ? errorMessage.value : props.c12.label;
73
- });
74
-
75
- const modelValue = defineModel() as Ref<IFormData>;
76
-
77
- const isFocused = computed(() => {
78
- return modelValue.value.focusedField == props.name;
79
- });
80
-
81
- const isDirty = computed(() => {
82
- return modelValue.value.dirtyFields[props.name];
83
- });
84
-
85
- const { errorMessage, setDefaultError, fieldHasError } = useErrorMessage(props.name, modelValue);
86
- setDefaultError(props.c12.errorMessage);
87
- </script>
88
-
89
- <style lang="css">
90
- .input-text-material {
91
- input {
92
- background-color: transparent;
93
- line-height: var(--line-height);
94
-
95
- &:focus {
96
- outline: none;
97
- box-shadow: none;
98
- border: none;
99
- }
100
-
101
- &:-internal-autofill-selected,
102
- &:autofill {
103
- background-color: transparent !important;
104
- }
105
- }
106
-
107
- label {
108
- margin: initial;
109
- line-height: var(--line-height);
110
- padding: initial;
111
- }
112
-
113
- --_gutter: 12px;
114
- --_form-theme: var(--theme-form-primary);
115
- --_border-width: var(--input-border-width-default);
116
-
117
- display: grid;
118
- border-radius: 2px;
119
- border: var(--_border-width) solid var(--_form-theme);
120
-
121
- margin-bottom: 20px;
122
- overflow: hidden;
123
-
124
- &.theme-secondary {
125
- --_form-theme: var(--theme-form-secondary);
126
- }
127
-
128
- &:focus-within {
129
- border: var(--_border-width) solid var(--_form-theme);
130
- outline: var(--_border-width) solid hsl(from var(--_form-theme) h s 50%);
131
- background-color: hsl(from var(--_form-theme) h s 95%);
132
- }
133
-
134
- &.error {
135
- /* outline: calc(var(--_border-width) * 2) solid var(--theme-error); */
136
-
137
- border: var(--_border-width) solid var(--theme-error);
138
- outline: var(--_border-width) solid hsl(from var(--theme-error) h s 75%);
139
-
140
- background-color: hsl(from var(--theme-error) h s 95%);
141
- }
142
-
143
- .label {
144
- grid-row: 1;
145
- grid-column: 1;
146
-
147
- font-family: var(--font-family);
148
- font-size: 20px;
149
- font-weight: 700;
150
- padding: var(--_gutter);
151
- transform: translateY(12px);
152
- transition: all linear 0.2s;
153
- background-color: transparent;
154
- z-index: 2;
155
-
156
- &.active,
157
- &.dirty,
158
- &.error {
159
- font-size: 16px;
160
- transform: translateY(-2px);
161
- z-index: auto;
162
- }
163
- }
164
-
165
- .input-text-container {
166
- display: grid;
167
- grid-row: 1;
168
- grid-column: 1;
169
- margin-top: 2rem;
170
- background-color: transparent;
171
- opacity: 0;
172
- transition: opacity linear 0.2s;
173
-
174
- &.active,
175
- &.dirty,
176
- &.error {
177
- opacity: 1;
178
- }
179
-
180
- .input-text {
181
- font-family: var(--font-family);
182
- border: 0px solid green;
183
- padding: calc(var(--_gutter) / 2) var(--_gutter);
184
- font-size: var(--font-size);
185
- margin: 0;
186
- /* opacity: 0;
187
- transition: opacity linear 0.2s;
188
-
189
- &.active,
190
- &.dirty {
191
- opacity: 1;
192
- } */
193
- /*
194
- &::placeholder,
195
- &:-ms-input-placeholder,
196
- &::-moz-placeholder, */
197
- &::-webkit-input-placeholder {
198
- font-family: var(--font-family);
199
- /* color: var(--gray-5); */
200
- color: hsl(from var(--_form-theme) h s 50%);
201
- font-size: var(--font-size);
202
- font-style: italic;
203
- font-weight: 500;
204
- }
205
- }
206
- }
207
- }
208
-
209
- /*
210
- * Compact UI
211
- **/
212
-
213
- .input-text-material {
214
- &.compact {
215
- overflow: initial;
216
-
217
- &:focus-within {
218
- background-color: initial;
219
- }
220
-
221
- &.error {
222
- background-color: initial;
223
- }
224
- }
225
-
226
- .label {
227
- &.compact {
228
- align-content: center;
229
- font-size: 16px;
230
- padding: 0 12px;
231
- transform: translateY(0);
232
-
233
- span {
234
- padding: 0 8px;
235
- }
236
-
237
- &.active,
238
- &.dirty,
239
- &.error {
240
- font-size: 16px;
241
- font-weight: 500;
242
- transform: translateY(-26px);
243
- z-index: auto;
244
-
245
- span {
246
- background-color: white;
247
- }
248
- }
249
- }
250
- }
251
-
252
- .input-text-container {
253
- &.compact {
254
- margin: 10px 8px 6px 8px;
255
- }
256
- }
257
- }
258
- </style>
@@ -1,29 +0,0 @@
1
- export const useUpdateStyleClassPassthrough = (classes: string) => {
2
- const styleClassPassthroughRef = ref(classes);
3
-
4
- function updateClasses(add: boolean, cssClass: string) {
5
- let classesArray = classes.split(' ');
6
-
7
- if (add && !classesArray.includes(cssClass)) {
8
- classesArray.push(cssClass);
9
- } else if (!add && classesArray.includes(cssClass)) {
10
- classesArray = classesArray.filter((className) => className !== cssClass);
11
- }
12
-
13
- // if (classesArray.includes(cssClass)) {
14
- // // Remove the value if it's already in the array
15
- // classesArray = classesArray.filter(className => className !== cssClass);
16
- // } else {
17
- // // Add the value if it's not in the array
18
- // classesArray.push(cssClass);
19
- // }
20
-
21
- // Join the array back into a string and assign it back
22
- styleClassPassthroughRef.value = classesArray.join(' ');
23
- }
24
-
25
- return {
26
- styleClassPassthroughRef,
27
- updateClasses,
28
- };
29
- };
@@ -1,136 +0,0 @@
1
- <template>
2
- <div>
3
- <NuxtLayout name="default">
4
- <template #layout-content>
5
- <div>
6
- <h1>Material UI text fields (compact)</h1>
7
- <p>Example test fields in "compact" material UI</p>
8
-
9
- <FormWrapper width="medium">
10
- <template #default>
11
- <form @submit.prevent="submitForm">
12
- <FormField width="wide" :has-gutter="true">
13
- <template #default>
14
- <InputEmailMaterial
15
- id="emailAddress"
16
- name="emailAddress"
17
- validation="emailaddress"
18
- :required="true"
19
- :c12="{
20
- label: 'Your Email Address',
21
- placeholder: 'eg. joe@example.com',
22
- errorMessage: 'Please enter a valid email address',
23
- }"
24
- v-model="formData"
25
- theme="secondary"
26
- :compact
27
- />
28
- </template>
29
- </FormField>
30
-
31
- <FormField width="wide" :has-gutter="true">
32
- <template #default>
33
- <InputTextMaterial
34
- id="username"
35
- name="username"
36
- validation="username"
37
- :required="true"
38
- :c12="{
39
- label: 'Your Username',
40
- placeholder: 'eg. YourUserName',
41
- errorMessage: 'Please enter a valid username',
42
- }"
43
- v-model="formData"
44
- theme="secondary"
45
- :compact
46
- />
47
- </template>
48
- </FormField>
49
-
50
- <FormField width="wide" :has-gutter="true">
51
- <template #default>
52
- <InputPasswordMaterial
53
- id="password"
54
- name="password"
55
- validation="password"
56
- :required="true"
57
- :c12="{
58
- label: 'Password',
59
- placeholder: 'eg. Your5illYPa55w0rd',
60
- errorMessage: 'Please enter a valid password',
61
- }"
62
- v-model="formData"
63
- theme="secondary"
64
- :compact
65
- />
66
- </template>
67
- </FormField>
68
-
69
- <FormField width="wide" :has-gutter="true">
70
- <template #default>
71
- <InputButtonSubmit @click.stop.prevent="submitForm" :is-pending="false" :readonly="submitDisabled" button-text="Submit" theme="secondary" size="medium" />
72
- </template>
73
- </FormField>
74
- </form>
75
- </template>
76
- </FormWrapper>
77
- </div>
78
- <ClientOnly>
79
- <p>Client only content</p>
80
- <pre>
81
- {{ formData }}
82
- </pre>
83
- </ClientOnly>
84
- </template>
85
- </NuxtLayout>
86
- </div>
87
- </template>
88
-
89
- <script setup lang="ts">
90
- import type { IFieldsInitialState, IOptionsConfig } from '@/types/types.forms';
91
-
92
- definePageMeta({
93
- layout: false,
94
- });
95
-
96
- useHead({
97
- title: 'Homepage',
98
- meta: [{ name: 'description', content: 'Homepage' }],
99
- bodyAttrs: {
100
- class: '',
101
- },
102
- });
103
-
104
- const compact = ref(true);
105
-
106
- /*
107
- * Setup forms
108
- */
109
- const fieldsInitialState = ref<IFieldsInitialState>({
110
- emailAddress: '',
111
- username: '',
112
- password: '',
113
- });
114
-
115
- // Setup formData
116
- const { formData, getErrorCount, updateCustomErrors, resetForm, formIsValid, submitDisabled } = useFormControl(fieldsInitialState);
117
-
118
- const submitForm = async () => {
119
- await getErrorCount(true);
120
-
121
- if (formIsValid.value) {
122
- formData.value.isPending = true;
123
- console.log('Form is good - post it!');
124
- // await useSleep(2000);
125
- // formData.value.isPending = false;
126
- } else {
127
- console.warn('Form has errors');
128
- }
129
- };
130
- </script>
131
-
132
- <style lang="css">
133
- p {
134
- color: initial;
135
- }
136
- </style>