srcdev-nuxt-forms 0.0.22 → 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.
- package/.prettierrc +2 -1
- package/assets/styles/forms/themes/_error.css +12 -0
- package/assets/styles/forms/themes/_ghost.css +11 -0
- package/assets/styles/forms/themes/_primary.css +9 -1
- package/assets/styles/forms/themes/_secondary.css +11 -0
- package/assets/styles/forms/themes/_success.css +12 -0
- package/assets/styles/forms/themes/_tertiary.css +11 -0
- package/assets/styles/forms/themes/_warning.css +11 -0
- package/assets/styles/forms/themes/index.css +6 -0
- package/assets/styles/forms/variables/_theme.css +64 -1
- package/assets/styles/variables/colors/_orange.css +1 -1
- package/assets/styles/variables/colors/_red.css +1 -1
- package/components/forms/c12/prop-validators/index.ts +25 -0
- package/components/forms/c12/validation-patterns/en.json +1 -1
- package/components/forms/input-button/InputButtonCore.vue +367 -0
- package/components/forms/input-button/variants/InputButtonConfirm.vue +78 -0
- package/components/forms/input-button/variants/InputButtonSubmit.vue +74 -0
- package/components/forms/input-text/InputTextCore.vue +77 -59
- package/components/forms/input-text/variants/material/InputEmailMaterial.vue +72 -0
- package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +88 -0
- package/components/forms/input-text/variants/material/InputTextMaterial.vue +75 -0
- package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +258 -0
- package/components/forms/ui/FormField.vue +7 -2
- package/components/forms/ui/FormWrapper.vue +2 -2
- package/composables/useErrorMessages.ts +4 -4
- package/composables/useFormControl.ts +36 -16
- package/composables/useUpdateStyleClassPassthrough.ts +29 -0
- package/layouts/default.vue +33 -2
- package/nuxt.config.ts +4 -3
- package/package.json +3 -1
- package/pages/forms/examples/buttons/index.vue +154 -0
- package/pages/forms/examples/material/text-fields-compact.vue +136 -0
- package/pages/forms/examples/material/text-fields.vue +136 -0
- package/pages/index.vue +2 -70
- package/types/types.forms.ts +6 -11
- package/components/forms/input-text/InputTextField.vue +0 -22
- package/components/forms/input-text/variants/InputTextMaterial.vue +0 -159
|
@@ -0,0 +1,258 @@
|
|
|
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,6 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="form-field" :class="[width, { 'has-gutter': hasGutter }]">
|
|
3
|
-
<h1>FormField.vue</h1>
|
|
2
|
+
<div class="form-field" :class="[width, styleClassPassthrough, { 'has-gutter': hasGutter }]">
|
|
4
3
|
<slot name="default"></slot>
|
|
5
4
|
</div>
|
|
6
5
|
</template>
|
|
@@ -16,6 +15,10 @@ defineProps({
|
|
|
16
15
|
type: Boolean as PropType<boolean>,
|
|
17
16
|
default: true,
|
|
18
17
|
},
|
|
18
|
+
styleClassPassthrough: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: '',
|
|
21
|
+
},
|
|
19
22
|
});
|
|
20
23
|
</script>
|
|
21
24
|
|
|
@@ -25,6 +28,8 @@ defineProps({
|
|
|
25
28
|
--_max-width: 400px;
|
|
26
29
|
|
|
27
30
|
margin-inline: auto;
|
|
31
|
+
margin-bottom: 16px;
|
|
32
|
+
|
|
28
33
|
width: min(100% - calc(2 * var(--_gutter-width)), var(--_max-width));
|
|
29
34
|
outline: 0px solid var(--gray-5);
|
|
30
35
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="form-wrapper" :class="width">
|
|
3
|
-
<h1>FormWrapper.vue</h1>
|
|
4
3
|
<slot name="default"></slot>
|
|
5
4
|
</div>
|
|
6
5
|
</template>
|
|
@@ -17,7 +16,8 @@ defineProps({
|
|
|
17
16
|
|
|
18
17
|
<style lang="css">
|
|
19
18
|
.form-wrapper {
|
|
20
|
-
outline:
|
|
19
|
+
outline: 0px solid var(--gray-12);
|
|
20
|
+
padding-bottom: 20px;
|
|
21
21
|
|
|
22
22
|
&.narrow {
|
|
23
23
|
max-width: 400px;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { IFormData } from
|
|
1
|
+
import type { IFormData } from '@/types/types.forms';
|
|
2
2
|
|
|
3
3
|
export function useErrorMessage(name: string, formData: Ref<IFormData>) {
|
|
4
|
-
const defaultError = ref(
|
|
4
|
+
const defaultError = ref('');
|
|
5
5
|
const customErrorMessages = ref(toRaw(formData.value.customErrorMessages));
|
|
6
6
|
|
|
7
7
|
const hasCustomError = () => {
|
|
@@ -21,7 +21,7 @@ export function useErrorMessage(name: string, formData: Ref<IFormData>) {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const fieldHasError = computed(() => {
|
|
24
|
-
if (formData.value.
|
|
24
|
+
if (formData.value.submitDisabled) {
|
|
25
25
|
if (hasCustomError()) {
|
|
26
26
|
return true;
|
|
27
27
|
} else if (Object.keys(formData.value.validityState).length > 0 && formData.value.validityState[name] !== undefined) {
|
|
@@ -42,6 +42,6 @@ export function useErrorMessage(name: string, formData: Ref<IFormData>) {
|
|
|
42
42
|
errorMessage,
|
|
43
43
|
setDefaultError,
|
|
44
44
|
fieldHasError,
|
|
45
|
-
removeCustomError
|
|
45
|
+
removeCustomError,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IFormData, IFieldsInitialState, ICustomErrorMessage, ICustomErrorMessagesArr } from
|
|
1
|
+
import type { IFormData, IFieldsInitialState, ICustomErrorMessage, ICustomErrorMessagesArr } from '@/types/types.forms';
|
|
2
2
|
|
|
3
3
|
export function useFormControl(fieldsInitialState: IFieldsInitialState | Ref<IFieldsInitialState | null>) {
|
|
4
4
|
let savedInitialState = {};
|
|
@@ -6,13 +6,15 @@ export function useFormControl(fieldsInitialState: IFieldsInitialState | Ref<IFi
|
|
|
6
6
|
const formData = ref<IFormData>({
|
|
7
7
|
data: {} as IFieldsInitialState,
|
|
8
8
|
validityState: {},
|
|
9
|
+
dirtyFields: {},
|
|
10
|
+
focusedField: '',
|
|
9
11
|
isPending: false,
|
|
10
12
|
errorCount: 0,
|
|
11
13
|
customErrorMessages: {},
|
|
12
14
|
hasCustomErrorMessages: false,
|
|
13
15
|
formIsValid: false,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
submitSuccess: false,
|
|
17
|
+
submitDisabled: false,
|
|
16
18
|
});
|
|
17
19
|
|
|
18
20
|
const initValidationState = async () => {
|
|
@@ -34,12 +36,21 @@ export function useFormControl(fieldsInitialState: IFieldsInitialState | Ref<IFi
|
|
|
34
36
|
return;
|
|
35
37
|
};
|
|
36
38
|
|
|
37
|
-
const getErrorCount = async () => {
|
|
39
|
+
const getErrorCount = async (updateState: boolean = false) => {
|
|
38
40
|
await nextTick();
|
|
39
41
|
|
|
40
42
|
const errorCount = Object.values(formData.value.validityState).filter((value) => !value).length;
|
|
41
43
|
formData.value.errorCount = errorCount;
|
|
42
44
|
formData.value.formIsValid = errorCount === 0;
|
|
45
|
+
|
|
46
|
+
if (updateState) {
|
|
47
|
+
formData.value.submitDisabled = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (formData.value.submitDisabled) {
|
|
51
|
+
formData.value.submitDisabled = !formData.value.formIsValid;
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
return formData.value.errorCount;
|
|
44
55
|
};
|
|
45
56
|
|
|
@@ -73,7 +84,7 @@ export function useFormControl(fieldsInitialState: IFieldsInitialState | Ref<IFi
|
|
|
73
84
|
formData.value.validityState[name] = valid;
|
|
74
85
|
formData.value.customErrorMessages[name] = {
|
|
75
86
|
useCustomError: true,
|
|
76
|
-
message
|
|
87
|
+
message,
|
|
77
88
|
};
|
|
78
89
|
}
|
|
79
90
|
formData.value.hasCustomErrorMessages = countItemsWithCustomError(formData.value.customErrorMessages) > 0;
|
|
@@ -88,15 +99,20 @@ export function useFormControl(fieldsInitialState: IFieldsInitialState | Ref<IFi
|
|
|
88
99
|
formData.value.formIsValid = false;
|
|
89
100
|
};
|
|
90
101
|
|
|
91
|
-
const showErrors = computed(() => {
|
|
92
|
-
return formData.value.errorCount > 0 && formData.value.isPending;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
102
|
const formIsValid = computed(() => {
|
|
96
103
|
return formData.value.errorCount === 0;
|
|
97
104
|
});
|
|
98
105
|
|
|
106
|
+
const submitDisabled = computed(() => {
|
|
107
|
+
return formData.value.submitDisabled;
|
|
108
|
+
});
|
|
109
|
+
|
|
99
110
|
// Keep an eye on this for performance issue
|
|
111
|
+
|
|
112
|
+
watchEffect(() => {
|
|
113
|
+
console.log('watchEffect: formData.value', formData.value.validityState);
|
|
114
|
+
});
|
|
115
|
+
|
|
100
116
|
watch(
|
|
101
117
|
() => formData.value.validityState,
|
|
102
118
|
() => {
|
|
@@ -105,12 +121,16 @@ export function useFormControl(fieldsInitialState: IFieldsInitialState | Ref<IFi
|
|
|
105
121
|
{ deep: true }
|
|
106
122
|
);
|
|
107
123
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// console.log("savedInitialState UPDATED", savedInitialState);
|
|
112
|
-
// }
|
|
113
|
-
// );
|
|
124
|
+
onMounted(() => {
|
|
125
|
+
initFormData();
|
|
126
|
+
});
|
|
114
127
|
|
|
115
|
-
return {
|
|
128
|
+
return {
|
|
129
|
+
formData,
|
|
130
|
+
getErrorCount,
|
|
131
|
+
updateCustomErrors,
|
|
132
|
+
resetForm,
|
|
133
|
+
formIsValid,
|
|
134
|
+
submitDisabled,
|
|
135
|
+
};
|
|
116
136
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
};
|
package/layouts/default.vue
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="page-layout">
|
|
3
3
|
<div>
|
|
4
|
-
<h1>
|
|
4
|
+
<h1><NuxtLink to="/">Home</NuxtLink></h1>
|
|
5
|
+
<ul class="flex-group">
|
|
6
|
+
<li>
|
|
7
|
+
<NuxtLink to="/forms/examples/material/text-fields"
|
|
8
|
+
>Material UI text fields</NuxtLink
|
|
9
|
+
>
|
|
10
|
+
</li>
|
|
11
|
+
<li>
|
|
12
|
+
<NuxtLink to="/forms/examples/material/text-fields-compact"
|
|
13
|
+
>Material UI text fields (compact)</NuxtLink
|
|
14
|
+
>
|
|
15
|
+
</li>
|
|
16
|
+
</ul>
|
|
5
17
|
</div>
|
|
18
|
+
<h2>Buttons</h2>
|
|
19
|
+
<ul class="flex-group">
|
|
20
|
+
<li>
|
|
21
|
+
<NuxtLink to="/forms/examples/buttons">Buttons</NuxtLink>
|
|
22
|
+
</li>
|
|
23
|
+
</ul>
|
|
6
24
|
|
|
7
25
|
<div>
|
|
8
26
|
<slot name="layout-content"></slot>
|
|
@@ -20,7 +38,7 @@ useHead({
|
|
|
20
38
|
class: 'body-default',
|
|
21
39
|
id: 'body',
|
|
22
40
|
},
|
|
23
|
-
})
|
|
41
|
+
});
|
|
24
42
|
</script>
|
|
25
43
|
|
|
26
44
|
<style lang="css">
|
|
@@ -28,4 +46,17 @@ useHead({
|
|
|
28
46
|
display: grid;
|
|
29
47
|
grid-template-rows: auto 1fr auto;
|
|
30
48
|
}
|
|
49
|
+
|
|
50
|
+
.flex-group {
|
|
51
|
+
align-items: flex-start;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-wrap: wrap;
|
|
54
|
+
gap: 24px;
|
|
55
|
+
margin-bottom: 32px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ul.flex-group {
|
|
59
|
+
list-style-type: none;
|
|
60
|
+
padding: 0;
|
|
61
|
+
}
|
|
31
62
|
</style>
|
package/nuxt.config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
2
|
-
import { createResolver } from '@nuxt/kit'
|
|
3
|
-
const { resolve } = createResolver(import.meta.url)
|
|
2
|
+
import { createResolver } from '@nuxt/kit';
|
|
3
|
+
const { resolve } = createResolver(import.meta.url);
|
|
4
4
|
|
|
5
5
|
export default defineNuxtConfig({
|
|
6
6
|
devtools: { enabled: true },
|
|
@@ -11,10 +11,11 @@ export default defineNuxtConfig({
|
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
|
|
14
|
+
modules: ['@nuxt/icon'],
|
|
14
15
|
components: [
|
|
15
16
|
{
|
|
16
17
|
path: './components',
|
|
17
18
|
pathPrefix: false,
|
|
18
19
|
},
|
|
19
20
|
],
|
|
20
|
-
})
|
|
21
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srcdev-nuxt-forms",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"reinstall": "rm -rf node_modules && npm install",
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"release": "release-it"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
+
"@iconify-json/material-symbols": "^1.1.83",
|
|
17
18
|
"@nuxt/eslint-config": "^0.3.13",
|
|
19
|
+
"@nuxt/icon": "^1.0.0",
|
|
18
20
|
"eslint": "^9.5.0",
|
|
19
21
|
"nuxt": "^3.12.2",
|
|
20
22
|
"release-it": "^17.4.0",
|