@eturnity/eturnity_reusable_components 7.24.3-EPDM-11320.0 → 7.24.3-EPDM-11143.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/.prettierrc +7 -0
- package/package.json +20 -6
- package/public/favicon.ico +0 -0
- package/public/index.html +17 -0
- package/src/App.vue +70 -75
- package/src/assets/svgIcons/copy.svg +10 -0
- package/src/components/addNewButton/index.vue +27 -24
- package/src/components/banner/actionBanner/index.vue +30 -32
- package/src/components/banner/banner/index.vue +80 -88
- package/src/components/banner/infoBanner/index.vue +44 -36
- package/src/components/buttons/buttonIcon/index.vue +78 -83
- package/src/components/buttons/closeButton/index.vue +26 -26
- package/src/components/buttons/mainButton/index.vue +76 -80
- package/src/components/card/index.vue +52 -56
- package/src/components/collapsableInfoText/index.vue +76 -81
- package/src/components/deleteIcon/index.vue +28 -31
- package/src/components/draggableInputHandle/index.vue +17 -20
- package/src/components/dropdown/Dropdown.stories.js +8 -8
- package/src/components/dropdown/index.vue +72 -75
- package/src/components/errorMessage/index.vue +23 -23
- package/src/components/filter/filterSettings.vue +329 -349
- package/src/components/filter/index.vue +130 -130
- package/src/components/filter/parentDropdown.vue +40 -43
- package/src/components/icon/Icons.stories.js +4 -4
- package/src/components/icon/iconCache.js +1 -1
- package/src/components/icon/iconCollection.vue +37 -40
- package/src/components/icon/index.vue +65 -72
- package/src/components/iconWrapper/index.vue +118 -122
- package/src/components/infoCard/index.vue +17 -20
- package/src/components/infoText/index.vue +82 -88
- package/src/components/inputs/checkbox/index.vue +94 -91
- package/src/components/inputs/inputNumber/index.vue +488 -508
- package/src/components/inputs/inputNumberQuestion/index.vue +124 -127
- package/src/components/inputs/inputText/index.vue +252 -265
- package/src/components/inputs/radioButton/index.vue +120 -135
- package/src/components/inputs/searchInput/index.vue +81 -84
- package/src/components/inputs/select/index.vue +631 -644
- package/src/components/inputs/select/option/index.vue +91 -91
- package/src/components/inputs/select/select.stories.js +7 -7
- package/src/components/inputs/slider/index.vue +46 -46
- package/src/components/inputs/switchField/index.vue +152 -159
- package/src/components/inputs/textAreaInput/index.vue +113 -120
- package/src/components/inputs/toggle/index.vue +127 -137
- package/src/components/label/index.vue +61 -64
- package/src/components/markerItem/index.vue +40 -40
- package/src/components/modals/actionModal/index.vue +29 -32
- package/src/components/modals/infoModal/index.vue +27 -34
- package/src/components/modals/modal/index.vue +80 -88
- package/src/components/navigationTabs/index.vue +47 -50
- package/src/components/pageSubtitle/index.vue +29 -33
- package/src/components/pageTitle/index.vue +39 -47
- package/src/components/pagination/index.vue +62 -64
- package/src/components/progressBar/index.vue +67 -70
- package/src/components/projectMarker/index.vue +163 -172
- package/src/components/rangeSlider/Slider.vue +449 -449
- package/src/components/rangeSlider/index.vue +270 -282
- package/src/components/rangeSlider/utils/dom.js +3 -3
- package/src/components/selectedOptions/index.vue +51 -51
- package/src/components/sideMenu/index.vue +109 -117
- package/src/components/spinner/index.vue +34 -37
- package/src/components/tableDropdown/index.vue +326 -343
- package/src/components/tables/mainTable/index.vue +106 -109
- package/src/components/tables/viewTable/index.vue +92 -105
- package/src/components/threeDots/index.vue +171 -174
- package/src/components/videoThumbnail/index.vue +59 -67
- package/src/components/videoThumbnail/videoThumbnail.stories.js +6 -6
- package/.eslintrc.js +0 -125
@@ -1,157 +1,144 @@
|
|
1
1
|
<template>
|
2
2
|
<Container
|
3
|
-
:
|
4
|
-
:
|
3
|
+
:selectWidth="selectWidth"
|
4
|
+
:noRelative="noRelative"
|
5
5
|
@mouseenter="mouseEnterHandler"
|
6
6
|
@mouseleave="mouseLeaveHandler"
|
7
7
|
>
|
8
|
-
<
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
8
|
+
<input-wrapper
|
9
|
+
:hasLabel="!!label && label.length > 0"
|
10
|
+
:alignItems="alignItems"
|
11
|
+
:noRelative="noRelative"
|
12
12
|
>
|
13
|
-
<
|
14
|
-
|
15
|
-
|
16
|
-
>
|
17
|
-
<InputLabel
|
18
|
-
:font-color="
|
13
|
+
<label-wrapper v-if="label" :data-id="labelDataId">
|
14
|
+
<input-label
|
15
|
+
:fontColor="
|
19
16
|
labelFontColor || colorMode == 'dark' ? 'white' : 'eturnityGrey'
|
20
17
|
"
|
21
|
-
:
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<InfoText
|
18
|
+
:fontSize="fontSize"
|
19
|
+
>{{ label }}
|
20
|
+
<optionalLabel v-if="labelOptional">
|
21
|
+
({{ $gettext('Optional') }})</optionalLabel
|
22
|
+
>
|
23
|
+
</input-label>
|
24
|
+
<info-text
|
29
25
|
v-if="infoTextMessage"
|
30
|
-
:size="infoTextSize"
|
31
26
|
:text="infoTextMessage"
|
27
|
+
:size="infoTextSize"
|
32
28
|
/>
|
33
|
-
</
|
34
|
-
<
|
35
|
-
<
|
29
|
+
</label-wrapper>
|
30
|
+
<select-button-wrapper :disabled="disabled">
|
31
|
+
<selectButton
|
36
32
|
ref="select"
|
37
|
-
|
33
|
+
class="select-button"
|
34
|
+
@click="toggleDropdown"
|
35
|
+
:selectWidth="selectWidth"
|
36
|
+
:selectHeight="selectHeight"
|
37
|
+
:height="height"
|
38
|
+
:selectMinHeight="selectMinHeight"
|
39
|
+
:bgColor="
|
38
40
|
buttonBgColor || colorMode == 'dark' ? 'transparentBlack1' : 'white'
|
39
41
|
"
|
40
|
-
|
41
|
-
:data-id="dataId"
|
42
|
-
:disabled="disabled"
|
43
|
-
:font-color="
|
42
|
+
:fontColor="
|
44
43
|
buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
|
45
44
|
"
|
46
|
-
:
|
47
|
-
:
|
48
|
-
:
|
49
|
-
:
|
50
|
-
:no-relative="noRelative"
|
51
|
-
:padding-left="paddingLeft"
|
52
|
-
:select-height="selectHeight"
|
53
|
-
:select-min-height="selectMinHeight"
|
54
|
-
:select-width="selectWidth"
|
55
|
-
:show-border="showBorder"
|
56
|
-
:show-disabled-background="showDisabledBackground"
|
57
|
-
:table-padding-left="tablePaddingLeft"
|
58
|
-
@click="toggleDropdown"
|
45
|
+
:fontSize="fontSize"
|
46
|
+
:hasError="hasError"
|
47
|
+
:hasNoPadding="isSearchBarVisible || !hasSelectButtonPadding"
|
48
|
+
:disabled="disabled"
|
59
49
|
@keydown="onKeyDown"
|
50
|
+
:showBorder="showBorder"
|
51
|
+
:data-id="dataId"
|
52
|
+
:paddingLeft="paddingLeft"
|
53
|
+
:tablePaddingLeft="tablePaddingLeft"
|
54
|
+
:noRelative="noRelative"
|
55
|
+
:showDisabledBackground="showDisabledBackground"
|
60
56
|
>
|
61
|
-
<
|
57
|
+
<draggableInputHandle
|
62
58
|
v-if="isDraggable && !isSearchBarVisible"
|
63
59
|
:height="selectHeight"
|
64
60
|
/>
|
65
|
-
<
|
61
|
+
<inputText
|
66
62
|
v-if="isSearchBarVisible"
|
67
63
|
ref="searchInput"
|
68
|
-
|
69
|
-
|
64
|
+
tabindex="0"
|
65
|
+
inputHeight="34px"
|
66
|
+
:noBorder="true"
|
67
|
+
:fontSize="fontSize"
|
68
|
+
backgroundColor="transparent"
|
69
|
+
:fontColor="
|
70
70
|
buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
|
71
71
|
"
|
72
|
-
:font-size="fontSize"
|
73
|
-
input-height="34px"
|
74
|
-
:input-width="computedWidth"
|
75
|
-
:no-border="true"
|
76
|
-
tabindex="0"
|
77
72
|
:value="textSearch"
|
78
|
-
|
79
|
-
@input-change="searchChange"
|
73
|
+
:inputWidth="computedWidth"
|
80
74
|
@keydown.stop="onKeyDown"
|
75
|
+
@input-change="searchChange"
|
76
|
+
@click.stop
|
81
77
|
/>
|
82
|
-
<
|
78
|
+
<selector
|
83
79
|
v-else
|
84
|
-
:
|
85
|
-
:
|
86
|
-
:
|
87
|
-
>
|
88
|
-
<slot
|
89
|
-
name="selector"
|
90
|
-
:selected-value="selectedValue"
|
91
|
-
></slot>
|
92
|
-
</Selector>
|
93
|
-
<Caret
|
94
|
-
class="caret_dropdown"
|
95
|
-
@click.stop="toggleCaretDropdown"
|
80
|
+
:showBorder="showBorder"
|
81
|
+
:selectWidth="selectWidth"
|
82
|
+
:paddingLeft="paddingLeft"
|
96
83
|
>
|
97
|
-
<
|
84
|
+
<slot name="selector" :selectedValue="selectedValue"></slot>
|
85
|
+
</selector>
|
86
|
+
<Caret @click.stop="toggleCaretDropdown" class="caret_dropdown">
|
87
|
+
<icon
|
98
88
|
v-if="isDropdownOpen"
|
89
|
+
name="arrow_up"
|
90
|
+
size="12px"
|
99
91
|
:color="
|
100
92
|
caretColor || colorMode == 'dark'
|
101
93
|
? 'white'
|
102
94
|
: 'transparentBlack1'
|
103
95
|
"
|
104
|
-
name="arrow_up"
|
105
|
-
size="12px"
|
106
96
|
/>
|
107
|
-
<
|
97
|
+
<icon
|
108
98
|
v-else
|
99
|
+
name="arrow_down"
|
100
|
+
size="12px"
|
109
101
|
:color="
|
110
102
|
caretColor || colorMode == 'dark'
|
111
103
|
? 'white'
|
112
104
|
: 'transparentBlack1'
|
113
105
|
"
|
114
|
-
name="arrow_down"
|
115
|
-
size="12px"
|
116
106
|
/>
|
117
107
|
</Caret>
|
118
|
-
</
|
119
|
-
<DropdownWrapper
|
120
|
-
ref="dropdownWrapperRef"
|
121
|
-
:no-relative="noRelative"
|
122
|
-
>
|
108
|
+
</selectButton>
|
109
|
+
<DropdownWrapper ref="dropdownWrapperRef" :noRelative="noRelative">
|
123
110
|
<Teleport to="#portal-target">
|
124
|
-
<
|
125
|
-
v-show="isSelectDropdownShown"
|
111
|
+
<selectDropdown
|
126
112
|
ref="dropdown"
|
127
|
-
|
113
|
+
v-show="isSelectDropdownShown"
|
114
|
+
:dropdownPosition="dropdownPosition"
|
115
|
+
:hoveredIndex="hoveredIndex"
|
116
|
+
:hoveredValue="hoveredValue"
|
117
|
+
:isActive="isActive"
|
118
|
+
:optionWidth="getOptionWidth"
|
119
|
+
:hoveredBgColor="
|
120
|
+
colorMode == 'dark' ? '#000000' : dropdownBgColor
|
121
|
+
"
|
122
|
+
:bgColor="
|
128
123
|
dropdownBgColor || colorMode == 'dark' ? 'black' : 'white'
|
129
124
|
"
|
130
|
-
:
|
131
|
-
:font-color="
|
125
|
+
:fontColor="
|
132
126
|
dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
|
133
127
|
"
|
134
|
-
:
|
135
|
-
:
|
136
|
-
|
137
|
-
"
|
138
|
-
:hovered-index="hoveredIndex"
|
139
|
-
:hovered-value="hoveredValue"
|
140
|
-
:is-active="isActive"
|
141
|
-
:min-width="minWidth"
|
142
|
-
:no-relative="noRelative"
|
143
|
-
:option-width="getOptionWidth"
|
144
|
-
:selected-value="selectedValue"
|
145
|
-
@mouseleave="optionLeave"
|
146
|
-
@option-hovered="optionHovered"
|
128
|
+
:noRelative="noRelative"
|
129
|
+
:fontSize="fontSize"
|
130
|
+
:minWidth="minWidth"
|
131
|
+
:selectedValue="selectedValue"
|
147
132
|
@option-selected="optionSelected"
|
133
|
+
@option-hovered="optionHovered"
|
134
|
+
@mouseleave="optionLeave"
|
148
135
|
>
|
149
136
|
<slot name="dropdown"></slot>
|
150
|
-
</
|
137
|
+
</selectDropdown>
|
151
138
|
</Teleport>
|
152
139
|
</DropdownWrapper>
|
153
|
-
</
|
154
|
-
</
|
140
|
+
</select-button-wrapper>
|
141
|
+
</input-wrapper>
|
155
142
|
</Container>
|
156
143
|
</template>
|
157
144
|
|
@@ -179,17 +166,17 @@
|
|
179
166
|
// </template>
|
180
167
|
// </Select>
|
181
168
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
169
|
+
import { Teleport } from 'vue'
|
170
|
+
import styled from 'vue3-styled-components'
|
171
|
+
import InfoText from '../../infoText'
|
172
|
+
import icon from '../../icon'
|
173
|
+
import inputText from '../inputText'
|
174
|
+
import draggableInputHandle from '../../draggableInputHandle'
|
188
175
|
|
189
|
-
|
190
|
-
|
176
|
+
const CARET_WIDTH = '30px'
|
177
|
+
const BORDER_WIDTH = '1px'
|
191
178
|
|
192
|
-
|
179
|
+
const Caret = styled.div`
|
193
180
|
display: flex;
|
194
181
|
align-items: center;
|
195
182
|
justify-content: center;
|
@@ -201,12 +188,12 @@
|
|
201
188
|
margin-left: auto;
|
202
189
|
`
|
203
190
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
191
|
+
const selectorProps = {
|
192
|
+
selectWidth: String,
|
193
|
+
paddingLeft: String,
|
194
|
+
showBorder: Boolean
|
195
|
+
}
|
196
|
+
const Selector = styled('div', selectorProps)`
|
210
197
|
${(props) =>
|
211
198
|
props.selectWidth === '100%'
|
212
199
|
? 'width: 100%;'
|
@@ -222,29 +209,29 @@
|
|
222
209
|
overflow: hidden;`}
|
223
210
|
`
|
224
211
|
|
225
|
-
|
226
|
-
|
212
|
+
const labelAttrs = { fontSize: String, fontColor: String }
|
213
|
+
const InputLabel = styled('div', labelAttrs)`
|
227
214
|
color: ${(props) =>
|
228
215
|
props.theme.colors[props.fontColor]
|
229
216
|
? props.theme.colors[props.fontColor]
|
230
|
-
|
217
|
+
: props.fontColor};
|
231
218
|
font-size: ${(props) => props.fontSize};
|
232
219
|
font-weight: 700;
|
233
220
|
`
|
234
|
-
|
221
|
+
const optionalLabel = styled.span`
|
235
222
|
font-weight: 300;
|
236
223
|
`
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
224
|
+
const inputProps = {
|
225
|
+
selectWidth: String,
|
226
|
+
optionWidth: String,
|
227
|
+
noRelative: Boolean
|
228
|
+
}
|
229
|
+
const Container = styled('div', inputProps)`
|
243
230
|
width: ${(props) => props.selectWidth};
|
244
231
|
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
245
232
|
display: inline-block;
|
246
233
|
`
|
247
|
-
|
234
|
+
const LabelWrapper = styled.div`
|
248
235
|
display: inline-grid;
|
249
236
|
grid-template-columns: auto auto;
|
250
237
|
grid-gap: 12px;
|
@@ -252,30 +239,30 @@
|
|
252
239
|
justify-content: start;
|
253
240
|
`
|
254
241
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
242
|
+
const SelectButtonWrapperAttrs = {
|
243
|
+
disabled: Boolean
|
244
|
+
}
|
245
|
+
const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
|
259
246
|
${(props) => (props.disabled ? 'cursor: not-allowed' : 'cursor: pointer')};
|
260
247
|
`
|
261
248
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
249
|
+
const selectButtonAttrs = {
|
250
|
+
bgColor: String,
|
251
|
+
fontColor: String,
|
252
|
+
hasError: Boolean,
|
253
|
+
disabled: Boolean,
|
254
|
+
selectHeight: String,
|
255
|
+
selectWidth: String,
|
256
|
+
height: String,
|
257
|
+
selectMinHeight: String,
|
258
|
+
hasNoPadding: Boolean,
|
259
|
+
showBorder: Boolean,
|
260
|
+
paddingLeft: String,
|
261
|
+
noRelative: Boolean,
|
262
|
+
tablePaddingLeft: String,
|
263
|
+
showDisabledBackground: Boolean
|
264
|
+
}
|
265
|
+
const selectButton = styled('div', selectButtonAttrs)`
|
279
266
|
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
280
267
|
box-sizing: border-box;
|
281
268
|
border-radius: 4px;
|
@@ -289,7 +276,7 @@
|
|
289
276
|
: props.tablePaddingLeft
|
290
277
|
? props.tablePaddingLeft
|
291
278
|
: props.paddingLeft
|
292
|
-
|
279
|
+
}`};
|
293
280
|
text-align: left;
|
294
281
|
min-height: ${(props) =>
|
295
282
|
props.selectHeight
|
@@ -298,7 +285,7 @@
|
|
298
285
|
? props.selectMinHeight
|
299
286
|
: props.height
|
300
287
|
? props.height
|
301
|
-
|
288
|
+
: '36px'};
|
302
289
|
display: flex;
|
303
290
|
align-items: center;
|
304
291
|
height: ${(props) => props.selectHeight};
|
@@ -314,38 +301,38 @@
|
|
314
301
|
? props.theme.colors.grey5
|
315
302
|
: props.theme.colors[props.bgColor]
|
316
303
|
? props.theme.colors[props.bgColor]
|
317
|
-
|
304
|
+
: props.bgColor};
|
318
305
|
color: ${(props) =>
|
319
306
|
props.theme.colors[props.fontColor]
|
320
307
|
? props.theme.colors[props.fontColor]
|
321
|
-
|
308
|
+
: props.fontColor};
|
322
309
|
${(props) => (props.disabled ? 'pointer-events: none' : '')};
|
323
310
|
overflow: hidden;
|
324
311
|
& > .handle {
|
325
312
|
border-right: ${(props) =>
|
326
|
-
|
313
|
+
props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
|
327
314
|
1px solid;
|
328
315
|
}
|
329
316
|
`
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
317
|
+
const selectDropdownAttrs = {
|
318
|
+
hoveredBgColor: String,
|
319
|
+
bgColor: String,
|
320
|
+
fontColor: String,
|
321
|
+
optionWidth: String,
|
322
|
+
hoveredIndex: Number,
|
323
|
+
fontSize: String,
|
324
|
+
dropdownPosition: Object,
|
325
|
+
hoveredValue: Number | String,
|
326
|
+
selectedValue: Number | String,
|
327
|
+
noRelative: Boolean,
|
328
|
+
minWidth: String
|
329
|
+
}
|
330
|
+
const selectDropdown = styled('div', selectDropdownAttrs)`
|
344
331
|
box-sizing: border-box;
|
345
332
|
z-index: ${(props) => (props.isActive ? '2' : '99999')};
|
346
333
|
position: absolute;
|
347
334
|
top: ${(props) =>
|
348
|
-
|
335
|
+
props.noRelative ? 'auto' : props.dropdownPosition?.top + 'px'};
|
349
336
|
left: ${(props) => props.dropdownPosition?.left}px;
|
350
337
|
border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
|
351
338
|
border-radius: 4px;
|
@@ -360,36 +347,36 @@
|
|
360
347
|
? props.minWidth
|
361
348
|
: props.optionWidth
|
362
349
|
? props.optionWidth
|
363
|
-
|
350
|
+
: '100%'};
|
364
351
|
background-color: ${(props) =>
|
365
352
|
props.theme.colors[props.bgColor]
|
366
353
|
? props.theme.colors[props.bgColor]
|
367
|
-
|
354
|
+
: props.bgColor};
|
368
355
|
color: ${(props) =>
|
369
356
|
props.theme.colors[props.fontColor]
|
370
357
|
? props.theme.colors[props.fontColor]
|
371
|
-
|
358
|
+
: props.fontColor};
|
372
359
|
max-height: 300px;
|
373
360
|
overflow-y: auto;
|
374
361
|
& > div[data-value='${(props) => props.hoveredValue}'] {
|
375
362
|
background-color: ${(props) =>
|
376
363
|
props.theme.colors[props.hoveredBgColor]
|
377
364
|
? props.theme.colors[props.hoveredBgColor]
|
378
|
-
|
365
|
+
: props.hoveredBgColor};
|
379
366
|
}
|
380
367
|
font-size: ${(props) => props.fontSize};
|
381
368
|
`
|
382
|
-
|
383
|
-
|
384
|
-
|
369
|
+
selectDropdown.emits = ['option-hovered', 'option-selected']
|
370
|
+
const DropdownAttrs = { noRelative: Boolean }
|
371
|
+
const DropdownWrapper = styled('div', DropdownAttrs)`
|
385
372
|
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
386
373
|
`
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
374
|
+
const inputAttrs = {
|
375
|
+
alignItems: String,
|
376
|
+
hasLabel: Boolean,
|
377
|
+
noRelative: Boolean
|
378
|
+
}
|
379
|
+
const InputWrapper = styled('div', inputAttrs)`
|
393
380
|
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
394
381
|
display: grid;
|
395
382
|
width: 100%;
|
@@ -397,502 +384,502 @@
|
|
397
384
|
align-items: center;
|
398
385
|
gap: 8px;
|
399
386
|
grid-template-columns: ${(props) =>
|
400
|
-
|
387
|
+
props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
|
401
388
|
`
|
402
389
|
|
403
|
-
|
404
|
-
|
405
|
-
|
390
|
+
const DROPDOWN_HEIGHT_OFFSET = 4
|
391
|
+
const DROPDOWN_TOP_OFFSET = 21
|
392
|
+
const MIN_OPTION_LENGTH = 5
|
406
393
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
394
|
+
const DROPDOWN_MENU_POSITIONS = {
|
395
|
+
Automatic: 'automatic',
|
396
|
+
Bottom: 'bottom'
|
397
|
+
}
|
411
398
|
|
412
|
-
|
413
|
-
|
399
|
+
export default {
|
400
|
+
name: 'RCselect',
|
414
401
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
402
|
+
props: {
|
403
|
+
value: {
|
404
|
+
required: false,
|
405
|
+
default: null
|
406
|
+
},
|
407
|
+
fontSize: {
|
408
|
+
required: false,
|
409
|
+
default: '13px'
|
410
|
+
},
|
411
|
+
noRelative: {
|
412
|
+
required: false,
|
413
|
+
default: false
|
414
|
+
},
|
415
|
+
label: {
|
416
|
+
required: false
|
417
|
+
},
|
418
|
+
labelOptional: {
|
419
|
+
required: false,
|
420
|
+
default: false
|
421
|
+
},
|
422
|
+
labelDataId: {
|
423
|
+
required: false,
|
424
|
+
default: ''
|
425
|
+
},
|
426
|
+
infoTextMessage: {
|
427
|
+
required: false
|
428
|
+
},
|
429
|
+
selectWidth: {
|
430
|
+
type: String,
|
431
|
+
required: false,
|
432
|
+
default: '100%'
|
433
|
+
},
|
434
|
+
minWidth: {
|
435
|
+
required: false
|
436
|
+
},
|
437
|
+
maxWidth: {
|
438
|
+
required: false
|
439
|
+
},
|
440
|
+
selectHeight: {
|
441
|
+
type: String,
|
442
|
+
required: false,
|
443
|
+
default: null
|
432
444
|
},
|
445
|
+
height: {
|
446
|
+
required: false,
|
447
|
+
default: null
|
448
|
+
},
|
449
|
+
selectMinHeight: {
|
450
|
+
required: false,
|
451
|
+
default: '36px'
|
452
|
+
},
|
453
|
+
optionWidth: {
|
454
|
+
required: false,
|
455
|
+
default: null
|
456
|
+
},
|
457
|
+
hoverDropdown: {
|
458
|
+
required: false,
|
459
|
+
default: false
|
460
|
+
},
|
461
|
+
dropdownAutoClose: {
|
462
|
+
required: false,
|
463
|
+
default: false
|
464
|
+
},
|
465
|
+
alignItems: {
|
466
|
+
required: false,
|
467
|
+
default: 'horizontal'
|
468
|
+
},
|
469
|
+
buttonBgColor: {
|
470
|
+
required: false
|
471
|
+
},
|
472
|
+
buttonFontColor: {
|
473
|
+
required: false
|
474
|
+
},
|
475
|
+
dropdownBgColor: {
|
476
|
+
required: false,
|
477
|
+
default: 'grey5'
|
478
|
+
},
|
479
|
+
dropdownFontColor: {
|
480
|
+
required: false
|
481
|
+
},
|
482
|
+
dropDownArrowVisible: {
|
483
|
+
required: false,
|
484
|
+
default: true
|
485
|
+
},
|
486
|
+
caretColor: {
|
487
|
+
required: false
|
488
|
+
},
|
489
|
+
labelFontColor: {
|
490
|
+
required: false
|
491
|
+
},
|
492
|
+
colorMode: {
|
493
|
+
required: false,
|
494
|
+
default: 'light'
|
495
|
+
},
|
496
|
+
isSearchable: {
|
497
|
+
required: false,
|
498
|
+
default: true
|
499
|
+
},
|
500
|
+
hasError: {
|
501
|
+
required: false,
|
502
|
+
default: false
|
503
|
+
},
|
504
|
+
disabled: {
|
505
|
+
required: false,
|
506
|
+
default: false
|
507
|
+
},
|
508
|
+
isAutoSearch: {
|
509
|
+
required: false,
|
510
|
+
default: true
|
511
|
+
},
|
512
|
+
showBorder: {
|
513
|
+
required: false,
|
514
|
+
default: true
|
515
|
+
},
|
516
|
+
infoTextSize: {
|
517
|
+
required: false,
|
518
|
+
default: '14px'
|
519
|
+
},
|
520
|
+
dataId: {
|
521
|
+
type: String,
|
522
|
+
default: ''
|
523
|
+
},
|
524
|
+
hasSelectButtonPadding: {
|
525
|
+
type: Boolean,
|
526
|
+
default: true
|
527
|
+
},
|
528
|
+
isDraggable: {
|
529
|
+
type: Boolean,
|
530
|
+
default: false
|
531
|
+
},
|
532
|
+
leftPadding: {
|
533
|
+
type: String,
|
534
|
+
default: '15px'
|
535
|
+
},
|
536
|
+
tablePaddingLeft: {
|
537
|
+
required: false
|
538
|
+
},
|
539
|
+
showDisabledBackground: {
|
540
|
+
required: false,
|
541
|
+
default: true
|
542
|
+
},
|
543
|
+
minOptionLength: {
|
544
|
+
type: Number,
|
545
|
+
default: MIN_OPTION_LENGTH
|
546
|
+
},
|
547
|
+
dropdownMenuPosition: {
|
548
|
+
type: String,
|
549
|
+
default: DROPDOWN_MENU_POSITIONS.Automatic // options: ['automatic', bottom]
|
550
|
+
}
|
551
|
+
},
|
433
552
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
},
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
required: false
|
523
|
-
},
|
524
|
-
colorMode: {
|
525
|
-
required: false,
|
526
|
-
default: 'light'
|
527
|
-
},
|
528
|
-
isSearchable: {
|
529
|
-
required: false,
|
530
|
-
default: true
|
531
|
-
},
|
532
|
-
hasError: {
|
533
|
-
required: false,
|
534
|
-
default: false
|
535
|
-
},
|
536
|
-
disabled: {
|
537
|
-
required: false,
|
538
|
-
default: false
|
539
|
-
},
|
540
|
-
isAutoSearch: {
|
541
|
-
required: false,
|
542
|
-
default: true
|
543
|
-
},
|
544
|
-
showBorder: {
|
545
|
-
required: false,
|
546
|
-
default: true
|
547
|
-
},
|
548
|
-
infoTextSize: {
|
549
|
-
required: false,
|
550
|
-
default: '14px'
|
551
|
-
},
|
552
|
-
dataId: {
|
553
|
-
type: String,
|
554
|
-
default: ''
|
555
|
-
},
|
556
|
-
hasSelectButtonPadding: {
|
557
|
-
type: Boolean,
|
558
|
-
default: true
|
559
|
-
},
|
560
|
-
isDraggable: {
|
561
|
-
type: Boolean,
|
562
|
-
default: false
|
563
|
-
},
|
564
|
-
leftPadding: {
|
565
|
-
type: String,
|
566
|
-
default: '15px'
|
567
|
-
},
|
568
|
-
tablePaddingLeft: {
|
569
|
-
required: false
|
570
|
-
},
|
571
|
-
showDisabledBackground: {
|
572
|
-
required: false,
|
573
|
-
default: true
|
574
|
-
},
|
575
|
-
minOptionLength: {
|
576
|
-
type: Number,
|
577
|
-
default: MIN_OPTION_LENGTH
|
578
|
-
},
|
579
|
-
dropdownMenuPosition: {
|
580
|
-
type: String,
|
581
|
-
default: DROPDOWN_MENU_POSITIONS.Automatic // options: ['automatic', bottom]
|
553
|
+
components: {
|
554
|
+
selectButton,
|
555
|
+
SelectButtonWrapper,
|
556
|
+
selectDropdown,
|
557
|
+
Container,
|
558
|
+
InputLabel,
|
559
|
+
LabelWrapper,
|
560
|
+
optionalLabel,
|
561
|
+
InfoText,
|
562
|
+
InputWrapper,
|
563
|
+
DropdownWrapper,
|
564
|
+
icon,
|
565
|
+
Caret,
|
566
|
+
Selector,
|
567
|
+
inputText,
|
568
|
+
Teleport,
|
569
|
+
draggableInputHandle
|
570
|
+
},
|
571
|
+
|
572
|
+
data() {
|
573
|
+
return {
|
574
|
+
selectedValue: null,
|
575
|
+
paddingLeft: this.isDraggable ? '30px' : this.leftPadding,
|
576
|
+
isDropdownOpen: false,
|
577
|
+
isActive: false,
|
578
|
+
textSearch: '',
|
579
|
+
hoveredIndex: 0,
|
580
|
+
isClickOutsideActive: false,
|
581
|
+
dropdownPosition: {
|
582
|
+
left: null,
|
583
|
+
top: null
|
584
|
+
},
|
585
|
+
dropdownWidth: null,
|
586
|
+
hoveredValue: null
|
587
|
+
}
|
588
|
+
},
|
589
|
+
mounted() {
|
590
|
+
this.observeDropdownHeight()
|
591
|
+
this.observeSelectWidth()
|
592
|
+
window.addEventListener('resize', this.handleSetDropdownOffet)
|
593
|
+
},
|
594
|
+
beforeMount() {
|
595
|
+
this.selectedValue = this.value
|
596
|
+
document.addEventListener('click', this.clickOutside)
|
597
|
+
this.getDropdownPosition()
|
598
|
+
window.removeEventListener('resize', this.handleSetDropdownOffet)
|
599
|
+
if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
|
600
|
+
if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
|
601
|
+
},
|
602
|
+
unmounted() {
|
603
|
+
document.removeEventListener('click', this.clickOutside)
|
604
|
+
},
|
605
|
+
methods: {
|
606
|
+
focus() {
|
607
|
+
this.isActive = true
|
608
|
+
},
|
609
|
+
blur(e) {
|
610
|
+
this.isActive = false
|
611
|
+
this.$emit('blur', e)
|
612
|
+
},
|
613
|
+
toggleDropdown() {
|
614
|
+
this.isDropdownOpen = !this.isDropdownOpen
|
615
|
+
},
|
616
|
+
toggleCaretDropdown() {
|
617
|
+
this.isDropdownOpen = !this.isDropdownOpen
|
618
|
+
},
|
619
|
+
closeDropdown() {
|
620
|
+
this.blur()
|
621
|
+
this.clearSearch()
|
622
|
+
this.isDropdownOpen = false
|
623
|
+
},
|
624
|
+
clearSearch() {
|
625
|
+
this.textSearch = ''
|
626
|
+
this.searchChange('')
|
627
|
+
},
|
628
|
+
optionSelected(e) {
|
629
|
+
this.selectedValue = e
|
630
|
+
this.closeDropdown()
|
631
|
+
this.blur()
|
632
|
+
this.$emit('input-change', e)
|
633
|
+
},
|
634
|
+
optionHovered(e) {
|
635
|
+
this.hoveredValue = e
|
636
|
+
},
|
637
|
+
mouseEnterHandler() {
|
638
|
+
if (this.hoverDropdown) {
|
639
|
+
this.focus()
|
640
|
+
this.isDropdownOpen = true
|
582
641
|
}
|
583
642
|
},
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
selectedValue: null,
|
588
|
-
paddingLeft: this.isDraggable ? '30px' : this.leftPadding,
|
589
|
-
isDropdownOpen: false,
|
590
|
-
isActive: false,
|
591
|
-
textSearch: '',
|
592
|
-
hoveredIndex: 0,
|
593
|
-
isClickOutsideActive: false,
|
594
|
-
dropdownPosition: {
|
595
|
-
left: null,
|
596
|
-
top: null
|
597
|
-
},
|
598
|
-
dropdownWidth: null,
|
599
|
-
hoveredValue: null
|
643
|
+
mouseLeaveHandler() {
|
644
|
+
if (this.hoverDropdown) {
|
645
|
+
this.blur()
|
600
646
|
}
|
601
647
|
},
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
648
|
+
optionLeave() {
|
649
|
+
if (this.dropdownAutoClose) {
|
650
|
+
this.isDropdownOpen = false
|
651
|
+
}
|
652
|
+
},
|
653
|
+
searchChange(value) {
|
654
|
+
this.textSearch = value
|
655
|
+
this.$emit('search-change', value)
|
656
|
+
const dropdownChildren = [...this.$refs.dropdown.$el.children]
|
657
|
+
dropdownChildren.forEach((el) => {
|
658
|
+
if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
|
659
|
+
el.style.display = 'none'
|
609
660
|
|
610
|
-
|
611
|
-
},
|
612
|
-
isSearchBarVisible() {
|
613
|
-
return (
|
614
|
-
this.isSearchable &&
|
615
|
-
this.optionLength >= this.minOptionLength &&
|
616
|
-
this.isDropdownOpen
|
617
|
-
)
|
618
|
-
},
|
619
|
-
computedWidth() {
|
620
|
-
function removePX(item) {
|
621
|
-
return Number(item.replace('px', ''))
|
661
|
+
return
|
622
662
|
}
|
623
663
|
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
}
|
640
|
-
|
641
|
-
const userAgent = navigator.userAgent || navigator.vendor || window.opera
|
642
|
-
const touchCapable =
|
643
|
-
'ontouchstart' in window ||
|
644
|
-
navigator.maxTouchPoints > 0 ||
|
645
|
-
navigator.msMaxTouchPoints > 0
|
646
|
-
|
647
|
-
return (
|
648
|
-
/Android/i.test(userAgent) ||
|
649
|
-
/iPad|iPhone|iPod/.test(userAgent) ||
|
650
|
-
(/Macintosh/.test(userAgent) && touchCapable) ||
|
651
|
-
/windows phone/i.test(userAgent)
|
652
|
-
)
|
664
|
+
el.style.display = 'inherit'
|
665
|
+
})
|
666
|
+
},
|
667
|
+
clickOutside(event) {
|
668
|
+
const dropdownRef = this.$refs.dropdown
|
669
|
+
// we need to prevent closing on selecting an option, because in the case of
|
670
|
+
// a disabled option, we don't want to close the dropdown
|
671
|
+
if (!this.isClickOutsideActive) return
|
672
|
+
if (
|
673
|
+
this.$refs.select.$el == event.target ||
|
674
|
+
this.$refs.select.$el.contains(event.target) ||
|
675
|
+
event.target.id === 'more-button' ||
|
676
|
+
event.target.parentNode === dropdownRef.$el
|
677
|
+
) {
|
678
|
+
return
|
679
|
+
} else {
|
680
|
+
this.closeDropdown()
|
653
681
|
}
|
654
682
|
},
|
655
|
-
|
656
|
-
|
657
|
-
this.
|
658
|
-
}
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
await this.$nextTick()
|
666
|
-
this.handleSetDropdownOffet()
|
667
|
-
} else {
|
668
|
-
this.dropdownPosition.left = null
|
669
|
-
setTimeout(() => {
|
670
|
-
this.isClickOutsideActive = false
|
671
|
-
}, 10)
|
672
|
-
}
|
673
|
-
if (val && this.isSearchable) {
|
674
|
-
this.$nextTick(() => {
|
675
|
-
if (this.$refs.searchInput && !this.isMobileDevice) {
|
676
|
-
this.$refs.searchInput.$el.querySelector('input').focus()
|
677
|
-
}
|
678
|
-
})
|
679
|
-
}
|
683
|
+
onKeyDown(e) {
|
684
|
+
if (e.key == 'ArrowDown') {
|
685
|
+
this.onArrowPress(1)
|
686
|
+
} else if (e.key == 'ArrowUp') {
|
687
|
+
this.onArrowPress(-1)
|
688
|
+
} else if (e.key == 'Enter') {
|
689
|
+
const optionHoveredComponent = [...this.$refs.dropdown.$el.children][
|
690
|
+
(this.hoveredIndex - 1 + this.optionLength) % this.optionLength
|
691
|
+
]
|
692
|
+
this.optionSelected(optionHoveredComponent.$el.dataset.value)
|
680
693
|
}
|
681
694
|
},
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
toggleCaretDropdown() {
|
710
|
-
this.isDropdownOpen = !this.isDropdownOpen
|
711
|
-
},
|
712
|
-
closeDropdown() {
|
713
|
-
this.blur()
|
714
|
-
this.clearSearch()
|
715
|
-
this.isDropdownOpen = false
|
716
|
-
},
|
717
|
-
clearSearch() {
|
718
|
-
this.textSearch = ''
|
719
|
-
this.searchChange('')
|
720
|
-
},
|
721
|
-
optionSelected(e) {
|
722
|
-
this.selectedValue = e
|
723
|
-
this.closeDropdown()
|
724
|
-
this.blur()
|
725
|
-
this.$emit('input-change', e)
|
726
|
-
},
|
727
|
-
optionHovered(e) {
|
728
|
-
this.hoveredValue = e
|
729
|
-
},
|
730
|
-
mouseEnterHandler() {
|
731
|
-
if (this.hoverDropdown) {
|
732
|
-
this.focus()
|
733
|
-
this.isDropdownOpen = true
|
734
|
-
}
|
735
|
-
},
|
736
|
-
mouseLeaveHandler() {
|
737
|
-
if (this.hoverDropdown) {
|
738
|
-
this.blur()
|
739
|
-
}
|
740
|
-
},
|
741
|
-
optionLeave() {
|
742
|
-
if (this.dropdownAutoClose) {
|
743
|
-
this.isDropdownOpen = false
|
744
|
-
}
|
745
|
-
},
|
746
|
-
searchChange(value) {
|
747
|
-
this.textSearch = value
|
748
|
-
this.$emit('search-change', value)
|
749
|
-
const dropdownChildren = [...this.$refs.dropdown.$el.children]
|
750
|
-
dropdownChildren.forEach((el) => {
|
751
|
-
if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
|
752
|
-
el.style.display = 'none'
|
695
|
+
// If some part of the dropdown menu is outside viewport of the bottom of the screen,
|
696
|
+
// we need to offset it and display it at the top of the select dropdown instead
|
697
|
+
async getDropdownPosition() {
|
698
|
+
if (
|
699
|
+
!this.$refs.dropdownWrapperRef ||
|
700
|
+
!this.$refs.select ||
|
701
|
+
!this.$refs.dropdown
|
702
|
+
) {
|
703
|
+
return
|
704
|
+
}
|
705
|
+
await this.$nextTick()
|
706
|
+
const isDisplayedAtBottom = await this.generateDropdownPosition()
|
707
|
+
// If the dropdown menu is going to be displayed at the bottom,
|
708
|
+
// we need reverify its position after a dom update (nextTick)
|
709
|
+
await this.$nextTick()
|
710
|
+
if (isDisplayedAtBottom) this.generateDropdownPosition()
|
711
|
+
},
|
712
|
+
async generateDropdownPosition() {
|
713
|
+
const isDropdownNotCompletelyVisible =
|
714
|
+
await this.isBottomOfDropdownOutOfViewport()
|
715
|
+
const dropdownWrapperEl = this.$refs.dropdownWrapperRef.$el
|
716
|
+
const selectButtonHeight = this.$refs.select.$el.clientHeight
|
717
|
+
const dropdownHeight = this.$refs.dropdown.$el.clientHeight
|
718
|
+
const dropdownWrapperRelativeHeight =
|
719
|
+
dropdownWrapperEl.getBoundingClientRect().top +
|
720
|
+
window.scrollY +
|
721
|
+
DROPDOWN_HEIGHT_OFFSET
|
753
722
|
|
754
|
-
|
755
|
-
|
723
|
+
const top =
|
724
|
+
isDropdownNotCompletelyVisible ||
|
725
|
+
(!isDropdownNotCompletelyVisible &&
|
726
|
+
this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom)
|
727
|
+
? dropdownWrapperRelativeHeight
|
728
|
+
: dropdownWrapperRelativeHeight -
|
729
|
+
dropdownHeight -
|
730
|
+
selectButtonHeight -
|
731
|
+
DROPDOWN_TOP_OFFSET
|
732
|
+
const left = this.dropdownPosition.left
|
733
|
+
? this.dropdownPosition.left
|
734
|
+
: dropdownWrapperEl.getBoundingClientRect().left + window.scrollX
|
756
735
|
|
757
|
-
|
758
|
-
})
|
759
|
-
},
|
760
|
-
clickOutside(event) {
|
761
|
-
const dropdownRef = this.$refs.dropdown
|
762
|
-
// we need to prevent closing on selecting an option, because in the case of
|
763
|
-
// a disabled option, we don't want to close the dropdown
|
764
|
-
if (!this.isClickOutsideActive) return
|
765
|
-
if (
|
766
|
-
this.$refs.select.$el == event.target ||
|
767
|
-
this.$refs.select.$el.contains(event.target) ||
|
768
|
-
event.target.id === 'more-button' ||
|
769
|
-
event.target.parentNode === dropdownRef.$el
|
770
|
-
) {
|
771
|
-
return
|
772
|
-
} else {
|
773
|
-
this.closeDropdown()
|
774
|
-
}
|
775
|
-
},
|
776
|
-
onKeyDown(e) {
|
777
|
-
if (e.key == 'ArrowDown') {
|
778
|
-
this.onArrowPress(1)
|
779
|
-
} else if (e.key == 'ArrowUp') {
|
780
|
-
this.onArrowPress(-1)
|
781
|
-
} else if (e.key == 'Enter') {
|
782
|
-
const optionHoveredComponent = [...this.$refs.dropdown.$el.children][
|
783
|
-
(this.hoveredIndex - 1 + this.optionLength) % this.optionLength
|
784
|
-
]
|
785
|
-
this.optionSelected(optionHoveredComponent.$el.dataset.value)
|
786
|
-
}
|
787
|
-
},
|
788
|
-
// If some part of the dropdown menu is outside viewport of the bottom of the screen,
|
789
|
-
// we need to offset it and display it at the top of the select dropdown instead
|
790
|
-
async getDropdownPosition() {
|
791
|
-
if (
|
792
|
-
!this.$refs.dropdownWrapperRef ||
|
793
|
-
!this.$refs.select ||
|
794
|
-
!this.$refs.dropdown
|
795
|
-
) {
|
796
|
-
return
|
797
|
-
}
|
798
|
-
await this.$nextTick()
|
799
|
-
const isDisplayedAtBottom = await this.generateDropdownPosition()
|
800
|
-
// If the dropdown menu is going to be displayed at the bottom,
|
801
|
-
// we need reverify its position after a dom update (nextTick)
|
802
|
-
await this.$nextTick()
|
803
|
-
if (isDisplayedAtBottom) this.generateDropdownPosition()
|
804
|
-
},
|
805
|
-
async generateDropdownPosition() {
|
806
|
-
const isDropdownNotCompletelyVisible =
|
807
|
-
await this.isBottomOfDropdownOutOfViewport()
|
808
|
-
const dropdownWrapperEl = this.$refs.dropdownWrapperRef.$el
|
809
|
-
const selectButtonHeight = this.$refs.select.$el.clientHeight
|
810
|
-
const dropdownHeight = this.$refs.dropdown.$el.clientHeight
|
811
|
-
const dropdownWrapperRelativeHeight =
|
812
|
-
dropdownWrapperEl.getBoundingClientRect().top +
|
813
|
-
window.scrollY +
|
814
|
-
DROPDOWN_HEIGHT_OFFSET
|
736
|
+
this.dropdownPosition = { left: Math.floor(left), top: Math.floor(top) }
|
815
737
|
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
const left = this.dropdownPosition.left
|
826
|
-
? this.dropdownPosition.left
|
827
|
-
: dropdownWrapperEl.getBoundingClientRect().left + window.scrollX
|
738
|
+
return isDropdownNotCompletelyVisible
|
739
|
+
},
|
740
|
+
async isBottomOfDropdownOutOfViewport() {
|
741
|
+
if (
|
742
|
+
!this.$refs.dropdown ||
|
743
|
+
this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom
|
744
|
+
) {
|
745
|
+
return false
|
746
|
+
}
|
828
747
|
|
829
|
-
|
748
|
+
await this.$nextTick()
|
749
|
+
const rect = this.$refs.dropdown.$el.getBoundingClientRect()
|
750
|
+
const windowHeight =
|
751
|
+
window.innerHeight || document.documentElement.clientHeight
|
830
752
|
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
753
|
+
if (windowHeight <= 650) return true
|
754
|
+
|
755
|
+
// using Math.floor because the offsets may contain decimals we are not going to consider here
|
756
|
+
return Math.floor(rect.top) + Math.floor(rect.height) <= windowHeight
|
757
|
+
},
|
758
|
+
observeDropdownHeight() {
|
759
|
+
if (!this.$refs.dropdown) return
|
760
|
+
this.dropdownResizeObserver = new ResizeObserver(() => {
|
761
|
+
this.$nextTick(() => this.getDropdownPosition())
|
762
|
+
})
|
763
|
+
this.dropdownResizeObserver.observe(this.$refs.dropdown.$el)
|
764
|
+
},
|
765
|
+
handleSetDropdownOffet() {
|
766
|
+
if (!this.$refs.select) return
|
767
|
+
this.dropdownPosition.left = Math.floor(
|
768
|
+
this.$refs.select.$el.getBoundingClientRect().left
|
769
|
+
)
|
770
|
+
this.getDropdownWidth()
|
771
|
+
},
|
772
|
+
observeSelectWidth() {
|
773
|
+
if (!this.$refs.select) return
|
774
|
+
this.selectResizeObserver = new ResizeObserver(() =>
|
775
|
+
// eslint-disable-next-line vue/valid-next-tick
|
776
|
+
this.$nextTick(() => this.getDropdownWidth())
|
777
|
+
)
|
778
|
+
this.selectResizeObserver.observe(this.$refs.dropdown.$el)
|
779
|
+
},
|
780
|
+
async getDropdownWidth() {
|
781
|
+
if (!this.$refs.select) return
|
782
|
+
await this.$nextTick()
|
783
|
+
this.dropdownWidth = `${this.$refs.select.$el.clientWidth}px`
|
784
|
+
},
|
785
|
+
onArrowPress(dir) {
|
786
|
+
let newHoveredElem
|
787
|
+
const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
|
788
|
+
`[data-value="${this.hoveredValue}"]`
|
789
|
+
)
|
790
|
+
if (currentHoveredElem) {
|
791
|
+
if (dir > 0) {
|
792
|
+
newHoveredElem = currentHoveredElem.nextElementSibling
|
793
|
+
} else {
|
794
|
+
newHoveredElem = currentHoveredElem.previousElementSibling
|
795
|
+
}
|
796
|
+
if (newHoveredElem) {
|
797
|
+
this.hoveredValue = newHoveredElem.getAttribute('data-value')
|
798
|
+
const topPos = newHoveredElem.offsetTop
|
799
|
+
this.$refs.dropdown.$el.scrollTop = topPos
|
839
800
|
}
|
801
|
+
}
|
802
|
+
}
|
803
|
+
},
|
804
|
+
computed: {
|
805
|
+
optionLength() {
|
806
|
+
if (this.isDropdownOpen) {
|
807
|
+
return this.$refs.dropdown.$el.childElementCount > 1
|
808
|
+
? this.$refs.dropdown.$el.childElementCount
|
809
|
+
: this.$refs.dropdown.$el.children[0].childElementCount
|
810
|
+
}
|
840
811
|
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
812
|
+
return 0
|
813
|
+
},
|
814
|
+
isSearchBarVisible() {
|
815
|
+
return (
|
816
|
+
this.isSearchable &&
|
817
|
+
this.optionLength >= this.minOptionLength &&
|
818
|
+
this.isDropdownOpen
|
819
|
+
)
|
820
|
+
},
|
821
|
+
computedWidth() {
|
822
|
+
function removePX(item) {
|
823
|
+
return Number(item.replace('px', ''))
|
824
|
+
}
|
845
825
|
|
846
|
-
|
826
|
+
return this.selectWidth === '100%'
|
827
|
+
? '100%'
|
828
|
+
: removePX(this.selectWidth) - removePX(CARET_WIDTH) + 'px'
|
829
|
+
},
|
830
|
+
getOptionWidth() {
|
831
|
+
if (this.optionWidth) return this.optionWidth
|
847
832
|
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
this.
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
833
|
+
return this.dropdownWidth
|
834
|
+
},
|
835
|
+
isSelectDropdownShown() {
|
836
|
+
return (
|
837
|
+
this.isDropdownOpen &&
|
838
|
+
this.dropdownPosition.left !== null &&
|
839
|
+
(!this.isSearchable || this.isSearchable)
|
840
|
+
)
|
841
|
+
},
|
842
|
+
isMobileDevice() {
|
843
|
+
const userAgent = navigator.userAgent || navigator.vendor || window.opera
|
844
|
+
const touchCapable =
|
845
|
+
'ontouchstart' in window ||
|
846
|
+
navigator.maxTouchPoints > 0 ||
|
847
|
+
navigator.msMaxTouchPoints > 0
|
848
|
+
|
849
|
+
return (
|
850
|
+
/Android/i.test(userAgent) ||
|
851
|
+
/iPad|iPhone|iPod/.test(userAgent) ||
|
852
|
+
(/Macintosh/.test(userAgent) && touchCapable) ||
|
853
|
+
/windows phone/i.test(userAgent)
|
854
|
+
)
|
855
|
+
}
|
856
|
+
},
|
857
|
+
watch: {
|
858
|
+
value(val) {
|
859
|
+
this.selectedValue = val
|
860
|
+
},
|
861
|
+
async isDropdownOpen(val) {
|
862
|
+
if (val) {
|
863
|
+
this.$emit('on-dropdown-open')
|
864
|
+
setTimeout(() => {
|
865
|
+
this.isClickOutsideActive = true
|
866
|
+
}, 10)
|
875
867
|
await this.$nextTick()
|
876
|
-
this.
|
877
|
-
}
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
newHoveredElem = currentHoveredElem.previousElementSibling
|
888
|
-
}
|
889
|
-
if (newHoveredElem) {
|
890
|
-
this.hoveredValue = newHoveredElem.getAttribute('data-value')
|
891
|
-
const topPos = newHoveredElem.offsetTop
|
892
|
-
this.$refs.dropdown.$el.scrollTop = topPos
|
868
|
+
this.handleSetDropdownOffet()
|
869
|
+
} else {
|
870
|
+
this.dropdownPosition.left = null
|
871
|
+
setTimeout(() => {
|
872
|
+
this.isClickOutsideActive = false
|
873
|
+
}, 10)
|
874
|
+
}
|
875
|
+
if (val && this.isSearchable) {
|
876
|
+
this.$nextTick(() => {
|
877
|
+
if (this.$refs.searchInput && !this.isMobileDevice) {
|
878
|
+
this.$refs.searchInput.$el.querySelector('input').focus()
|
893
879
|
}
|
894
|
-
}
|
880
|
+
})
|
895
881
|
}
|
896
882
|
}
|
897
883
|
}
|
884
|
+
}
|
898
885
|
</script>
|