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,370 @@
1
+ <template>
2
+ <button
3
+ :type="type"
4
+ :readonly
5
+ :aria-disabled="readonly"
6
+ :data-test-id="dataTestId"
7
+ class="input-button-core btn"
8
+ :class="[`btn-${type}`, `theme-${theme}`, size, effectClass, styleClassPassthrough, { 'icon-only': isIconOnly }]"
9
+ >
10
+ <span v-if="useEffect && effect == 'fancy'" class="fancy"></span>
11
+ <template v-if="hasLeftContent && !isIconOnly">
12
+ <span class="btn-icon left" :class="[size]">
13
+ <slot name="left"></slot>
14
+ </span>
15
+ </template>
16
+ <span class="btn-text" :class="[size, weight, { 'sr-only': isIconOnly }]">{{ buttonText }}</span>
17
+ <template v-if="hasRightContent && !isIconOnly">
18
+ <span class="btn-icon right">
19
+ <slot name="right"></slot>
20
+ </span>
21
+ </template>
22
+ <template v-if="isIconOnly">
23
+ <span class="btn-icon icon-only" :class="[size]">
24
+ <slot name="iconOnly"></slot>
25
+ </span>
26
+ </template>
27
+ </button>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import propValidators from '../c12/prop-validators';
32
+
33
+ const props = defineProps({
34
+ size: {
35
+ type: String as PropType<string>,
36
+ default: 'normal',
37
+ validator(value: string) {
38
+ return propValidators.size.includes(value);
39
+ },
40
+ },
41
+ weight: {
42
+ type: String as PropType<string>,
43
+ default: 'wght-400',
44
+ validator(value: string) {
45
+ return propValidators.weight.includes(value);
46
+ },
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
+ type: {
56
+ type: String as PropType<'submit' | 'button' | 'reset'>,
57
+ default: 'button',
58
+ validator(value: string) {
59
+ return propValidators.inputTypesButton.includes(value);
60
+ },
61
+ },
62
+ buttonText: {
63
+ type: String,
64
+ required: true,
65
+ },
66
+ dataTestId: {
67
+ type: String,
68
+ default: '',
69
+ },
70
+ styleClassPassthrough: {
71
+ type: String,
72
+ default: '',
73
+ },
74
+ useEffect: {
75
+ type: Boolean,
76
+ default: false,
77
+ },
78
+ effect: {
79
+ type: String as PropType<string>,
80
+ default: 'fancy',
81
+ validator(value: string) {
82
+ return ['fancy', 'pulse'].includes(value);
83
+ },
84
+ },
85
+ isPending: {
86
+ type: Boolean,
87
+ default: false,
88
+ },
89
+ readonly: {
90
+ type: Boolean,
91
+ default: false,
92
+ },
93
+ });
94
+
95
+ const type = toRef(() => props.type);
96
+ const effectClass = computed(() => {
97
+ if (props.useEffect) {
98
+ return props.effect === 'fancy' ? '' : props.effect;
99
+ } else {
100
+ return '';
101
+ }
102
+ });
103
+
104
+ const slots = useSlots();
105
+ const hasLeftContent = computed(() => slots.left !== undefined);
106
+ const hasRightContent = computed(() => slots.right !== undefined);
107
+ const isIconOnly = computed(() => slots.iconOnly !== undefined);
108
+ </script>
109
+
110
+ <style lang="css">
111
+ .btn {
112
+ --_padding-block: var(--theme-form-button-padding-block-normal);
113
+ --_padding-inline: var(--theme-form-button-padding-inline-normal);
114
+ --_icon-gap: var(--theme-form-button-icon-gap-normal);
115
+
116
+ align-items: center;
117
+ display: flex;
118
+ gap: var(--_icon-gap);
119
+ justify-content: center;
120
+ border: none;
121
+ border-radius: var(--input-border-radius);
122
+ font-family: var(--font-family);
123
+
124
+ padding-inline: var(--_padding-inline);
125
+ padding-block: var(--_padding-block);
126
+
127
+ transition: all 0.2s ease-in-out;
128
+
129
+ &:hover {
130
+ cursor: pointer;
131
+ }
132
+
133
+ &:focus-visible {
134
+ outline: var(--focus-visible-outline);
135
+ box-shadow: var(--focus-visible-box-shadow);
136
+ }
137
+
138
+ &[readonly] {
139
+ opacity: 0.5;
140
+ &:hover,
141
+ &:focus-visible {
142
+ cursor: not-allowed;
143
+ }
144
+ }
145
+
146
+ &.x-small {
147
+ &:not(.icon-only) {
148
+ --_padding-block: var(--theme-form-button-padding-block-x-small);
149
+ --_padding-inline: var(--theme-form-button-padding-inline-x-small);
150
+ --_icon-gap: var(--theme-form-button-icon-gap-x-small);
151
+ }
152
+ &.icon-only {
153
+ --_padding-block: var(--theme-form-button-padding-block-icon-only-x-small);
154
+ --_padding-inline: var(--theme-form-button-padding-inline-icon-only-x-small);
155
+ }
156
+ }
157
+
158
+ &.small {
159
+ &:not(.icon-only) {
160
+ --_padding-block: var(--theme-form-button-padding-block-x-small);
161
+ --_padding-inline: var(--theme-form-button-padding-inline-small);
162
+ --_icon-gap: var(--theme-form-button-icon-gap-small);
163
+ }
164
+ &.icon-only {
165
+ --_padding-block: var(--theme-form-button-padding-block-icon-only-small);
166
+ --_padding-inline: var(--theme-form-button-padding-inline-icon-only-small);
167
+ }
168
+ }
169
+ &.normal {
170
+ &:not(.icon-only) {
171
+ --_padding-block: var(--theme-form-button-padding-block-x-small);
172
+ --_padding-inline: var(--theme-form-button-padding-inline-normal);
173
+ --_icon-gap: var(--theme-form-button-icon-gap-normal);
174
+ }
175
+ &.icon-only {
176
+ --_padding-block: var(--theme-form-button-padding-block-icon-only-normal);
177
+ --_padding-inline: var(--theme-form-button-padding-inline-icon-only-normal);
178
+ }
179
+ }
180
+ &.medium {
181
+ &:not(.icon-only) {
182
+ --_padding-block: var(--theme-form-button-padding-block-x-small);
183
+ --_padding-inline: var(--theme-form-button-padding-inline-medium);
184
+ --_icon-gap: var(--theme-form-button-icon-gap-medium);
185
+ }
186
+ &.icon-only {
187
+ --_padding-block: var(--theme-form-button-padding-block-icon-only-medium);
188
+ --_padding-inline: var(--theme-form-button-padding-inline-icon-only-medium);
189
+ }
190
+ }
191
+
192
+ &.large {
193
+ &:not(.icon-only) {
194
+ --_padding-block: var(--theme-form-button-padding-block-x-small);
195
+ --_padding-inline: var(--theme-form-button-padding-inline-large);
196
+ --_icon-gap: var(--theme-form-button-icon-gap-large);
197
+ }
198
+ &.icon-only {
199
+ --_padding-block: var(--theme-form-button-padding-block-icon-only-large);
200
+ --_padding-inline: var(--theme-form-button-padding-inline-icon-only-large);
201
+ }
202
+ }
203
+
204
+ .btn-text {
205
+ &.small {
206
+ font-size: var(--theme-form-button-font-size-small);
207
+ }
208
+ &.normal {
209
+ font-size: var(--theme-form-button-font-size-normal);
210
+ }
211
+ &.medium {
212
+ font-size: var(--theme-form-button-font-size-medium);
213
+ }
214
+
215
+ &.large {
216
+ font-size: var(--theme-form-button-font-size-large);
217
+ }
218
+
219
+ &.sr-only {
220
+ position: absolute;
221
+ clip: rect(1px, 1px, 1px, 1px);
222
+ clip-path: inset(50%);
223
+ height: 1px;
224
+ width: 1px;
225
+ overflow: hidden;
226
+ white-space: nowrap;
227
+ }
228
+ }
229
+
230
+ .btn-icon {
231
+ display: flex;
232
+ .icon {
233
+ aspect-ratio: 1;
234
+ display: inline-block;
235
+ }
236
+
237
+ &.x-small {
238
+ .icon {
239
+ height: var(--theme-form-button-icon-size-small);
240
+ width: var(--theme-form-button-icon-size-small);
241
+ }
242
+ }
243
+ &.small {
244
+ .icon {
245
+ height: var(--theme-form-button-icon-size-small);
246
+ width: var(--theme-form-button-icon-size-small);
247
+ }
248
+ }
249
+ &.normal {
250
+ .icon {
251
+ height: var(--theme-form-button-icon-size-normal);
252
+ width: var(--theme-form-button-icon-size-normal);
253
+ }
254
+ }
255
+ &.medium {
256
+ .icon {
257
+ height: var(--theme-form-button-icon-size-medium);
258
+ width: var(--theme-form-button-icon-size-medium);
259
+ }
260
+ }
261
+
262
+ &.large {
263
+ .icon {
264
+ height: var(--theme-form-button-icon-size-large);
265
+ width: var(--theme-form-button-icon-size-large);
266
+ }
267
+ }
268
+ }
269
+
270
+ --_border-width: var(--input-border-width-default);
271
+ --_outline-width: var(--input-outline-width-thin);
272
+
273
+ /*
274
+ * Initial theme (primary)
275
+ **/
276
+ --_theme-form-border: var(--theme-form-primary-border);
277
+ --_theme-form-border-hover: var(--theme-form-primary-border-hover);
278
+ --_theme-form-outline: var(--theme-form-primary-outline);
279
+ --_theme-form-outline-hover: var(--theme-form-primary-outline-hover);
280
+ --_theme-form-bg: var(--theme-form-primary-bg);
281
+ --_theme-form-bg-hover: var(--theme-form-primary-bg-hover);
282
+ --_theme-form-color: var(--theme-form-primary-color);
283
+ --_theme-form-color-hover: var(--theme-form-primary-color-hover);
284
+
285
+ background-color: var(--_theme-form-bg);
286
+ border: var(--_border-width) solid var(--_theme-form-border);
287
+ color: var(--_theme-form-color);
288
+ outline: 1px solid var(--_theme-form-outline);
289
+
290
+ /*
291
+ * Themes (alternate)
292
+ **/
293
+ &.theme-secondary {
294
+ --_theme-form-border: var(--theme-form-secondary-border);
295
+ --_theme-form-border-hover: var(--theme-form-secondary-border-hover);
296
+ --_theme-form-outline: var(--theme-form-secondary-outline);
297
+ --_theme-form-outline-hover: var(--theme-form-secondary-outline-hover);
298
+ --_theme-form-bg: var(--theme-form-secondary-bg);
299
+ --_theme-form-bg-hover: var(--theme-form-secondary-bg-hover);
300
+ --_theme-form-color: var(--theme-form-secondary-color);
301
+ --_theme-form-color-hover: var(--theme-form-secondary-color-hover);
302
+ }
303
+
304
+ &.theme-tertiary {
305
+ --_theme-form-border: var(--theme-form-tertiary-border);
306
+ --_theme-form-border-hover: var(--theme-form-tertiary-border-hover);
307
+ --_theme-form-outline: var(--theme-form-tertiary-outline);
308
+ --_theme-form-outline-hover: var(--theme-form-tertiary-outline-hover);
309
+ --_theme-form-bg: var(--theme-form-tertiary-bg);
310
+ --_theme-form-bg-hover: var(--theme-form-tertiary-bg-hover);
311
+ --_theme-form-color: var(--theme-form-tertiary-color);
312
+ --_theme-form-color-hover: var(--theme-form-tertiary-color-hover);
313
+ }
314
+
315
+ &.theme-warning {
316
+ --_theme-form-border: var(--theme-form-warning-border);
317
+ --_theme-form-border-hover: var(--theme-form-warning-border-hover);
318
+ --_theme-form-outline: var(--theme-form-warning-outline);
319
+ --_theme-form-outline-hover: var(--theme-form-warning-outline-hover);
320
+ --_theme-form-bg: var(--theme-form-warning-bg);
321
+ --_theme-form-bg-hover: var(--theme-form-warning-bg-hover);
322
+ --_theme-form-color: var(--theme-form-warning-color);
323
+ --_theme-form-color-hover: var(--theme-form-warning-color-hover);
324
+ }
325
+
326
+ &.theme-error {
327
+ --_theme-form-border: var(--theme-form-error-border);
328
+ --_theme-form-border-hover: var(--theme-form-error-border-hover);
329
+ --_theme-form-outline: var(--theme-form-error-outline);
330
+ --_theme-form-outline-hover: var(--theme-form-error-outline-hover);
331
+ --_theme-form-bg: var(--theme-form-error-bg);
332
+ --_theme-form-bg-hover: var(--theme-form-error-bg-hover);
333
+ --_theme-form-color: var(--theme-form-error-color);
334
+ --_theme-form-color-hover: var(--theme-form-error-color-hover);
335
+ }
336
+
337
+ &.theme-success {
338
+ --_theme-form-border: var(--theme-form-success-border);
339
+ --_theme-form-border-hover: var(--theme-form-success-border-hover);
340
+ --_theme-form-outline: var(--theme-form-success-outline);
341
+ --_theme-form-outline-hover: var(--theme-form-success-outline-hover);
342
+ --_theme-form-bg: var(--theme-form-success-bg);
343
+ --_theme-form-bg-hover: var(--theme-form-success-bg-hover);
344
+ --_theme-form-color: var(--theme-form-success-color);
345
+ --_theme-form-color-hover: var(--theme-form-success-color-hover);
346
+ }
347
+
348
+ &.theme-ghost {
349
+ --_theme-form-border: var(--theme-form-ghost-border);
350
+ --_theme-form-border-hover: var(--theme-form-ghost-border-hover);
351
+ --_theme-form-outline: var(--theme-form-ghost-outline);
352
+ --_theme-form-outline-hover: var(--theme-form-ghost-outline-hover);
353
+ --_theme-form-bg: var(--theme-form-ghost-bg);
354
+ --_theme-form-bg-hover: var(--theme-form-ghost-bg-hover);
355
+ --_theme-form-color: var(--theme-form-ghost-color);
356
+ --_theme-form-color-hover: var(--theme-form-ghost-color-hover);
357
+ }
358
+
359
+ /*
360
+ * States
361
+ **/
362
+ &:hover,
363
+ &:focus-visible {
364
+ --_theme-form-color: var(--_theme-form-color-hover);
365
+ --_theme-form-bg: var(--_theme-form-bg-hover);
366
+ --_theme-form-border: var(--_theme-form-border-hover);
367
+ --_theme-form-outline: var(--_theme-form-outline-hover);
368
+ }
369
+ }
370
+ </style>
@@ -0,0 +1,78 @@
1
+ <template>
2
+ <InputButtonCore
3
+ type="button"
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 #left>
16
+ <Icon name="material-symbols:check-circle-outline" class="icon" />
17
+ </template>
18
+ </InputButtonCore>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import propValidators from '../../c12/prop-validators';
23
+
24
+ const props = defineProps({
25
+ size: {
26
+ type: String as PropType<string>,
27
+ default: 'normal',
28
+ validator(value: string) {
29
+ return propValidators.size.includes(value);
30
+ },
31
+ },
32
+ weight: {
33
+ type: String as PropType<string>,
34
+ default: 'wght-400',
35
+ validator(value: string) {
36
+ return propValidators.weight.includes(value);
37
+ },
38
+ },
39
+ theme: {
40
+ type: String as PropType<string>,
41
+ default: 'primary',
42
+ validator(value: string) {
43
+ return propValidators.theme.includes(value);
44
+ },
45
+ },
46
+ useEffect: {
47
+ type: Boolean,
48
+ default: false,
49
+ },
50
+ effect: {
51
+ type: String as PropType<string>,
52
+ default: 'fancy',
53
+ validator(value: string) {
54
+ return ['fancy', 'pulse'].includes(value);
55
+ },
56
+ },
57
+ buttonText: {
58
+ type: String,
59
+ required: true,
60
+ },
61
+ dataTestId: {
62
+ type: String,
63
+ default: '',
64
+ },
65
+ styleClassPassthrough: {
66
+ type: String,
67
+ default: '',
68
+ },
69
+ isPending: {
70
+ type: Boolean,
71
+ default: false,
72
+ },
73
+ readonly: {
74
+ type: Boolean,
75
+ default: false,
76
+ },
77
+ });
78
+ </script>
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <InputButtonCore
3
+ type="button"
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>