srcdev-nuxt-forms 6.0.1 → 6.1.1
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/README.md +45 -5
- package/app/assets/styles/extends-layer/srcdev-forms/components/_form-fieldset.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-button.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-checkbox-radio-core.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-checkbox-radio-options-button.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-error.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-label.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-select.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-text.css +1 -1
- package/app/assets/styles/extends-layer/srcdev-forms/components/_input-textarea.css +1 -1
- package/app/assets/styles/setup/_head.css +1 -1
- package/app/assets/styles/setup/typography/vars/_reponsive-font-sizes.css +10 -10
- package/app/assets/styles/setup/typography/vars/index.css +0 -1
- package/app/components/forms/form-fieldset/FormFieldset.vue +19 -10
- package/app/components/forms/input-button/InputButtonCore.vue +25 -28
- package/app/components/forms/input-checkbox/MultipleCheckboxes.vue +48 -27
- package/app/components/forms/input-checkbox/SingleCheckbox.vue +52 -33
- package/app/components/forms/input-checkbox-radio/InputCheckboxRadioButton.vue +40 -22
- package/app/components/forms/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +33 -17
- package/app/components/forms/input-label/InputLabel.vue +10 -12
- package/app/components/forms/input-number/InputNumberCore.vue +26 -22
- package/app/components/forms/input-number/variants/InputNumberDefault.vue +50 -27
- package/app/components/forms/input-radio/MultipleRadiobuttons.vue +31 -25
- package/app/components/forms/input-range/InputRangeCore.vue +30 -28
- package/app/components/forms/input-range/variants/InputRangeDefault.vue +45 -28
- package/app/components/forms/input-range-fancy/InputRangeFancyWithLabel.vue +31 -18
- package/app/components/forms/input-select/variants/InputSelectWithLabel.vue +48 -37
- package/app/components/forms/input-text/InputTextCore.vue +56 -52
- package/app/components/forms/input-text/variants/InputTextAsNumberWithLabel.vue +42 -33
- package/app/components/forms/input-text/variants/InputTextWithLabel.vue +51 -42
- package/app/components/forms/input-textarea/InputTextareaCore.vue +29 -24
- package/app/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +41 -31
- package/app/components/forms/toggle-switch/ToggleSwitchCore.vue +43 -25
- package/app/components/forms/toggle-switch/ToggleSwitchCoreOld.vue +36 -22
- package/app/components/forms/toggle-switch/variants/ToggleSwitchWithLabel.vue +42 -25
- package/app/components/forms/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +30 -26
- package/nuxt.config.ts +11 -11
- package/package.json +2 -2
- package/app/assets/styles/setup/typography/vars/_colors.css +0 -14
- package/app/assets/styles/setup/variables/index.css +0 -1
|
@@ -4,9 +4,16 @@
|
|
|
4
4
|
:data-theme="formTheme"
|
|
5
5
|
:data-size="size"
|
|
6
6
|
:data-inputmode="inputmode"
|
|
7
|
-
:class="[
|
|
7
|
+
:class="[
|
|
8
|
+
inputVariant,
|
|
9
|
+
{ dirty: isDirty },
|
|
10
|
+
{ active: isActive },
|
|
11
|
+
{ error: fieldHasError },
|
|
12
|
+
{ 'has-left-slot': slots.left },
|
|
13
|
+
{ 'has-right-slot': slots.right },
|
|
14
|
+
]"
|
|
8
15
|
>
|
|
9
|
-
<span v-if="
|
|
16
|
+
<span v-if="slots.left" class="slot left-slot">
|
|
10
17
|
<slot name="left"></slot>
|
|
11
18
|
</span>
|
|
12
19
|
|
|
@@ -28,29 +35,28 @@
|
|
|
28
35
|
@focusout="updateFocus(false)"
|
|
29
36
|
/>
|
|
30
37
|
|
|
31
|
-
<span v-if="
|
|
38
|
+
<span v-if="slots.right" class="slot right-slot">
|
|
32
39
|
<slot name="right"></slot>
|
|
33
40
|
</span>
|
|
34
41
|
</div>
|
|
35
42
|
</template>
|
|
36
43
|
|
|
37
44
|
<script setup lang="ts">
|
|
38
|
-
import propValidators from
|
|
45
|
+
import propValidators from "../c12/prop-validators"
|
|
39
46
|
|
|
40
47
|
const props = defineProps({
|
|
41
48
|
type: {
|
|
42
|
-
type: String as PropType<
|
|
43
|
-
|
|
44
|
-
default: 'text',
|
|
49
|
+
type: String as PropType<"text" | "email" | "password" | "number" | "tel" | "url">,
|
|
50
|
+
default: "text",
|
|
45
51
|
validator(value: string) {
|
|
46
|
-
return propValidators.inputTypesText.includes(value)
|
|
52
|
+
return propValidators.inputTypesText.includes(value)
|
|
47
53
|
},
|
|
48
54
|
},
|
|
49
55
|
inputmode: {
|
|
50
|
-
type: String as PropType<
|
|
51
|
-
default:
|
|
56
|
+
type: String as PropType<"text" | "email" | "tel" | "url" | "search" | "numeric" | "none" | "decimal">,
|
|
57
|
+
default: "text",
|
|
52
58
|
validator(value: string) {
|
|
53
|
-
return propValidators.inputMode.includes(value)
|
|
59
|
+
return propValidators.inputMode.includes(value)
|
|
54
60
|
},
|
|
55
61
|
},
|
|
56
62
|
maxlength: {
|
|
@@ -71,7 +77,7 @@ const props = defineProps({
|
|
|
71
77
|
},
|
|
72
78
|
placeholder: {
|
|
73
79
|
type: String,
|
|
74
|
-
default:
|
|
80
|
+
default: "",
|
|
75
81
|
},
|
|
76
82
|
fieldHasError: {
|
|
77
83
|
type: Boolean,
|
|
@@ -83,9 +89,9 @@ const props = defineProps({
|
|
|
83
89
|
},
|
|
84
90
|
theme: {
|
|
85
91
|
type: String as PropType<string>,
|
|
86
|
-
default:
|
|
92
|
+
default: "primary",
|
|
87
93
|
validator(value: string) {
|
|
88
|
-
return propValidators.theme.includes(value)
|
|
94
|
+
return propValidators.theme.includes(value)
|
|
89
95
|
},
|
|
90
96
|
},
|
|
91
97
|
ariaDescribedby: {
|
|
@@ -94,66 +100,64 @@ const props = defineProps({
|
|
|
94
100
|
},
|
|
95
101
|
size: {
|
|
96
102
|
type: String as PropType<string>,
|
|
97
|
-
default:
|
|
103
|
+
default: "default",
|
|
98
104
|
validator(value: string) {
|
|
99
|
-
return propValidators.size.includes(value)
|
|
105
|
+
return propValidators.size.includes(value)
|
|
100
106
|
},
|
|
101
107
|
},
|
|
102
108
|
inputVariant: {
|
|
103
109
|
type: String as PropType<string>,
|
|
104
|
-
default:
|
|
110
|
+
default: "normal",
|
|
105
111
|
validator(value: string) {
|
|
106
|
-
return propValidators.inputVariant.includes(value)
|
|
112
|
+
return propValidators.inputVariant.includes(value)
|
|
107
113
|
},
|
|
108
114
|
},
|
|
109
|
-
})
|
|
115
|
+
})
|
|
110
116
|
|
|
111
|
-
const slots = useSlots()
|
|
112
|
-
const hasLeftSlot = computed(() => slots.left !== undefined);
|
|
113
|
-
const hasRightSlot = computed(() => slots.right !== undefined);
|
|
117
|
+
const slots = useSlots()
|
|
114
118
|
|
|
115
119
|
const formTheme = computed(() => {
|
|
116
|
-
return props.fieldHasError ?
|
|
117
|
-
})
|
|
120
|
+
return props.fieldHasError ? "error" : props.theme
|
|
121
|
+
})
|
|
118
122
|
|
|
119
|
-
const modelValue = defineModel()
|
|
120
|
-
const isDirty = defineModel(
|
|
121
|
-
const isActive = defineModel(
|
|
123
|
+
const modelValue = defineModel()
|
|
124
|
+
const isDirty = defineModel("isDirty")
|
|
125
|
+
const isActive = defineModel("isActive")
|
|
122
126
|
|
|
123
127
|
const inputPattern = computed(() => {
|
|
124
|
-
return props.inputmode ===
|
|
125
|
-
})
|
|
128
|
+
return props.inputmode === "numeric" ? "[0-9]+" : undefined
|
|
129
|
+
})
|
|
126
130
|
|
|
127
131
|
const updateFocus = (isFocused: boolean) => {
|
|
128
|
-
isActive.value = isFocused
|
|
129
|
-
}
|
|
132
|
+
isActive.value = isFocused
|
|
133
|
+
}
|
|
130
134
|
|
|
131
|
-
const inputField = ref<HTMLInputElement | null>(null)
|
|
135
|
+
const inputField = ref<HTMLInputElement | null>(null)
|
|
132
136
|
|
|
133
|
-
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
137
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
134
138
|
|
|
135
139
|
// TODO: Move this to a utility function to allow removeEventListener on unmounted
|
|
136
140
|
// Leaving like this could lead to memory leaks
|
|
137
141
|
const validateInput = () => {
|
|
138
142
|
if (inputField.value !== null) {
|
|
139
|
-
inputField.value.addEventListener(
|
|
140
|
-
let beforeValue = modelValue.value
|
|
143
|
+
inputField.value.addEventListener("beforeinput", (event: any) => {
|
|
144
|
+
let beforeValue = modelValue.value
|
|
141
145
|
event.target.addEventListener(
|
|
142
|
-
|
|
146
|
+
"input",
|
|
143
147
|
() => {
|
|
144
148
|
if (inputField.value !== null && inputField.value.validity.patternMismatch) {
|
|
145
|
-
inputField.value.value = beforeValue as string
|
|
149
|
+
inputField.value.value = beforeValue as string
|
|
146
150
|
}
|
|
147
151
|
},
|
|
148
152
|
{ once: true }
|
|
149
|
-
)
|
|
150
|
-
})
|
|
153
|
+
)
|
|
154
|
+
})
|
|
151
155
|
}
|
|
152
|
-
}
|
|
156
|
+
}
|
|
153
157
|
|
|
154
158
|
onMounted(() => {
|
|
155
|
-
if (props.inputmode ===
|
|
156
|
-
})
|
|
159
|
+
if (props.inputmode === "numeric") validateInput()
|
|
160
|
+
})
|
|
157
161
|
</script>
|
|
158
162
|
|
|
159
163
|
<style lang="css">
|
|
@@ -197,13 +201,13 @@ onMounted(() => {
|
|
|
197
201
|
place-items: center;
|
|
198
202
|
background-clip: padding-box;
|
|
199
203
|
|
|
200
|
-
&.left-slot:not([data-theme=
|
|
204
|
+
&.left-slot:not([data-theme="input-action"]) {
|
|
201
205
|
.icon {
|
|
202
206
|
width: 2.2rem;
|
|
203
207
|
height: 2.2rem;
|
|
204
208
|
}
|
|
205
209
|
|
|
206
|
-
[data-theme=
|
|
210
|
+
[data-theme="input-action"] {
|
|
207
211
|
width: initial;
|
|
208
212
|
height: initial;
|
|
209
213
|
padding: 0.5rem;
|
|
@@ -214,13 +218,13 @@ onMounted(() => {
|
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
}
|
|
217
|
-
&.right-slot:not([data-theme=
|
|
221
|
+
&.right-slot:not([data-theme="input-action"]) {
|
|
218
222
|
.icon {
|
|
219
223
|
width: 2.2rem;
|
|
220
224
|
height: 2.2rem;
|
|
221
225
|
}
|
|
222
226
|
|
|
223
|
-
[data-theme=
|
|
227
|
+
[data-theme="input-action"] {
|
|
224
228
|
width: initial;
|
|
225
229
|
height: initial;
|
|
226
230
|
padding: 0.5rem;
|
|
@@ -233,12 +237,12 @@ onMounted(() => {
|
|
|
233
237
|
}
|
|
234
238
|
}
|
|
235
239
|
|
|
236
|
-
&[data-inputmode=
|
|
240
|
+
&[data-inputmode="numeric"] {
|
|
237
241
|
padding-block: 0rem;
|
|
238
242
|
padding-inline: 0.75rem;
|
|
239
243
|
|
|
240
244
|
.slot {
|
|
241
|
-
[data-theme=
|
|
245
|
+
[data-theme="input-action"] {
|
|
242
246
|
width: initial;
|
|
243
247
|
height: initial;
|
|
244
248
|
padding: 0.5rem;
|
|
@@ -281,13 +285,13 @@ onMounted(() => {
|
|
|
281
285
|
place-items: center;
|
|
282
286
|
background-clip: padding-box;
|
|
283
287
|
|
|
284
|
-
&.left-slot:not([data-theme=
|
|
288
|
+
&.left-slot:not([data-theme="input-action-underlined"]) {
|
|
285
289
|
.icon {
|
|
286
290
|
width: 2.2rem;
|
|
287
291
|
height: 2.2rem;
|
|
288
292
|
}
|
|
289
293
|
|
|
290
|
-
[data-theme=
|
|
294
|
+
[data-theme="input-action-underlined"] {
|
|
291
295
|
width: initial;
|
|
292
296
|
height: initial;
|
|
293
297
|
padding: 0.5rem;
|
|
@@ -298,13 +302,13 @@ onMounted(() => {
|
|
|
298
302
|
}
|
|
299
303
|
}
|
|
300
304
|
}
|
|
301
|
-
&.right-slot:not([data-theme=
|
|
305
|
+
&.right-slot:not([data-theme="input-action-underlined"]) {
|
|
302
306
|
.icon {
|
|
303
307
|
width: 2.2rem;
|
|
304
308
|
height: 2.2rem;
|
|
305
309
|
}
|
|
306
310
|
|
|
307
|
-
[data-theme=
|
|
311
|
+
[data-theme="input-action-underlined"] {
|
|
308
312
|
width: initial;
|
|
309
313
|
height: initial;
|
|
310
314
|
padding: 0.5rem;
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
2
|
+
<div
|
|
3
|
+
class="input-text-with-label"
|
|
4
|
+
:data-theme="formTheme"
|
|
5
|
+
:class="[inputVariant, elementClasses, { dirty: isDirty }, { active: isActive }]"
|
|
6
|
+
>
|
|
7
|
+
<InputLabel
|
|
8
|
+
:for="id"
|
|
9
|
+
:id
|
|
10
|
+
:theme
|
|
11
|
+
:name
|
|
12
|
+
:input-variant
|
|
13
|
+
:field-has-error
|
|
14
|
+
:style-class-passthrough="['input-text-label', 'body-normal-bold']"
|
|
15
|
+
>
|
|
4
16
|
<template #textLabel>{{ label }}</template>
|
|
5
17
|
</InputLabel>
|
|
6
18
|
|
|
7
|
-
<div v-if="
|
|
19
|
+
<div v-if="slots.description" :id="`${id}-description`">
|
|
8
20
|
<slot name="description"></slot>
|
|
9
21
|
</div>
|
|
10
22
|
|
|
@@ -28,7 +40,7 @@
|
|
|
28
40
|
:size
|
|
29
41
|
:inputVariant
|
|
30
42
|
>
|
|
31
|
-
<template v-if="
|
|
43
|
+
<template v-if="slots.left" #left>
|
|
32
44
|
<InputButtonCore
|
|
33
45
|
type="button"
|
|
34
46
|
@click.stop.prevent="updateValue(-step, Number(modelValue) > min)"
|
|
@@ -43,7 +55,7 @@
|
|
|
43
55
|
</template>
|
|
44
56
|
</InputButtonCore>
|
|
45
57
|
</template>
|
|
46
|
-
<template v-if="
|
|
58
|
+
<template v-if="slots.right" #right>
|
|
47
59
|
<InputButtonCore
|
|
48
60
|
type="button"
|
|
49
61
|
@click.stop.prevent="updateValue(step, Number(modelValue) < max)"
|
|
@@ -64,7 +76,7 @@
|
|
|
64
76
|
</template>
|
|
65
77
|
|
|
66
78
|
<script setup lang="ts">
|
|
67
|
-
import propValidators from
|
|
79
|
+
import propValidators from "../../c12/prop-validators"
|
|
68
80
|
const props = defineProps({
|
|
69
81
|
maxlength: {
|
|
70
82
|
type: Number,
|
|
@@ -76,7 +88,7 @@ const props = defineProps({
|
|
|
76
88
|
},
|
|
77
89
|
placeholder: {
|
|
78
90
|
type: String,
|
|
79
|
-
default:
|
|
91
|
+
default: "",
|
|
80
92
|
},
|
|
81
93
|
label: {
|
|
82
94
|
type: String,
|
|
@@ -100,9 +112,9 @@ const props = defineProps({
|
|
|
100
112
|
},
|
|
101
113
|
theme: {
|
|
102
114
|
type: String as PropType<string>,
|
|
103
|
-
default:
|
|
115
|
+
default: "primary",
|
|
104
116
|
validator(value: string) {
|
|
105
|
-
return propValidators.theme.includes(value)
|
|
117
|
+
return propValidators.theme.includes(value)
|
|
106
118
|
},
|
|
107
119
|
},
|
|
108
120
|
min: {
|
|
@@ -119,50 +131,47 @@ const props = defineProps({
|
|
|
119
131
|
},
|
|
120
132
|
size: {
|
|
121
133
|
type: String as PropType<string>,
|
|
122
|
-
default:
|
|
134
|
+
default: "default",
|
|
123
135
|
validator(value: string) {
|
|
124
|
-
return propValidators.size.includes(value)
|
|
136
|
+
return propValidators.size.includes(value)
|
|
125
137
|
},
|
|
126
138
|
},
|
|
127
139
|
inputVariant: {
|
|
128
140
|
type: String as PropType<string>,
|
|
129
|
-
default:
|
|
141
|
+
default: "normal",
|
|
130
142
|
validator(value: string) {
|
|
131
|
-
return propValidators.inputVariant.includes(value)
|
|
143
|
+
return propValidators.inputVariant.includes(value)
|
|
132
144
|
},
|
|
133
145
|
},
|
|
134
|
-
})
|
|
146
|
+
})
|
|
135
147
|
|
|
136
|
-
const slots = useSlots()
|
|
137
|
-
const hasDescriptionSlot = computed(() => slots.description !== undefined);
|
|
138
|
-
const hasLeftSlot = computed(() => slots.left !== undefined);
|
|
139
|
-
const hasRightSlot = computed(() => slots.right !== undefined);
|
|
148
|
+
const slots = useSlots()
|
|
140
149
|
|
|
141
150
|
const formTheme = computed(() => {
|
|
142
|
-
return props.fieldHasError ?
|
|
143
|
-
})
|
|
151
|
+
return props.fieldHasError ? "error" : props.theme
|
|
152
|
+
})
|
|
144
153
|
|
|
145
|
-
const id = useId()
|
|
146
|
-
const errorId = `${id}-error-message
|
|
154
|
+
const id = useId()
|
|
155
|
+
const errorId = `${id}-error-message`
|
|
147
156
|
const ariaDescribedby = computed(() => {
|
|
148
|
-
const ariaDescribedbyId =
|
|
149
|
-
return props.fieldHasError ? errorId : ariaDescribedbyId
|
|
150
|
-
})
|
|
157
|
+
const ariaDescribedbyId = slots.description ? `${id}-description` : undefined
|
|
158
|
+
return props.fieldHasError ? errorId : ariaDescribedbyId
|
|
159
|
+
})
|
|
151
160
|
|
|
152
|
-
const modelValue = defineModel()
|
|
153
|
-
const isActive = ref<boolean>(false)
|
|
154
|
-
const isDirty = ref<boolean>(false)
|
|
161
|
+
const modelValue = defineModel()
|
|
162
|
+
const isActive = ref<boolean>(false)
|
|
163
|
+
const isDirty = ref<boolean>(false)
|
|
155
164
|
|
|
156
|
-
const { elementClasses, updateElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
157
|
-
const minLength = computed(() => `${props.max.toString().length + 1}em`)
|
|
165
|
+
const { elementClasses, updateElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
166
|
+
const minLength = computed(() => `${props.max.toString().length + 1}em`)
|
|
158
167
|
|
|
159
168
|
const updateValue = (step: number, withinRangeLimit: boolean) => {
|
|
160
169
|
if (withinRangeLimit) {
|
|
161
|
-
modelValue.value = (Number(modelValue.value) + step) as number
|
|
170
|
+
modelValue.value = (Number(modelValue.value) + step) as number
|
|
162
171
|
}
|
|
163
|
-
}
|
|
172
|
+
}
|
|
164
173
|
|
|
165
|
-
updateElementClasses([
|
|
174
|
+
updateElementClasses(["input-text-as-number", "has-left-button", "has-right-button"])
|
|
166
175
|
</script>
|
|
167
176
|
|
|
168
177
|
<style lang="css">
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<div
|
|
4
|
-
|
|
3
|
+
<div
|
|
4
|
+
class="input-text-with-label"
|
|
5
|
+
:data-theme="formTheme"
|
|
6
|
+
:class="[elementClasses, inputVariant, { dirty: isDirty }, { active: isActive }]"
|
|
7
|
+
>
|
|
8
|
+
<InputLabel
|
|
9
|
+
:for="id"
|
|
10
|
+
:id
|
|
11
|
+
:theme
|
|
12
|
+
:name
|
|
13
|
+
:input-variant
|
|
14
|
+
:field-has-error
|
|
15
|
+
:style-class-passthrough="['input-text-label']"
|
|
16
|
+
>
|
|
5
17
|
<template #textLabel>{{ label }}</template>
|
|
6
18
|
</InputLabel>
|
|
7
19
|
|
|
8
|
-
<div v-if="inputVariant === 'normal' &&
|
|
20
|
+
<div v-if="inputVariant === 'normal' && slots.description" :id="`${id}-description`">
|
|
9
21
|
<slot name="description"></slot>
|
|
10
22
|
</div>
|
|
11
23
|
|
|
@@ -29,10 +41,10 @@
|
|
|
29
41
|
:size
|
|
30
42
|
:inputVariant
|
|
31
43
|
>
|
|
32
|
-
<template v-if="
|
|
44
|
+
<template v-if="slots.left" #left>
|
|
33
45
|
<slot name="left"></slot>
|
|
34
46
|
</template>
|
|
35
|
-
<template v-if="
|
|
47
|
+
<template v-if="slots.right" #right>
|
|
36
48
|
<slot name="right"></slot>
|
|
37
49
|
</template>
|
|
38
50
|
</InputTextCore>
|
|
@@ -40,28 +52,28 @@
|
|
|
40
52
|
<InputError :errorMessage :showError="fieldHasError" :id="errorId" :isDetached="false" :inputVariant />
|
|
41
53
|
</div>
|
|
42
54
|
|
|
43
|
-
<div v-if="inputVariant !== 'normal' &&
|
|
55
|
+
<div v-if="inputVariant !== 'normal' && slots.description" :id="`${id}-description`">
|
|
44
56
|
<slot name="description"></slot>
|
|
45
57
|
</div>
|
|
46
58
|
</div>
|
|
47
59
|
</template>
|
|
48
60
|
|
|
49
61
|
<script setup lang="ts">
|
|
50
|
-
import propValidators from
|
|
62
|
+
import propValidators from "../../c12/prop-validators"
|
|
51
63
|
const props = defineProps({
|
|
52
64
|
maxlength: {
|
|
53
65
|
type: Number,
|
|
54
66
|
default: 255,
|
|
55
67
|
},
|
|
56
68
|
type: {
|
|
57
|
-
type: String as PropType<
|
|
69
|
+
type: String as PropType<"text" | "email" | "password" | "number" | "tel" | "url">,
|
|
58
70
|
required: true,
|
|
59
71
|
},
|
|
60
72
|
inputmode: {
|
|
61
|
-
type: String as PropType<
|
|
62
|
-
default:
|
|
73
|
+
type: String as PropType<"text" | "email" | "tel" | "url" | "search" | "numeric" | "none" | "decimal">,
|
|
74
|
+
default: "text",
|
|
63
75
|
validator(value: string) {
|
|
64
|
-
return propValidators.inputMode.includes(value)
|
|
76
|
+
return propValidators.inputMode.includes(value)
|
|
65
77
|
},
|
|
66
78
|
},
|
|
67
79
|
name: {
|
|
@@ -70,7 +82,7 @@ const props = defineProps({
|
|
|
70
82
|
},
|
|
71
83
|
placeholder: {
|
|
72
84
|
type: String,
|
|
73
|
-
default:
|
|
85
|
+
default: "",
|
|
74
86
|
},
|
|
75
87
|
label: {
|
|
76
88
|
type: String,
|
|
@@ -94,65 +106,62 @@ const props = defineProps({
|
|
|
94
106
|
},
|
|
95
107
|
theme: {
|
|
96
108
|
type: String as PropType<string>,
|
|
97
|
-
default:
|
|
109
|
+
default: "primary",
|
|
98
110
|
validator(value: string) {
|
|
99
|
-
return propValidators.theme.includes(value)
|
|
111
|
+
return propValidators.theme.includes(value)
|
|
100
112
|
},
|
|
101
113
|
},
|
|
102
114
|
size: {
|
|
103
115
|
type: String as PropType<string>,
|
|
104
|
-
default:
|
|
116
|
+
default: "default",
|
|
105
117
|
validator(value: string) {
|
|
106
|
-
return propValidators.size.includes(value)
|
|
118
|
+
return propValidators.size.includes(value)
|
|
107
119
|
},
|
|
108
120
|
},
|
|
109
121
|
inputVariant: {
|
|
110
122
|
type: String as PropType<string>,
|
|
111
|
-
default:
|
|
123
|
+
default: "normal",
|
|
112
124
|
validator(value: string) {
|
|
113
|
-
return propValidators.inputVariant.includes(value)
|
|
125
|
+
return propValidators.inputVariant.includes(value)
|
|
114
126
|
},
|
|
115
127
|
},
|
|
116
|
-
})
|
|
128
|
+
})
|
|
117
129
|
|
|
118
|
-
const slots = useSlots()
|
|
119
|
-
const hasDescriptionSlot = computed(() => slots.description !== undefined);
|
|
120
|
-
const hasLeftSlot = computed(() => slots.left !== undefined);
|
|
121
|
-
const hasRightSlot = computed(() => slots.right !== undefined);
|
|
130
|
+
const slots = useSlots()
|
|
122
131
|
|
|
123
132
|
const formTheme = computed(() => {
|
|
124
|
-
return props.fieldHasError ?
|
|
125
|
-
})
|
|
133
|
+
return props.fieldHasError ? "error" : props.theme
|
|
134
|
+
})
|
|
126
135
|
|
|
127
|
-
const id = `${props.name}-${useId()}
|
|
128
|
-
const errorId = `${id}-error-message
|
|
136
|
+
const id = `${props.name}-${useId()}`
|
|
137
|
+
const errorId = `${id}-error-message`
|
|
129
138
|
const ariaDescribedby = computed(() => {
|
|
130
|
-
const ariaDescribedbyId =
|
|
131
|
-
return props.fieldHasError ? errorId : ariaDescribedbyId
|
|
132
|
-
})
|
|
139
|
+
const ariaDescribedbyId = slots.description ? `${id}-description` : undefined
|
|
140
|
+
return props.fieldHasError ? errorId : ariaDescribedbyId
|
|
141
|
+
})
|
|
133
142
|
|
|
134
|
-
const modelValue = defineModel()
|
|
135
|
-
const isActive = ref<boolean>(false)
|
|
136
|
-
const isDirty = ref<boolean>(false)
|
|
143
|
+
const modelValue = defineModel()
|
|
144
|
+
const isActive = ref<boolean>(false)
|
|
145
|
+
const isDirty = ref<boolean>(false)
|
|
137
146
|
|
|
138
|
-
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
147
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
139
148
|
|
|
140
149
|
const testDirty = () => {
|
|
141
|
-
const watchValue = modelValue.value ??
|
|
150
|
+
const watchValue = modelValue.value ?? ""
|
|
142
151
|
|
|
143
|
-
if (!isDirty.value && typeof watchValue ===
|
|
144
|
-
isDirty.value = true
|
|
152
|
+
if (!isDirty.value && typeof watchValue === "string" && watchValue.length > 0) {
|
|
153
|
+
isDirty.value = true
|
|
145
154
|
}
|
|
146
|
-
}
|
|
155
|
+
}
|
|
147
156
|
|
|
148
157
|
onMounted(() => {
|
|
149
|
-
testDirty()
|
|
150
|
-
})
|
|
158
|
+
testDirty()
|
|
159
|
+
})
|
|
151
160
|
|
|
152
161
|
watch(
|
|
153
162
|
() => modelValue.value,
|
|
154
163
|
() => {
|
|
155
|
-
testDirty()
|
|
164
|
+
testDirty()
|
|
156
165
|
}
|
|
157
|
-
)
|
|
166
|
+
)
|
|
158
167
|
</script>
|
|
@@ -3,9 +3,16 @@
|
|
|
3
3
|
class="input-textarea-wrapper"
|
|
4
4
|
:data-theme="formTheme"
|
|
5
5
|
:data-size="size"
|
|
6
|
-
:class="[
|
|
6
|
+
:class="[
|
|
7
|
+
inputVariant,
|
|
8
|
+
{ dirty: isDirty },
|
|
9
|
+
{ active: isActive },
|
|
10
|
+
{ error: fieldHasError },
|
|
11
|
+
{ 'has-left-slot': slots.left },
|
|
12
|
+
{ 'has-right-slot': slots.right },
|
|
13
|
+
]"
|
|
7
14
|
>
|
|
8
|
-
<span v-if="
|
|
15
|
+
<span v-if="slots.left" class="slot left-slot">
|
|
9
16
|
<slot name="left"></slot>
|
|
10
17
|
</span>
|
|
11
18
|
|
|
@@ -24,14 +31,14 @@
|
|
|
24
31
|
@focusout="updateFocus(false)"
|
|
25
32
|
></textarea>
|
|
26
33
|
|
|
27
|
-
<span v-if="
|
|
34
|
+
<span v-if="slots.right" class="slot right-slot">
|
|
28
35
|
<slot name="right"></slot>
|
|
29
36
|
</span>
|
|
30
37
|
</div>
|
|
31
38
|
</template>
|
|
32
39
|
|
|
33
40
|
<script setup lang="ts">
|
|
34
|
-
import propValidators from
|
|
41
|
+
import propValidators from "../c12/prop-validators"
|
|
35
42
|
const props = defineProps({
|
|
36
43
|
maxlength: {
|
|
37
44
|
type: Number,
|
|
@@ -47,7 +54,7 @@ const props = defineProps({
|
|
|
47
54
|
},
|
|
48
55
|
placeholder: {
|
|
49
56
|
type: String,
|
|
50
|
-
default:
|
|
57
|
+
default: "",
|
|
51
58
|
},
|
|
52
59
|
fieldHasError: {
|
|
53
60
|
type: Boolean,
|
|
@@ -63,46 +70,44 @@ const props = defineProps({
|
|
|
63
70
|
},
|
|
64
71
|
theme: {
|
|
65
72
|
type: String as PropType<string>,
|
|
66
|
-
default:
|
|
73
|
+
default: "primary",
|
|
67
74
|
validator(value: string) {
|
|
68
|
-
return propValidators.theme.includes(value)
|
|
75
|
+
return propValidators.theme.includes(value)
|
|
69
76
|
},
|
|
70
77
|
},
|
|
71
78
|
size: {
|
|
72
79
|
type: String as PropType<string>,
|
|
73
|
-
default:
|
|
80
|
+
default: "default",
|
|
74
81
|
validator(value: string) {
|
|
75
|
-
return propValidators.size.includes(value)
|
|
82
|
+
return propValidators.size.includes(value)
|
|
76
83
|
},
|
|
77
84
|
},
|
|
78
85
|
inputVariant: {
|
|
79
86
|
type: String as PropType<string>,
|
|
80
|
-
default:
|
|
87
|
+
default: "normal",
|
|
81
88
|
validator(value: string) {
|
|
82
|
-
return propValidators.inputVariant.includes(value)
|
|
89
|
+
return propValidators.inputVariant.includes(value)
|
|
83
90
|
},
|
|
84
91
|
},
|
|
85
|
-
})
|
|
92
|
+
})
|
|
86
93
|
|
|
87
|
-
const slots = useSlots()
|
|
88
|
-
const hasLeftSlot = computed(() => slots.left !== undefined);
|
|
89
|
-
const hasRightSlot = computed(() => slots.right !== undefined);
|
|
94
|
+
const slots = useSlots()
|
|
90
95
|
|
|
91
96
|
const formTheme = computed(() => {
|
|
92
|
-
return props.fieldHasError ?
|
|
93
|
-
})
|
|
97
|
+
return props.fieldHasError ? "error" : props.theme
|
|
98
|
+
})
|
|
94
99
|
|
|
95
|
-
const modelValue = defineModel<string | number | readonly string[] | null | undefined>()
|
|
96
|
-
const isDirty = defineModel(
|
|
97
|
-
const isActive = defineModel(
|
|
100
|
+
const modelValue = defineModel<string | number | readonly string[] | null | undefined>()
|
|
101
|
+
const isDirty = defineModel("isDirty")
|
|
102
|
+
const isActive = defineModel("isActive")
|
|
98
103
|
|
|
99
104
|
const updateFocus = (isFocused: boolean) => {
|
|
100
|
-
isActive.value = isFocused
|
|
101
|
-
}
|
|
105
|
+
isActive.value = isFocused
|
|
106
|
+
}
|
|
102
107
|
|
|
103
|
-
const inputField = ref<HTMLInputElement | null>(null)
|
|
108
|
+
const inputField = ref<HTMLInputElement | null>(null)
|
|
104
109
|
|
|
105
|
-
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
110
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
106
111
|
</script>
|
|
107
112
|
|
|
108
113
|
<style lang="css">
|