srcdev-nuxt-forms 0.0.23 → 0.2.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 (64) hide show
  1. package/.prettierrc +2 -1
  2. package/LICENSE +21 -0
  3. package/assets/styles/forms/index.css +1 -0
  4. package/assets/styles/forms/themes/_error.css +9 -0
  5. package/assets/styles/forms/themes/_ghost.css +11 -0
  6. package/assets/styles/forms/themes/_primary.css +11 -1
  7. package/assets/styles/forms/themes/_secondary.css +13 -0
  8. package/assets/styles/forms/themes/_success.css +12 -0
  9. package/assets/styles/forms/themes/_tertiary.css +11 -0
  10. package/assets/styles/forms/themes/_warning.css +11 -0
  11. package/assets/styles/forms/themes/index.css +5 -0
  12. package/assets/styles/forms/utils/_a11y.css +5 -0
  13. package/assets/styles/forms/utils/index.css +1 -0
  14. package/assets/styles/forms/variables/_theme.css +56 -2
  15. package/assets/styles/variables/colors/_gray.css +1 -0
  16. package/assets/styles/variables/colors/_orange.css +1 -1
  17. package/assets/styles/variables/colors/_red.css +1 -1
  18. package/components/forms/c12/prop-validators/index.ts +13 -0
  19. package/components/forms/c12/utils.ts +14 -0
  20. package/components/forms/c12/validation-patterns/en.json +13 -1
  21. package/components/forms/form-errors/InputError.vue +132 -0
  22. package/components/forms/input-button/InputButtonCore.vue +370 -0
  23. package/components/forms/input-button/variants/InputButtonConfirm.vue +78 -0
  24. package/components/forms/input-button/variants/InputButtonSubmit.vue +74 -0
  25. package/components/forms/input-checkbox/InputCheckboxCore.vue +407 -0
  26. package/components/forms/input-checkbox/InputCheckboxWithLabel.vue +125 -0
  27. package/components/forms/input-checkbox/variants/MultipleCheckboxes.vue +194 -0
  28. package/components/forms/input-checkbox/variants/SingleCheckbox.vue +157 -0
  29. package/components/forms/input-radio/InputRadioCore.vue +226 -0
  30. package/components/forms/input-radio/InputRadioWithLabel.vue +118 -0
  31. package/components/forms/input-radio/variants/MultipleRadio.vue +183 -0
  32. package/components/forms/input-radio/variants/SingleRadio.vue +131 -0
  33. package/components/forms/input-range/InputRangeCore.vue +171 -0
  34. package/components/forms/input-range/variants/InputRangeDefault.vue +131 -0
  35. package/components/forms/input-text/InputTextCore.vue +115 -79
  36. package/components/forms/input-text/variants/material/InputEmailMaterial.vue +72 -0
  37. package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +114 -0
  38. package/components/forms/input-text/variants/material/InputTextMaterial.vue +68 -0
  39. package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +313 -0
  40. package/components/forms/input-textarea/InputTextareaCore.vue +170 -0
  41. package/components/forms/input-textarea/variants/material/InputTextareaMaterial.vue +75 -0
  42. package/components/forms/input-textarea/variants/material/InputTextareaMaterialCore.vue +290 -0
  43. package/components/forms/ui/FormField.vue +7 -2
  44. package/components/forms/ui/FormWrapper.vue +2 -2
  45. package/components/ui/content-grid/ContentGrid.vue +85 -0
  46. package/composables/useErrorMessages.ts +21 -9
  47. package/composables/useFormControl.ts +171 -41
  48. package/layouts/default.vue +28 -3
  49. package/nuxt.config.ts +26 -3
  50. package/package.json +9 -6
  51. package/pages/forms/examples/buttons/index.vue +155 -0
  52. package/pages/forms/examples/material/text-fields.vue +372 -0
  53. package/pages/index.vue +2 -70
  54. package/pages/limit-text.vue +43 -0
  55. package/server/api/places/list.get.ts +23 -0
  56. package/server/api/textFields.post.ts +37 -0
  57. package/server/api/utils/index.get.ts +20 -0
  58. package/server/data/places/cities.json +37 -0
  59. package/server/data/places/countries.json +55 -0
  60. package/server/data/utils/title.json +49 -0
  61. package/types/types.forms.ts +38 -13
  62. package/types/types.places.ts +8 -0
  63. package/components/forms/input-text/InputTextField.vue +0 -22
  64. package/components/forms/input-text/variants/InputTextMaterial.vue +0 -192
@@ -0,0 +1,407 @@
1
+ <template>
2
+ <div class="input-checkbox-wrapper" :class="[size, `theme-${theme}`, checkboxAppearance, { error: fieldHasError }]">
3
+ <input
4
+ type="checkbox"
5
+ :true-value="trueValue"
6
+ :false-value="falseValue"
7
+ :id
8
+ :name
9
+ :required="props.required && !props.multipleOptions"
10
+ :value="trueValue"
11
+ :class="['input-checkbox-core', `theme-${theme}`, size, checkboxAppearance, { error: fieldHasError }]"
12
+ v-model="modelValue.data[name]"
13
+ ref="inputField"
14
+ />
15
+ <div v-if="checkboxAppearance === 'with-decorator'" :class="['input-checkbox-decorator', size, checkboxStyle]">
16
+ <Icon name="material-symbols:check" class="icon-check" :class="[{ checked: isChecked }]" />
17
+ <div v-if="checkboxStyle === 'check' || checkboxStyle === 'cross'" :class="[checkboxStyle, { checked: isChecked }]"></div>
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import propValidators from '../c12/prop-validators';
24
+
25
+ import type { InpuTextC12, IFormFieldC12, IFormData } from '@/types/types.forms';
26
+ // import { validationConfig } from '@/components/forms/c12/validation-patterns';
27
+
28
+ const props = defineProps({
29
+ id: {
30
+ // type: String as PropType<string>,
31
+ type: String,
32
+ required: true,
33
+ },
34
+ name: {
35
+ type: String,
36
+ required: true,
37
+ },
38
+ required: {
39
+ type: Boolean,
40
+ value: false,
41
+ },
42
+ c12: {
43
+ type: Object as PropType<InpuTextC12>,
44
+ required: true,
45
+ },
46
+ trueValue: {
47
+ type: [String, Number, Boolean],
48
+ default: true,
49
+ },
50
+ falseValue: {
51
+ type: [String, Number, Boolean],
52
+ default: false,
53
+ },
54
+ multipleOptions: {
55
+ type: Boolean,
56
+ default: false,
57
+ },
58
+ styleClassPassthrough: {
59
+ type: String,
60
+ default: '',
61
+ },
62
+ theme: {
63
+ type: String as PropType<string>,
64
+ default: 'primary',
65
+ validator(value: string) {
66
+ return propValidators.theme.includes(value);
67
+ },
68
+ },
69
+ size: {
70
+ type: String as PropType<string>,
71
+ default: 'medium',
72
+ validator(value: string) {
73
+ return propValidators.size.includes(value);
74
+ },
75
+ },
76
+ checkboxAppearance: {
77
+ type: String as PropType<string>,
78
+ default: null,
79
+ validator(value: string) {
80
+ return propValidators.checkboxAppearance.includes(value);
81
+ },
82
+ },
83
+ checkboxStyle: {
84
+ type: String as PropType<string>,
85
+ default: 'check',
86
+ validator(value: string) {
87
+ return propValidators.checkboxStyle.includes(value);
88
+ },
89
+ },
90
+ });
91
+
92
+ const slots = useSlots();
93
+ const hasLeftContent = computed(() => slots.left !== undefined);
94
+ const hasRightContent = computed(() => slots.right !== undefined);
95
+
96
+ const modelValue = defineModel() as Ref<IFormData>;
97
+
98
+ // const updateFocus = (name: string, isFocused: boolean) => {
99
+ // modelValue.value.focusedField = isFocused ? name : '';
100
+ // };
101
+
102
+ // const isFocused = computed(() => {
103
+ // return modelValue.value.focusedField == name.value;
104
+ // });
105
+
106
+ const name = computed(() => {
107
+ return props.name !== null ? props.name : props.id;
108
+ });
109
+
110
+ // const validatorLocale = toRef(useRuntimeConfig().public.validatorLocale);
111
+
112
+ // const componentValidation = validationConfig[validatorLocale.value][props.validation];
113
+ const inputField = ref<HTMLInputElement | null>(null);
114
+
115
+ const isArray = Array.isArray(modelValue.value.data[name.value]);
116
+
117
+ const isChecked = computed(() => {
118
+ if (isArray) {
119
+ if (name.value in modelValue.value.data) {
120
+ const keyValue = modelValue.value.data[name.value] as any[];
121
+ const isValid = keyValue.indexOf(props.trueValue) > -1;
122
+ // modelValue.value.validityState[name.value] = isValid;
123
+ return isValid;
124
+ }
125
+ } else {
126
+ const isValid = modelValue.value.data[name.value] === props.trueValue;
127
+ modelValue.value.validityState[name.value] = isValid;
128
+ return isValid;
129
+ }
130
+ });
131
+
132
+ const isFocussed = ref(false);
133
+
134
+ // watch(isChecked, () => {
135
+ // console.log('inputField.value', inputField.value?.validity);
136
+ // });
137
+
138
+ // const fieldIsDirty = computed(() => {
139
+ // return modelValue.value!.formFieldsC12[name.value].isDirty;
140
+ // });
141
+ const fieldHasError = computed(() => {
142
+ return modelValue.value!.submitAttempted && !modelValue.value!.formFieldsC12[name.value].isValid;
143
+ });
144
+
145
+ // const { updateFieldValidity } = useFormControl(name.value);
146
+
147
+ if (
148
+ // !isArray &&
149
+ modelValue.value.formFieldsC12[name.value] === undefined
150
+ ) {
151
+ const formFieldC12 = <IFormFieldC12>{
152
+ label: props.c12.label,
153
+ placeholder: props.c12.placeholder,
154
+ errorMessage: props.c12.errorMessage,
155
+ useCustomError: false,
156
+ customErrors: {},
157
+ isValid: false,
158
+ isDirty: false,
159
+ type: isArray ? 'array' : 'string',
160
+ previousValue: null,
161
+ };
162
+ modelValue.value.formFieldsC12[name.value] = formFieldC12;
163
+ }
164
+
165
+ // const { initFormFieldsC12 } = useFormControl();
166
+ // initFormFieldsC12(props.name, formFieldC12);
167
+
168
+ const fieldValue = computed(() => {
169
+ return modelValue.value.data[name.value];
170
+ });
171
+
172
+ watch(fieldValue, () => {
173
+ if (isArray) {
174
+ // console.log(Object.values(modelValue.value.data[name.value] ?? []).length);
175
+ modelValue.value.validityState[name.value] = Object.values(modelValue.value.data[name.value] ?? []).length > 0;
176
+ modelValue.value!.formFieldsC12[name.value].isValid = modelValue.value.validityState[name.value];
177
+ // console.log(Object.keys(modelValue.value.data[name.value]).length);
178
+ // if (name.value in modelValue.value.data) {
179
+ // const keyValue = modelValue.value.data[name.value] as any[];
180
+ // const isValid = keyValue.indexOf(props.trueValue) > -1;
181
+ // modelValue.value.validityState[name.value] = isValid;
182
+ // }
183
+ } else {
184
+ // updateFieldValidity(name.value, inputField.value?.validity.valid ?? false);
185
+ if (!modelValue.value!.formFieldsC12[name.value].isDirty) {
186
+ modelValue.value!.formFieldsC12[name.value].isDirty = modelValue.value.data[name.value] !== '';
187
+ }
188
+ modelValue.value!.formFieldsC12[name.value].isValid = inputField.value?.validity.valid ?? false;
189
+ modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
190
+ }
191
+
192
+ // if (modelValue.value!.formFieldsC12[name.value].useCustomError && modelValue.value.data[props.name] === modelValue.value.formFieldsC12[props.name].previousValue) {
193
+ // modelValue.value!.validityState[name.value] = false;
194
+ // modelValue.value!.formFieldsC12[name.value].isValid = false;
195
+ // modelValue.value.displayErrorMessages = true;
196
+ // }
197
+ });
198
+
199
+ // const isValid = () => {
200
+ // setTimeout(() => {
201
+ // modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
202
+ // modelValue.value!.formFieldsC12[name.value].isValid = inputField.value?.validity.valid ?? false;
203
+ // if (!modelValue.value!.formFieldsC12[name.value].isDirty) {
204
+ // modelValue.value!.formFieldsC12[name.value].isDirty = modelValue.value.data[name.value] !== '';
205
+ // }
206
+ // }, 0);
207
+ // };
208
+
209
+ // onMounted(() => {
210
+ // isValid();
211
+ // });
212
+ </script>
213
+
214
+ <style scoped lang="css">
215
+ .input-checkbox-wrapper {
216
+ --_checkbox-size: initial;
217
+ --_checkbox-border-radius: 4px;
218
+ --_form-theme: var(--theme-form-primary);
219
+ --_outline-width: var(--input-outline-width-thin);
220
+ --_border-width: var(--input-border-width-thin);
221
+ --_border-color: var(--_form-theme);
222
+ --_focus-colour: var(--theme-form-primary-focus);
223
+
224
+ display: grid;
225
+ grid-template-areas: 'checkbox-stack';
226
+
227
+ &.theme-secondary {
228
+ --_form-theme: var(--theme-form-secondary);
229
+ --_focus-colour: var(--theme-form-secondary-focus);
230
+ }
231
+
232
+ &.error {
233
+ --_form-theme: var(--theme-error);
234
+ }
235
+
236
+ &.with-decorator {
237
+ border-radius: var(--_checkbox-border-radius);
238
+ border: var(--_border-width) solid var(--_border-color);
239
+ height: var(--_checkbox-size);
240
+ width: var(--_checkbox-size);
241
+
242
+ &:has(.input-checkbox-core:focus-visible) {
243
+ --_border-color: white;
244
+ box-shadow: 0 0 2px 3px var(--_focus-colour);
245
+ outline-color: var(--_focus-colour);
246
+ }
247
+ }
248
+
249
+ /* Sizes */
250
+ &.x-small {
251
+ --_checkbox-size: 20px;
252
+ }
253
+ &.small {
254
+ --_checkbox-size: 24px;
255
+ }
256
+ &.normal {
257
+ --_checkbox-size: 30px;
258
+ }
259
+ &.medium {
260
+ --_checkbox-size: 40px;
261
+ }
262
+ &.large {
263
+ --_checkbox-size: 44px;
264
+ }
265
+
266
+ .input-checkbox-decorator {
267
+ display: grid;
268
+ grid-area: checkbox-stack;
269
+
270
+ height: var(--_checkbox-size);
271
+ width: var(--_checkbox-size);
272
+ place-content: center;
273
+ position: relative;
274
+ z-index: -1;
275
+
276
+ :not(&.check),
277
+ :not(&.cross) {
278
+ .icon-check {
279
+ display: none;
280
+ }
281
+ }
282
+
283
+ .check {
284
+ grid-area: stack;
285
+ width: calc(var(--_checkbox-size) * 0.2);
286
+ height: calc(var(--_checkbox-size) * 0.45);
287
+ border-bottom: 3px solid var(--_form-theme);
288
+ border-right: 3px solid var(--_form-theme);
289
+ transform: rotate(45deg) translate(-1px, -1px);
290
+ /* transform: translate(-3px, 0px); */
291
+ opacity: 0;
292
+ transition: opacity 0.2s ease-in-out;
293
+
294
+ &.checked {
295
+ opacity: 1;
296
+ }
297
+ }
298
+
299
+ .cross {
300
+ grid-area: stack;
301
+ width: calc(var(--_checkbox-size) * 0.65);
302
+ height: 3px;
303
+ background-color: var(--_form-theme);
304
+ transform: rotate(45deg);
305
+ opacity: 0;
306
+ transition: opacity 0.2s ease-in-out;
307
+
308
+ &.checked {
309
+ opacity: 1;
310
+
311
+ &::after {
312
+ opacity: 1;
313
+ }
314
+ }
315
+
316
+ &::after {
317
+ content: '';
318
+ grid-area: stack;
319
+ display: block;
320
+ width: calc(var(--_checkbox-size) * 0.65);
321
+ height: 3px;
322
+ background-color: var(--_form-theme);
323
+ transform: rotate(-90deg);
324
+ opacity: 0;
325
+ transition: opacity 0.2s ease-in-out;
326
+ }
327
+ }
328
+
329
+ .icon-check {
330
+ grid-area: stack;
331
+ display: block;
332
+ height: var(--_checkbox-size);
333
+ width: var(--_checkbox-size);
334
+ transform: translate(-3px, 0px);
335
+ zoom: 0.75;
336
+ margin: 0;
337
+ opacity: 0;
338
+ padding: 0;
339
+ transition: opacity 0.2s ease-in-out;
340
+
341
+ &.checked {
342
+ opacity: 1;
343
+ }
344
+ }
345
+ }
346
+
347
+ .input-checkbox-core {
348
+ grid-area: checkbox-stack;
349
+ border: var(--_border-width) solid var(--_form-theme);
350
+ height: var(--_checkbox-size);
351
+ width: var(--_checkbox-size);
352
+
353
+ transition: all 0.2s ease-in-out;
354
+
355
+ &.with-decorator {
356
+ appearance: none;
357
+ margin: 0;
358
+ overflow: hidden;
359
+ opacity: 0;
360
+ }
361
+
362
+ &:hover {
363
+ cursor: pointer;
364
+ }
365
+
366
+ &:focus-visible {
367
+ border-radius: var(--input-border-radius);
368
+ }
369
+
370
+ &:focus {
371
+ border: var(--_border-width) solid var(--_form-theme);
372
+ outline: var(--_outline-width) solid hsl(from var(--_form-theme) h s 50%);
373
+ }
374
+
375
+ &:checked::after {
376
+ /* content: '✔'; */
377
+ display: grid;
378
+ font-family: var(--font-family);
379
+ place-content: center;
380
+ font-size: calc(var(--_checkbox-size) * 0.75);
381
+ }
382
+ &.error {
383
+ /* border-color: var(--theme-error); */
384
+ border: var(--_border-width) solid var(--theme-error);
385
+ outline: var(--_outline-width) solid hsl(from var(--theme-error) h s 75%);
386
+ background-color: hsl(from var(--theme-error) h s 95%);
387
+ }
388
+
389
+ &.theme-secondary {
390
+ --_form-theme: var(--theme-form-secondary);
391
+ }
392
+
393
+ /* &:valid {
394
+ border-color: var(--theme-success);
395
+ }
396
+ &:invalid {
397
+ border-color: var(--theme-error);
398
+ }
399
+ &:not(:placeholder-shown):valid {
400
+ border-color: var(--theme-success);
401
+ }
402
+ &:not(:placeholder-shown):invalid {
403
+ border-color: var(--theme-error);
404
+ } */
405
+ }
406
+ }
407
+ </style>
@@ -0,0 +1,125 @@
1
+ <template>
2
+ <div class="input-checkbox-with-label" :class="[styleClassPassthrough, `theme-${theme}`, { error: fieldHasError }]">
3
+ <InputCheckboxCore :id :name :required :c12 v-model="modelValue" :theme :size :trueValue :falseValue :checkboxAppearance :checkboxStyle />
4
+ <label class="input-checkbox-label" :for="id">{{ c12.label }}</label>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import propValidators from '../c12/prop-validators';
10
+
11
+ import type { InpuTextC12, IFormFieldC12, IFormData } from '@/types/types.forms';
12
+ // import { validationConfig } from '@/components/forms/c12/validation-patterns';
13
+
14
+ const props = defineProps({
15
+ id: {
16
+ // type: String as PropType<string>,
17
+ type: String,
18
+ required: true,
19
+ },
20
+ name: {
21
+ type: String,
22
+ required: true,
23
+ },
24
+ required: {
25
+ type: Boolean,
26
+ value: false,
27
+ },
28
+ c12: {
29
+ type: Object as PropType<InpuTextC12>,
30
+ required: true,
31
+ },
32
+ trueValue: {
33
+ type: [String, Number, Boolean],
34
+ default: true,
35
+ },
36
+ falseValue: {
37
+ type: [String, Number, Boolean],
38
+ default: false,
39
+ },
40
+ multipleOptions: {
41
+ type: Boolean,
42
+ default: false,
43
+ },
44
+ styleClassPassthrough: {
45
+ type: String,
46
+ default: '',
47
+ },
48
+ theme: {
49
+ type: String as PropType<string>,
50
+ default: 'primary',
51
+ validator(value: string) {
52
+ return propValidators.theme.includes(value);
53
+ },
54
+ },
55
+ size: {
56
+ type: String as PropType<string>,
57
+ default: 'medium',
58
+ validator(value: string) {
59
+ return propValidators.size.includes(value);
60
+ },
61
+ },
62
+ checkboxAppearance: {
63
+ type: String as PropType<string>,
64
+ default: null,
65
+ validator(value: string) {
66
+ return propValidators.checkboxAppearance.includes(value);
67
+ },
68
+ },
69
+ checkboxStyle: {
70
+ type: String as PropType<string>,
71
+ default: 'check',
72
+ validator(value: string) {
73
+ return propValidators.checkboxStyle.includes(value);
74
+ },
75
+ },
76
+ });
77
+
78
+ const slots = useSlots();
79
+ const hasLeftContent = computed(() => slots.left !== undefined);
80
+ const hasRightContent = computed(() => slots.right !== undefined);
81
+
82
+ const modelValue = defineModel() as Ref<IFormData>;
83
+ const name = computed(() => {
84
+ return props.name !== null ? props.name : props.id;
85
+ });
86
+ const fieldHasError = computed(() => {
87
+ return modelValue.value!.submitAttempted && !modelValue.value!.formFieldsC12[name.value].isValid;
88
+ });
89
+ </script>
90
+
91
+ <style lang="css">
92
+ .input-checkbox-with-label {
93
+ --_form-theme: var(--theme-form-primary);
94
+ --_border-width: var(--input-border-width-default);
95
+ --_outline-width: var(--input-outline-width-thin);
96
+ --_label-padding-inline: 10px;
97
+
98
+ display: flex;
99
+ align-items: center;
100
+
101
+ &.theme-secondary {
102
+ --_form-theme: var(--theme-form-secondary);
103
+ }
104
+
105
+ &.error {
106
+ --_form-theme: var(--theme-error);
107
+ }
108
+
109
+ .input-checkbox-label {
110
+ color: var(--_form-theme);
111
+ font-family: var(--font-family);
112
+ font-size: 14px;
113
+ font-weight: 500;
114
+ display: flex;
115
+ width: 100%;
116
+ height: 100%;
117
+ align-items: center;
118
+ padding-inline: var(--_label-padding-inline);
119
+
120
+ &:hover {
121
+ cursor: pointer;
122
+ }
123
+ }
124
+ }
125
+ </style>