@citizenplane/pimp 8.0.0 → 8.0.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/dist/pimp.es.js +218 -184
- package/dist/pimp.umd.js +3 -3
- package/dist/style.css +1 -1
- package/package-lock.json +373 -378
- package/package.json +11 -11
- package/src/assets/styles/lib/_normalize.scss +0 -24
- package/src/assets/styles/variables/_colors.scss +1 -1
- package/src/components/buttons/CpButton.vue +1 -1
- package/src/components/core/BaseInputLabel/index.vue +0 -1
- package/src/components/core/playground-sections/SectionDatePickers.vue +2 -2
- package/src/components/core/playground-sections/SectionSimpleInputs.vue +6 -1
- package/src/components/date-pickers/CpCalendar.vue +1 -1
- package/src/components/date-pickers/CpDate.vue +61 -39
- package/src/components/date-pickers/CpDatepicker.vue +1 -1
- package/src/components/feedback-indicators/CpAlert.vue +2 -1
- package/src/components/inputs/CpInput.vue +59 -75
- package/src/components/inputs/CpTextarea.vue +19 -2
- package/src/components/selects/CpSelect.vue +21 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citizenplane/pimp",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "vite --host",
|
|
6
6
|
"build": "vite build",
|
|
@@ -25,32 +25,32 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"vue": "^3.2.
|
|
28
|
+
"vue": "^3.2.29",
|
|
29
29
|
"animejs": "^3.2.0",
|
|
30
|
-
"core-js": "^3.20.
|
|
30
|
+
"core-js": "^3.20.3",
|
|
31
31
|
"feather-icons": "^4.28.0",
|
|
32
|
-
"luxon": "^2.
|
|
32
|
+
"luxon": "^2.3.0",
|
|
33
33
|
"maska": "^1.5.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@babel/core": "^7.16.
|
|
37
|
-
"@vitejs/plugin-vue": "^2.0
|
|
36
|
+
"@babel/core": "^7.16.12",
|
|
37
|
+
"@vitejs/plugin-vue": "^2.1.0",
|
|
38
38
|
"@vue/babel-preset-app": "^4.5.15",
|
|
39
39
|
"@vue/eslint-config-prettier": "^7.0.0",
|
|
40
40
|
"@vue/test-utils": "^2.0.0-rc.18",
|
|
41
41
|
"babel-core": "^7.0.0-bridge.0",
|
|
42
|
-
"eslint": "^8.
|
|
42
|
+
"eslint": "^8.7.0",
|
|
43
43
|
"eslint-plugin-prettier": "^4.0.0",
|
|
44
|
-
"eslint-plugin-vue": "^8.
|
|
44
|
+
"eslint-plugin-vue": "^8.4.0",
|
|
45
45
|
"husky": "^7.0.4",
|
|
46
46
|
"jest": "^26.6.3",
|
|
47
|
-
"lint-staged": "^12.
|
|
47
|
+
"lint-staged": "^12.3.2",
|
|
48
48
|
"prettier": "^2.5.1",
|
|
49
|
-
"sass": "~1.
|
|
49
|
+
"sass": "~1.49.0",
|
|
50
50
|
"sass-loader": "^12.4.0",
|
|
51
51
|
"stylus": "^0.56.0",
|
|
52
52
|
"stylus-loader": "^3.0.2",
|
|
53
|
-
"vite": "^2.7.
|
|
53
|
+
"vite": "^2.7.13",
|
|
54
54
|
"vue-jest": "^5.0.0-alpha.10"
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -214,30 +214,6 @@ button:-moz-focusring,
|
|
|
214
214
|
outline: 1px dotted ButtonText;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
/**
|
|
218
|
-
* Correct the padding in Firefox.
|
|
219
|
-
*/
|
|
220
|
-
|
|
221
|
-
fieldset {
|
|
222
|
-
padding: 0.35em 0.75em 0.625em;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* 1. Correct the text wrapping in Edge and IE.
|
|
227
|
-
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
|
228
|
-
* 3. Remove the padding so developers are not caught out when they zero out
|
|
229
|
-
* `fieldset` elements in all browsers.
|
|
230
|
-
*/
|
|
231
|
-
|
|
232
|
-
legend {
|
|
233
|
-
box-sizing: border-box; /* 1 */
|
|
234
|
-
color: inherit; /* 2 */
|
|
235
|
-
display: table; /* 1 */
|
|
236
|
-
max-width: 100%; /* 1 */
|
|
237
|
-
padding: 0; /* 3 */
|
|
238
|
-
white-space: normal; /* 1 */
|
|
239
|
-
}
|
|
240
|
-
|
|
241
217
|
/**
|
|
242
218
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
|
243
219
|
*/
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
Default date input: {{ cpDate }}
|
|
6
6
|
</cp-heading>
|
|
7
7
|
<div class="sectionDatePickers__datepickers">
|
|
8
|
-
<cp-date v-model="cpDate" label="Default date input" class="sectionDatePickers__date" />
|
|
8
|
+
<cp-date v-model="cpDate" label="Default date input" class="sectionDatePickers__date" :is-invalid="false" />
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="sectionDatePickers__type">
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
</div>
|
|
19
19
|
<div class="sectionDatePickers__datepickers">
|
|
20
20
|
<div class="sectionDatePickers__wrapper">
|
|
21
|
-
<cp-input
|
|
21
|
+
<cp-input id="datepicker-trigger" label="CoreDatepicker" placeholder="CoreDatepicker" />
|
|
22
22
|
<cp-core-datepicker
|
|
23
23
|
class="sectionDatePickers__custom"
|
|
24
24
|
mode="range"
|
|
@@ -70,7 +70,12 @@
|
|
|
70
70
|
<div class="sectionSimpleInputs__type">
|
|
71
71
|
<cp-heading heading-level="h3" :size="600" class="sectionSimpleInputs__title">Disabled</cp-heading>
|
|
72
72
|
<div class="sectionSimpleInputs__inputs">
|
|
73
|
-
<cp-input
|
|
73
|
+
<cp-input
|
|
74
|
+
label="Empty disabled input with icon before"
|
|
75
|
+
type="text"
|
|
76
|
+
placeholder="Input placeholder"
|
|
77
|
+
:disabled="true"
|
|
78
|
+
>
|
|
74
79
|
<template #input-icon><cp-icon type="map-pin" /></template>
|
|
75
80
|
</cp-input>
|
|
76
81
|
<cp-input
|
|
@@ -5,22 +5,26 @@
|
|
|
5
5
|
</label>
|
|
6
6
|
<div class="cpDate__inputs">
|
|
7
7
|
<input
|
|
8
|
-
ref="day"
|
|
9
8
|
v-model="day"
|
|
9
|
+
v-maska="'##'"
|
|
10
10
|
placeholder="DD"
|
|
11
11
|
class="cpDate__day"
|
|
12
|
-
type="number"
|
|
13
12
|
inputmode="numeric"
|
|
14
|
-
:min="1"
|
|
15
|
-
:max="31"
|
|
16
13
|
maxlength="2"
|
|
17
14
|
:required="required"
|
|
18
15
|
:disabled="disabled"
|
|
16
|
+
:autocomplete="autocompleteFields.day"
|
|
19
17
|
/>
|
|
20
18
|
<div class="cpDate__divider" />
|
|
21
19
|
<div class="cpDate__month" :class="selectDynamicClass">
|
|
22
|
-
<select
|
|
23
|
-
|
|
20
|
+
<select
|
|
21
|
+
:id="cpDateId"
|
|
22
|
+
v-model="month"
|
|
23
|
+
:required="required"
|
|
24
|
+
:disabled="disabled"
|
|
25
|
+
:autocomplete="autocompleteFields.month"
|
|
26
|
+
>
|
|
27
|
+
<option value>Month</option>
|
|
24
28
|
<option v-for="(monthItem, index) in months" :key="index" :value="monthItem.value">
|
|
25
29
|
{{ monthItem.label }}
|
|
26
30
|
</option>
|
|
@@ -28,21 +32,19 @@
|
|
|
28
32
|
</div>
|
|
29
33
|
<div class="cpDate__divider" />
|
|
30
34
|
<input
|
|
31
|
-
ref="year"
|
|
32
35
|
v-model="year"
|
|
36
|
+
v-maska="'####'"
|
|
33
37
|
placeholder="YYYY"
|
|
34
38
|
class="cpDate__year"
|
|
35
|
-
type="number"
|
|
36
39
|
inputmode="numeric"
|
|
37
|
-
:min="minYear"
|
|
38
|
-
:max="maxYear"
|
|
39
40
|
maxlength="4"
|
|
40
41
|
:disabled="disabled"
|
|
41
42
|
:required="required"
|
|
43
|
+
:autocomplete="autocompleteFields.year"
|
|
42
44
|
/>
|
|
43
45
|
</div>
|
|
44
46
|
<transition-expand>
|
|
45
|
-
<div v-if="
|
|
47
|
+
<div v-if="advancedErrorMessage" class="cpDate__errorMessage">{{ advancedErrorMessage }}</div>
|
|
46
48
|
</transition-expand>
|
|
47
49
|
</div>
|
|
48
50
|
</template>
|
|
@@ -80,6 +82,18 @@ export default {
|
|
|
80
82
|
type: Boolean,
|
|
81
83
|
default: false,
|
|
82
84
|
},
|
|
85
|
+
isInvalid: {
|
|
86
|
+
type: Boolean,
|
|
87
|
+
default: false,
|
|
88
|
+
},
|
|
89
|
+
errorMessage: {
|
|
90
|
+
type: String,
|
|
91
|
+
default: '',
|
|
92
|
+
},
|
|
93
|
+
autocompleteBirthday: {
|
|
94
|
+
type: Boolean,
|
|
95
|
+
default: false,
|
|
96
|
+
},
|
|
83
97
|
},
|
|
84
98
|
emits: ['update:modelValue', 'on-validation'],
|
|
85
99
|
data() {
|
|
@@ -144,13 +158,16 @@ export default {
|
|
|
144
158
|
return this.day === '' && this.month === '' && this.year === ''
|
|
145
159
|
},
|
|
146
160
|
isDateValid() {
|
|
147
|
-
if (
|
|
161
|
+
if (this.areInputsEmpty && !this.errorMessage) return true
|
|
148
162
|
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
163
|
+
return (
|
|
164
|
+
!this.isInvalid &&
|
|
165
|
+
this.isDayValid &&
|
|
166
|
+
this.isMonthValid &&
|
|
167
|
+
this.isYearValid &&
|
|
168
|
+
this.isDateBeforeMaxDate &&
|
|
169
|
+
this.isDateAfterMinDate
|
|
170
|
+
)
|
|
154
171
|
},
|
|
155
172
|
isDayValid() {
|
|
156
173
|
return this.day >= 1 && this.day <= this.monthMaxDay
|
|
@@ -164,10 +181,10 @@ export default {
|
|
|
164
181
|
areAllFieldsEmpty() {
|
|
165
182
|
return !this.day && !this.month && !this.year
|
|
166
183
|
},
|
|
167
|
-
|
|
168
|
-
if (this.
|
|
169
|
-
|
|
170
|
-
|
|
184
|
+
advancedErrorMessage() {
|
|
185
|
+
if (this.isDateValid) return ''
|
|
186
|
+
|
|
187
|
+
if (this.errorMessage) return this.errorMessage
|
|
171
188
|
|
|
172
189
|
if (!this.isMonthValid) {
|
|
173
190
|
return 'Month is required.'
|
|
@@ -204,6 +221,15 @@ export default {
|
|
|
204
221
|
'cpDate__month--isEmpty': !this.month,
|
|
205
222
|
}
|
|
206
223
|
},
|
|
224
|
+
autocompleteFields() {
|
|
225
|
+
if (!this.autocompleteBirthday) return 'off'
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
day: 'bday-day',
|
|
229
|
+
month: 'bday-month',
|
|
230
|
+
year: 'bday-year',
|
|
231
|
+
}
|
|
232
|
+
},
|
|
207
233
|
},
|
|
208
234
|
watch: {
|
|
209
235
|
day() {
|
|
@@ -211,7 +237,6 @@ export default {
|
|
|
211
237
|
},
|
|
212
238
|
month() {
|
|
213
239
|
this.handleUpdate()
|
|
214
|
-
this.focusOnFirstEmptyInput()
|
|
215
240
|
},
|
|
216
241
|
year() {
|
|
217
242
|
this.handleUpdate()
|
|
@@ -224,17 +249,9 @@ export default {
|
|
|
224
249
|
return DateTime.fromISO(this.modelValue)[token]
|
|
225
250
|
},
|
|
226
251
|
handleUpdate() {
|
|
227
|
-
|
|
252
|
+
this.$emit('update:modelValue', this.isoDate)
|
|
228
253
|
|
|
229
|
-
this.$emit('
|
|
230
|
-
},
|
|
231
|
-
focusOnFirstEmptyInput() {
|
|
232
|
-
if (!this.isDayValid) {
|
|
233
|
-
this.$refs.day.focus()
|
|
234
|
-
return
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (!this.isYearValid) this.$refs.year.focus()
|
|
254
|
+
this.$emit('on-validation', this.isDateValid)
|
|
238
255
|
},
|
|
239
256
|
},
|
|
240
257
|
}
|
|
@@ -273,14 +290,14 @@ export default {
|
|
|
273
290
|
.cpDate {
|
|
274
291
|
input::placeholder,
|
|
275
292
|
&__month--isEmpty {
|
|
276
|
-
color: $neutral-dark
|
|
293
|
+
color: $neutral-dark;
|
|
277
294
|
}
|
|
278
295
|
|
|
279
296
|
&__label {
|
|
280
297
|
display: flex;
|
|
281
298
|
align-items: center;
|
|
282
|
-
margin:
|
|
283
|
-
font-size:
|
|
299
|
+
margin-bottom: pxToEm(6);
|
|
300
|
+
font-size: pxToEm(14);
|
|
284
301
|
|
|
285
302
|
svg {
|
|
286
303
|
margin-left: $space-sm;
|
|
@@ -331,8 +348,8 @@ export default {
|
|
|
331
348
|
position: absolute;
|
|
332
349
|
top: 50%;
|
|
333
350
|
right: pxToEm(12);
|
|
334
|
-
width:
|
|
335
|
-
height:
|
|
351
|
+
width: pxToEm(20);
|
|
352
|
+
height: pxToEm(20);
|
|
336
353
|
background-image: url('@/assets/images/icons/chevron-down-icon.svg');
|
|
337
354
|
background-size: cover;
|
|
338
355
|
transform: translateY(-50%);
|
|
@@ -343,9 +360,14 @@ export default {
|
|
|
343
360
|
select {
|
|
344
361
|
@extend %u-text-ellipsis;
|
|
345
362
|
width: 100%;
|
|
346
|
-
padding:
|
|
363
|
+
padding: pxToEm(12) pxToEm(40) pxToEm(12) pxToEm(12);
|
|
347
364
|
color: inherit;
|
|
348
365
|
cursor: pointer;
|
|
366
|
+
|
|
367
|
+
&:focus-visible {
|
|
368
|
+
text-decoration: underline;
|
|
369
|
+
font-weight: 500;
|
|
370
|
+
}
|
|
349
371
|
}
|
|
350
372
|
|
|
351
373
|
select > option:not(:disabled) {
|
|
@@ -395,7 +417,7 @@ export default {
|
|
|
395
417
|
margin-top: pxToRem(6);
|
|
396
418
|
color: $error-color;
|
|
397
419
|
font-weight: 500;
|
|
398
|
-
font-size:
|
|
420
|
+
font-size: pxToEm(14);
|
|
399
421
|
}
|
|
400
422
|
}
|
|
401
423
|
</style>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<div class="cpDatepicker">
|
|
3
3
|
<cp-input
|
|
4
4
|
v-show="!isInline"
|
|
5
|
+
:id="datePickerReferenceId"
|
|
5
6
|
:model-value="inputComputedValue"
|
|
6
7
|
type="text"
|
|
7
|
-
:input-id="datePickerReferenceId"
|
|
8
8
|
:placeholder="placeholder"
|
|
9
9
|
:is-invalid="isError"
|
|
10
10
|
:error-message="errorMessage"
|
|
@@ -19,6 +19,7 @@ export default {
|
|
|
19
19
|
intent: {
|
|
20
20
|
type: String,
|
|
21
21
|
required: true,
|
|
22
|
+
default: Intent.INFO.value,
|
|
22
23
|
validator(value) {
|
|
23
24
|
const intentValues = Object.values(Intent).map((item) => item.value)
|
|
24
25
|
return intentValues.includes(value)
|
|
@@ -78,7 +79,7 @@ export default {
|
|
|
78
79
|
display: flex;
|
|
79
80
|
align-items: flex-start;
|
|
80
81
|
padding: pxToRem(10);
|
|
81
|
-
font-size:
|
|
82
|
+
font-size: pxToEm(14);
|
|
82
83
|
border-radius: pxToRem(4);
|
|
83
84
|
overflow: hidden;
|
|
84
85
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="cpInput" :class="dynamicClasses" :aria-disabled="
|
|
3
|
-
<base-input-label v-if="label" :for="
|
|
2
|
+
<div class="cpInput" :class="dynamicClasses" :aria-disabled="isDisabled" @click="focusOnInput">
|
|
3
|
+
<base-input-label v-if="label" :for="inputIdentifier" class="cpInput__label">
|
|
4
|
+
{{ inputLabelTitle }}
|
|
5
|
+
</base-input-label>
|
|
4
6
|
<div
|
|
5
7
|
ref="cpInputContainer"
|
|
6
8
|
:class="{ 'cpInput__container--hasBeforeIcon': hasBeforeIcon }"
|
|
@@ -19,23 +21,21 @@
|
|
|
19
21
|
<slot name="input-icon-after" />
|
|
20
22
|
</div>
|
|
21
23
|
<input
|
|
22
|
-
:id="
|
|
24
|
+
:id="inputIdentifier"
|
|
23
25
|
v-maska="mask"
|
|
24
|
-
:disabled="disabled"
|
|
25
|
-
:name="name"
|
|
26
|
-
:placeholder="placeholder"
|
|
27
|
-
:readonly="readonly"
|
|
28
|
-
:required="required"
|
|
29
|
-
:autocomplete="autocomplete"
|
|
30
|
-
:inputmode="inputMode"
|
|
31
|
-
:type="type"
|
|
32
26
|
:value="modelValue"
|
|
27
|
+
v-bind="restAttributes"
|
|
33
28
|
class="cpInput__inner"
|
|
34
29
|
@input="handleChange"
|
|
35
30
|
/>
|
|
36
31
|
</div>
|
|
37
32
|
<transition-expand>
|
|
38
|
-
<base-input-label
|
|
33
|
+
<base-input-label
|
|
34
|
+
v-if="isInputInvalid && errorMessage"
|
|
35
|
+
:is-invalid="isInvalid"
|
|
36
|
+
:for="inputIdentifier"
|
|
37
|
+
class="cpInput__label cpInput__label--isAfter"
|
|
38
|
+
>
|
|
39
39
|
{{ errorMessage }}
|
|
40
40
|
</base-input-label>
|
|
41
41
|
</transition-expand>
|
|
@@ -43,27 +43,14 @@
|
|
|
43
43
|
</template>
|
|
44
44
|
|
|
45
45
|
<script>
|
|
46
|
+
import { ref } from 'vue'
|
|
47
|
+
|
|
46
48
|
import { randomString } from '@/helpers'
|
|
47
49
|
|
|
48
50
|
import BaseInputLabel from '@/components/core/BaseInputLabel/index.vue'
|
|
49
51
|
import CpIcon from '@/components/visual/CpIcon.vue'
|
|
50
52
|
import TransitionExpand from '@/components/helpers-utilities/TransitionExpand.vue'
|
|
51
53
|
|
|
52
|
-
const inputTypesList = [
|
|
53
|
-
'text',
|
|
54
|
-
'date',
|
|
55
|
-
'datetime-local',
|
|
56
|
-
'email',
|
|
57
|
-
'month',
|
|
58
|
-
'number',
|
|
59
|
-
'password',
|
|
60
|
-
'search',
|
|
61
|
-
'tel',
|
|
62
|
-
'time',
|
|
63
|
-
'url',
|
|
64
|
-
'week',
|
|
65
|
-
]
|
|
66
|
-
|
|
67
54
|
export default {
|
|
68
55
|
name: 'CpInput',
|
|
69
56
|
components: {
|
|
@@ -71,6 +58,7 @@ export default {
|
|
|
71
58
|
BaseInputLabel,
|
|
72
59
|
TransitionExpand,
|
|
73
60
|
},
|
|
61
|
+
inheritAttrs: false,
|
|
74
62
|
props: {
|
|
75
63
|
modelValue: {
|
|
76
64
|
type: [String, Number, Boolean],
|
|
@@ -80,46 +68,10 @@ export default {
|
|
|
80
68
|
type: String,
|
|
81
69
|
default: '',
|
|
82
70
|
},
|
|
83
|
-
placeholder: {
|
|
84
|
-
type: String,
|
|
85
|
-
default: '',
|
|
86
|
-
required: true,
|
|
87
|
-
},
|
|
88
|
-
required: {
|
|
89
|
-
type: Boolean,
|
|
90
|
-
default: false,
|
|
91
|
-
},
|
|
92
71
|
inputId: {
|
|
93
72
|
type: String,
|
|
94
|
-
default: '',
|
|
95
|
-
},
|
|
96
|
-
type: {
|
|
97
|
-
type: String,
|
|
98
|
-
default: inputTypesList[0],
|
|
99
|
-
validator: (value) => {
|
|
100
|
-
return inputTypesList.includes(value)
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
name: {
|
|
104
|
-
type: String,
|
|
105
|
-
default: '',
|
|
106
|
-
},
|
|
107
|
-
readonly: {
|
|
108
|
-
type: Boolean,
|
|
109
|
-
default: false,
|
|
110
|
-
},
|
|
111
|
-
disabled: {
|
|
112
|
-
type: Boolean,
|
|
113
73
|
default: null,
|
|
114
74
|
},
|
|
115
|
-
autocomplete: {
|
|
116
|
-
type: String,
|
|
117
|
-
default: 'on',
|
|
118
|
-
},
|
|
119
|
-
inputMode: {
|
|
120
|
-
type: String,
|
|
121
|
-
default: 'text',
|
|
122
|
-
},
|
|
123
75
|
isInvalid: {
|
|
124
76
|
type: Boolean,
|
|
125
77
|
default: false,
|
|
@@ -146,18 +98,38 @@ export default {
|
|
|
146
98
|
},
|
|
147
99
|
},
|
|
148
100
|
emits: ['update:modelValue'],
|
|
101
|
+
setup(props, { attrs }) {
|
|
102
|
+
// class is a reserved work, we can't remove 'class' property from attrs
|
|
103
|
+
// eslint-disable-next-line no-unused-vars
|
|
104
|
+
const { ['class']: value, id, ...restAttributes } = attrs
|
|
105
|
+
const inputIdentifier = id === undefined ? ref(randomString()) : id
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
inputIdentifier,
|
|
109
|
+
restAttributes,
|
|
110
|
+
}
|
|
111
|
+
},
|
|
149
112
|
data() {
|
|
150
113
|
return {
|
|
151
|
-
inputReferenceId: this.inputId,
|
|
152
114
|
isDOMElementValid: true,
|
|
153
115
|
}
|
|
154
116
|
},
|
|
155
117
|
computed: {
|
|
118
|
+
isDisabled() {
|
|
119
|
+
return this.checkAttribute('disabled')
|
|
120
|
+
},
|
|
121
|
+
isRequired() {
|
|
122
|
+
return this.checkAttribute('required')
|
|
123
|
+
},
|
|
124
|
+
isReadonly() {
|
|
125
|
+
return this.checkAttribute('readonly')
|
|
126
|
+
},
|
|
156
127
|
dynamicClasses() {
|
|
157
128
|
return [
|
|
129
|
+
this.$attrs.class,
|
|
158
130
|
{
|
|
159
131
|
'cpInput--isInvalid': this.isInputInvalid,
|
|
160
|
-
'cpInput--isDisabled': this.
|
|
132
|
+
'cpInput--isDisabled': this.isDisabled,
|
|
161
133
|
'cpInput--hasNoBorder': this.removeBorder,
|
|
162
134
|
'cpInput--isLarge': this.isLarge,
|
|
163
135
|
},
|
|
@@ -171,12 +143,14 @@ export default {
|
|
|
171
143
|
}
|
|
172
144
|
},
|
|
173
145
|
inputLabelTitle() {
|
|
174
|
-
|
|
146
|
+
if (this.label === '') return ''
|
|
147
|
+
|
|
148
|
+
const requiredMark = this.isRequired ? '*' : ''
|
|
175
149
|
|
|
176
|
-
return `${this.label} ${
|
|
150
|
+
return `${this.label} ${requiredMark}`
|
|
177
151
|
},
|
|
178
152
|
isValid() {
|
|
179
|
-
return this.modelValue && !this.
|
|
153
|
+
return this.modelValue && !this.isReadonly && !this.isInvalid && this.isDOMElementValid
|
|
180
154
|
},
|
|
181
155
|
isInputInvalid() {
|
|
182
156
|
return this.isInvalid || !this.isDOMElementValid
|
|
@@ -188,15 +162,11 @@ export default {
|
|
|
188
162
|
return !!this.$slots['input-icon-after']
|
|
189
163
|
},
|
|
190
164
|
DOMElement() {
|
|
191
|
-
return this.$refs.cpInputContainer.children.namedItem(this.
|
|
165
|
+
return this.$refs.cpInputContainer.children.namedItem(this.inputIdentifier)
|
|
192
166
|
},
|
|
193
167
|
},
|
|
194
168
|
mounted() {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
this.$nextTick(() => {
|
|
198
|
-
this.checkInputValidity()
|
|
199
|
-
})
|
|
169
|
+
this.$nextTick(() => this.checkInputValidity())
|
|
200
170
|
},
|
|
201
171
|
methods: {
|
|
202
172
|
handleChange(e) {
|
|
@@ -214,6 +184,9 @@ export default {
|
|
|
214
184
|
(this.DOMElement.validity && this.DOMElement.validity.valid) ||
|
|
215
185
|
(this.DOMElement.validity && this.DOMElement.validity.valueMissing)
|
|
216
186
|
},
|
|
187
|
+
checkAttribute(attribute) {
|
|
188
|
+
return this.$attrs[attribute] === '' || this.$attrs[attribute] === true
|
|
189
|
+
},
|
|
217
190
|
},
|
|
218
191
|
}
|
|
219
192
|
</script>
|
|
@@ -229,7 +202,6 @@ export default {
|
|
|
229
202
|
position: relative;
|
|
230
203
|
display: flex;
|
|
231
204
|
flex-direction: column;
|
|
232
|
-
font-size: pxToRem(16);
|
|
233
205
|
|
|
234
206
|
&__container {
|
|
235
207
|
z-index: 1;
|
|
@@ -310,6 +282,18 @@ export default {
|
|
|
310
282
|
box-shadow: none;
|
|
311
283
|
}
|
|
312
284
|
|
|
285
|
+
&__label {
|
|
286
|
+
display: block;
|
|
287
|
+
|
|
288
|
+
&:not(#{&}--isAfter) {
|
|
289
|
+
margin-bottom: pxToEm(6);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
&--isAfter {
|
|
293
|
+
margin-top: pxToEm(6);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
313
297
|
$cp-input-icon-size: pxToEm(20);
|
|
314
298
|
|
|
315
299
|
&__icon {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="cpTextarea">
|
|
3
|
-
<base-input-label v-if="label" :for="inputReferenceId">
|
|
3
|
+
<base-input-label v-if="label" :for="inputReferenceId" class="cpTextarea__label">
|
|
4
4
|
{{ inputLabelTitle }}
|
|
5
5
|
</base-input-label>
|
|
6
6
|
<textarea
|
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
@input="handleChange"
|
|
16
16
|
/>
|
|
17
17
|
<transition-expand>
|
|
18
|
-
<base-input-label
|
|
18
|
+
<base-input-label
|
|
19
|
+
v-if="isInvalid"
|
|
20
|
+
:for="inputReferenceId"
|
|
21
|
+
is-invalid
|
|
22
|
+
class="cpTextarea__label cpTextarea__label--isAfter"
|
|
23
|
+
>
|
|
19
24
|
{{ errorMessage }}
|
|
20
25
|
</base-input-label>
|
|
21
26
|
</transition-expand>
|
|
@@ -153,5 +158,17 @@ export default {
|
|
|
153
158
|
}
|
|
154
159
|
}
|
|
155
160
|
}
|
|
161
|
+
|
|
162
|
+
&__label {
|
|
163
|
+
display: block;
|
|
164
|
+
|
|
165
|
+
&:not(#{&}--isAfter) {
|
|
166
|
+
margin-bottom: pxToEm(6);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
&--isAfter {
|
|
170
|
+
margin-top: pxToEm(6);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
156
173
|
}
|
|
157
174
|
</style>
|