@eturnity/eturnity_reusable_components 7.18.0-qa-dev03.0 → 7.20.0--EPDM-10564.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/.storybook/preview.js +1 -1
- package/babel.config.js +2 -4
- package/package.json +18 -23
- package/src/App.vue +2 -2
- package/src/assets/svgIcons/split.svg +88 -6
- package/src/components/addNewButton/index.vue +5 -3
- package/src/components/buttons/buttonIcon/index.vue +1 -1
- package/src/components/buttons/closeButton/index.vue +1 -1
- package/src/components/buttons/mainButton/index.vue +6 -1
- package/src/components/card/index.vue +25 -24
- package/src/components/deleteIcon/DeleteIcon.stories.js +7 -7
- package/src/components/deleteIcon/index.vue +47 -30
- package/src/components/draggableInputHandle/index.vue +24 -25
- package/src/components/dropdown/index.vue +129 -110
- package/src/components/errorMessage/index.vue +10 -5
- package/src/components/filter/filterSettings.vue +59 -97
- package/src/components/filter/index.vue +3 -3
- package/src/components/filter/parentDropdown.vue +2 -2
- package/src/components/icon/iconCache.js +23 -0
- package/src/components/icon/iconCollection.vue +2 -2
- package/src/components/icon/index.vue +67 -75
- package/src/components/iconWrapper/index.vue +1 -4
- package/src/components/infoCard/index.vue +2 -3
- package/src/components/infoText/index.vue +2 -2
- package/src/components/inputs/checkbox/index.vue +21 -6
- package/src/components/inputs/inputNumber/index.vue +10 -10
- package/src/components/inputs/inputNumberQuestion/index.vue +1 -1
- package/src/components/inputs/inputText/index.vue +3 -3
- package/src/components/inputs/radioButton/index.vue +1 -1
- package/src/components/inputs/searchInput/index.vue +28 -11
- package/src/components/inputs/select/index.vue +295 -67
- package/src/components/inputs/select/option/index.vue +49 -12
- package/src/components/inputs/slider/index.vue +16 -16
- package/src/components/inputs/switchField/index.vue +2 -2
- package/src/components/inputs/textAreaInput/index.vue +1 -1
- package/src/components/inputs/toggle/index.vue +2 -2
- package/src/components/label/index.vue +27 -31
- package/src/components/markerItem/index.vue +86 -0
- package/src/components/modals/modal/index.vue +2 -6
- package/src/components/navigationTabs/index.vue +27 -20
- package/src/components/pageSubtitle/index.vue +1 -1
- package/src/components/pageTitle/index.vue +13 -18
- package/src/components/pagination/index.vue +3 -3
- package/src/components/progressBar/index.vue +1 -1
- package/src/components/projectMarker/index.vue +16 -9
- package/src/components/sideMenu/index.vue +1 -1
- package/src/components/spinner/index.vue +7 -11
- package/src/components/tableDropdown/index.vue +35 -45
- package/src/components/tables/mainTable/exampleNested.vue +1 -1
- package/src/components/tables/mainTable/index.vue +10 -9
- package/src/components/tables/viewTable/index.vue +2 -2
- package/src/components/threeDots/index.vue +1 -1
- package/src/components/videoThumbnail/index.vue +95 -100
- package/src/main.js +4 -11
- package/src/assets/svgIcons/anchor.svg +0 -18
- package/src/assets/svgIcons/flatten_roof.svg +0 -20
@@ -1,12 +1,14 @@
|
|
1
1
|
<template>
|
2
2
|
<Container
|
3
3
|
:selectWidth="selectWidth"
|
4
|
+
:noRelative="noRelative"
|
4
5
|
@mouseenter="mouseEnterHandler"
|
5
6
|
@mouseleave="mouseLeaveHandler"
|
6
7
|
>
|
7
8
|
<input-wrapper
|
8
9
|
:hasLabel="!!label && label.length > 0"
|
9
10
|
:alignItems="alignItems"
|
11
|
+
:noRelative="noRelative"
|
10
12
|
>
|
11
13
|
<label-wrapper v-if="label" :data-id="labelDataId">
|
12
14
|
<input-label
|
@@ -28,7 +30,9 @@
|
|
28
30
|
<select-button-wrapper :disabled="disabled">
|
29
31
|
<selectButton
|
30
32
|
ref="select"
|
33
|
+
class="select-button"
|
31
34
|
@click="toggleDropdown"
|
35
|
+
:selectWidth="selectWidth"
|
32
36
|
:selectHeight="selectHeight"
|
33
37
|
:height="height"
|
34
38
|
:selectMinHeight="selectMinHeight"
|
@@ -39,12 +43,15 @@
|
|
39
43
|
buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
|
40
44
|
"
|
41
45
|
:hasError="hasError"
|
42
|
-
:
|
46
|
+
:hasNoPadding="isSearchBarVisible || !hasSelectButtonPadding"
|
43
47
|
:disabled="disabled"
|
44
|
-
@keydown
|
48
|
+
@keydown="onKeyDown"
|
45
49
|
:showBorder="showBorder"
|
46
50
|
:data-id="dataId"
|
47
51
|
:paddingLeft="paddingLeft"
|
52
|
+
:tablePaddingLeft="tablePaddingLeft"
|
53
|
+
:noRelative="noRelative"
|
54
|
+
:showDisabledBackground="showDisabledBackground"
|
48
55
|
>
|
49
56
|
<draggableInputHandle
|
50
57
|
v-if="isDraggable && !isSearchBarVisible"
|
@@ -64,7 +71,7 @@
|
|
64
71
|
:value="textSearch"
|
65
72
|
@keydown.stop="onKeyDown"
|
66
73
|
@input-change="searchChange"
|
67
|
-
@click.
|
74
|
+
@click.stop
|
68
75
|
/>
|
69
76
|
<selector
|
70
77
|
v-else
|
@@ -74,7 +81,7 @@
|
|
74
81
|
>
|
75
82
|
<slot name="selector" :selectedValue="selectedValue"></slot>
|
76
83
|
</selector>
|
77
|
-
<Caret @click.stop="toggleCaretDropdown">
|
84
|
+
<Caret @click.stop="toggleCaretDropdown" class="caret_dropdown">
|
78
85
|
<icon
|
79
86
|
v-if="isDropdownOpen"
|
80
87
|
name="arrow_up"
|
@@ -97,26 +104,36 @@
|
|
97
104
|
/>
|
98
105
|
</Caret>
|
99
106
|
</selectButton>
|
100
|
-
<DropdownWrapper>
|
101
|
-
<
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
107
|
+
<DropdownWrapper ref="dropdownWrapperRef" :noRelative="noRelative">
|
108
|
+
<Teleport to="#portal-target">
|
109
|
+
<selectDropdown
|
110
|
+
ref="dropdown"
|
111
|
+
v-show="isSelectDropdownShown"
|
112
|
+
:dropdownPosition="dropdownPosition"
|
113
|
+
:hoveredIndex="hoveredIndex"
|
114
|
+
:hoveredValue="hoveredValue"
|
115
|
+
:isActive="isActive"
|
116
|
+
:optionWidth="getOptionWidth"
|
117
|
+
:hoveredBgColor="
|
118
|
+
colorMode == 'dark' ? '#000000' : dropdownBgColor
|
119
|
+
"
|
120
|
+
:bgColor="
|
121
|
+
dropdownBgColor || colorMode == 'dark' ? 'black' : 'white'
|
122
|
+
"
|
123
|
+
:fontColor="
|
124
|
+
dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
|
125
|
+
"
|
126
|
+
:noRelative="noRelative"
|
127
|
+
:fontSize="fontSize"
|
128
|
+
:minWidth="minWidth"
|
129
|
+
:selectedValue="selectedValue"
|
130
|
+
@option-selected="optionSelected"
|
131
|
+
@option-hovered="optionHovered"
|
132
|
+
@mouseleave="optionLeave"
|
133
|
+
>
|
134
|
+
<slot name="dropdown"></slot>
|
135
|
+
</selectDropdown>
|
136
|
+
</Teleport>
|
120
137
|
</DropdownWrapper>
|
121
138
|
</select-button-wrapper>
|
122
139
|
</input-wrapper>
|
@@ -131,8 +148,9 @@
|
|
131
148
|
// optionWidth="50%"
|
132
149
|
// label="that is a label"
|
133
150
|
// alignItems="vertical"
|
134
|
-
// label-data-id="test-
|
151
|
+
// label-data-id="test-label-data-id"
|
135
152
|
// data-id="test-data-id"
|
153
|
+
// :hasSelectButtonPadding="false"
|
136
154
|
// >
|
137
155
|
// <template #selector="{selectedValue}">
|
138
156
|
// value selected: {{selectedValue}}
|
@@ -145,7 +163,8 @@
|
|
145
163
|
// </template>
|
146
164
|
// </Select>
|
147
165
|
|
148
|
-
import
|
166
|
+
import { Teleport } from 'vue'
|
167
|
+
import styled from 'vue3-styled-components'
|
149
168
|
import InfoText from '../../infoText'
|
150
169
|
import icon from '../../icon'
|
151
170
|
import inputText from '../inputText'
|
@@ -161,7 +180,7 @@ const Caret = styled.div`
|
|
161
180
|
width: ${CARET_WIDTH};
|
162
181
|
min-width: ${CARET_WIDTH};
|
163
182
|
height: 100%;
|
164
|
-
align-items:
|
183
|
+
align-items: center;
|
165
184
|
cursor: pointer;
|
166
185
|
margin-left: auto;
|
167
186
|
`
|
@@ -172,7 +191,10 @@ const selectorProps = {
|
|
172
191
|
showBorder: Boolean
|
173
192
|
}
|
174
193
|
const Selector = styled('div', selectorProps)`
|
175
|
-
${(props) =>
|
194
|
+
${(props) =>
|
195
|
+
props.selectWidth === '100%'
|
196
|
+
? 'width: 100%;'
|
197
|
+
: `width: calc(${props.selectWidth} -
|
176
198
|
(
|
177
199
|
${CARET_WIDTH} +
|
178
200
|
${props.paddingLeft}
|
@@ -181,8 +203,7 @@ const Selector = styled('div', selectorProps)`
|
|
181
203
|
);
|
182
204
|
white-space: nowrap;
|
183
205
|
text-overflow: ellipsis;
|
184
|
-
overflow: hidden;`
|
185
|
-
}
|
206
|
+
overflow: hidden;`}
|
186
207
|
`
|
187
208
|
|
188
209
|
const labelAttrs = { fontSize: String, fontColor: String }
|
@@ -197,10 +218,14 @@ const InputLabel = styled('div', labelAttrs)`
|
|
197
218
|
const optionalLabel = styled.span`
|
198
219
|
font-weight: 300;
|
199
220
|
`
|
200
|
-
const inputProps = {
|
221
|
+
const inputProps = {
|
222
|
+
selectWidth: String,
|
223
|
+
optionWidth: String,
|
224
|
+
noRelative: Boolean
|
225
|
+
}
|
201
226
|
const Container = styled('div', inputProps)`
|
202
227
|
width: ${(props) => props.selectWidth};
|
203
|
-
position: relative;
|
228
|
+
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
204
229
|
display: inline-block;
|
205
230
|
`
|
206
231
|
const LabelWrapper = styled.div`
|
@@ -224,18 +249,29 @@ const selectButtonAttrs = {
|
|
224
249
|
hasError: Boolean,
|
225
250
|
disabled: Boolean,
|
226
251
|
selectHeight: String,
|
252
|
+
selectWidth: String,
|
227
253
|
height: String,
|
228
254
|
selectMinHeight: String,
|
229
|
-
|
255
|
+
hasNoPadding: Boolean,
|
230
256
|
showBorder: Boolean,
|
231
|
-
paddingLeft: String
|
257
|
+
paddingLeft: String,
|
258
|
+
noRelative: Boolean,
|
259
|
+
tablePaddingLeft: String,
|
260
|
+
showDisabledBackground: Boolean
|
232
261
|
}
|
233
262
|
const selectButton = styled('div', selectButtonAttrs)`
|
234
|
-
position: relative;
|
263
|
+
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
235
264
|
box-sizing: border-box;
|
236
265
|
border-radius: 4px;
|
266
|
+
max-width: ${(props) => (props.selectWidth ? props.selectWidth : '100%')};
|
237
267
|
${(props) =>
|
238
|
-
props.isSearchBarVisible
|
268
|
+
props.isSearchBarVisible
|
269
|
+
? ''
|
270
|
+
: `padding-left: ${
|
271
|
+
props.tablePaddingLeft ? props.tablePaddingLeft : props.paddingLeft
|
272
|
+
}`};
|
273
|
+
${(props) =>
|
274
|
+
props.hasNoPadding ? '' : `padding-left: ${props.paddingLeft}`};
|
239
275
|
text-align: left;
|
240
276
|
min-height: ${(props) =>
|
241
277
|
props.selectHeight
|
@@ -247,7 +283,7 @@ const selectButton = styled('div', selectButtonAttrs)`
|
|
247
283
|
: '36px'};
|
248
284
|
display: flex;
|
249
285
|
align-items: center;
|
250
|
-
|
286
|
+
height: ${(props) => props.selectHeight};
|
251
287
|
${({ showBorder, theme, hasError }) =>
|
252
288
|
showBorder &&
|
253
289
|
`
|
@@ -256,7 +292,7 @@ const selectButton = styled('div', selectButtonAttrs)`
|
|
256
292
|
}
|
257
293
|
`}
|
258
294
|
background-color:${(props) =>
|
259
|
-
props.disabled
|
295
|
+
props.disabled && props.showDisabledBackground
|
260
296
|
? props.theme.colors.grey5
|
261
297
|
: props.theme.colors[props.bgColor]
|
262
298
|
? props.theme.colors[props.bgColor]
|
@@ -279,14 +315,20 @@ const selectDropdownAttrs = {
|
|
279
315
|
fontColor: String,
|
280
316
|
optionWidth: String,
|
281
317
|
hoveredIndex: Number,
|
318
|
+
fontSize: String,
|
319
|
+
dropdownPosition: Object,
|
282
320
|
hoveredValue: Number | String,
|
283
|
-
selectedValue: Number | String
|
321
|
+
selectedValue: Number | String,
|
322
|
+
noRelative: Boolean,
|
323
|
+
minWidth: String
|
284
324
|
}
|
285
325
|
const selectDropdown = styled('div', selectDropdownAttrs)`
|
286
326
|
box-sizing: border-box;
|
287
|
-
z-index: ${(props) => (props.isActive ? '2' : '
|
327
|
+
z-index: ${(props) => (props.isActive ? '2' : '99999')};
|
288
328
|
position: absolute;
|
289
|
-
top:
|
329
|
+
top: ${(props) =>
|
330
|
+
props.noRelative ? 'auto' : props.dropdownPosition?.top + 'px'};
|
331
|
+
left: ${(props) => props.dropdownPosition?.left}px;
|
290
332
|
border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
|
291
333
|
border-radius: 4px;
|
292
334
|
display: flex;
|
@@ -295,6 +337,7 @@ const selectDropdown = styled('div', selectDropdownAttrs)`
|
|
295
337
|
padding: 0px;
|
296
338
|
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
297
339
|
width: ${(props) => (props.optionWidth ? props.optionWidth : '100%')};
|
340
|
+
min-width: ${(props) => (props.minWidth ? props.minWidth : '100%')};
|
298
341
|
background-color: ${(props) =>
|
299
342
|
props.theme.colors[props.bgColor]
|
300
343
|
? props.theme.colors[props.bgColor]
|
@@ -311,19 +354,36 @@ const selectDropdown = styled('div', selectDropdownAttrs)`
|
|
311
354
|
? props.theme.colors[props.hoveredBgColor]
|
312
355
|
: props.hoveredBgColor};
|
313
356
|
}
|
357
|
+
font-size: ${(props) => props.fontSize};
|
314
358
|
`
|
315
|
-
|
316
|
-
|
359
|
+
selectDropdown.emits = ['option-hovered', 'option-selected']
|
360
|
+
const DropdownAttrs = { noRelative: Boolean }
|
361
|
+
const DropdownWrapper = styled('div', DropdownAttrs)`
|
362
|
+
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
317
363
|
`
|
318
|
-
const inputAttrs = {
|
364
|
+
const inputAttrs = {
|
365
|
+
alignItems: String,
|
366
|
+
hasLabel: Boolean,
|
367
|
+
noRelative: Boolean
|
368
|
+
}
|
319
369
|
const InputWrapper = styled('div', inputAttrs)`
|
320
|
-
position: relative;
|
370
|
+
position: ${(props) => (props.noRelative ? 'static' : 'relative')};
|
321
371
|
display: grid;
|
322
372
|
align-items: center;
|
323
373
|
gap: 8px;
|
324
374
|
grid-template-columns: ${(props) =>
|
325
375
|
props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
|
326
376
|
`
|
377
|
+
|
378
|
+
const DROPDOWN_HEIGHT_OFFSET = 4
|
379
|
+
const DROPDOWN_TOP_OFFSET = 21
|
380
|
+
const MIN_OPTION_LENGTH = 5
|
381
|
+
|
382
|
+
const DROPDOWN_MENU_POSITIONS = {
|
383
|
+
Automatic: 'automatic',
|
384
|
+
Bottom: 'bottom'
|
385
|
+
}
|
386
|
+
|
327
387
|
export default {
|
328
388
|
name: 'RCselect',
|
329
389
|
|
@@ -336,6 +396,10 @@ export default {
|
|
336
396
|
required: false,
|
337
397
|
default: '13px'
|
338
398
|
},
|
399
|
+
noRelative: {
|
400
|
+
required: false,
|
401
|
+
default: false
|
402
|
+
},
|
339
403
|
label: {
|
340
404
|
required: false
|
341
405
|
},
|
@@ -368,6 +432,9 @@ export default {
|
|
368
432
|
required: false,
|
369
433
|
default: '36px'
|
370
434
|
},
|
435
|
+
minWidth: {
|
436
|
+
required: false
|
437
|
+
},
|
371
438
|
optionWidth: {
|
372
439
|
required: false,
|
373
440
|
default: null
|
@@ -435,9 +502,28 @@ export default {
|
|
435
502
|
type: String,
|
436
503
|
default: ''
|
437
504
|
},
|
505
|
+
hasSelectButtonPadding: {
|
506
|
+
type: Boolean,
|
507
|
+
default: true
|
508
|
+
},
|
438
509
|
isDraggable: {
|
439
510
|
type: Boolean,
|
440
511
|
default: false
|
512
|
+
},
|
513
|
+
tablePaddingLeft: {
|
514
|
+
required: false
|
515
|
+
},
|
516
|
+
showDisabledBackground: {
|
517
|
+
required: false,
|
518
|
+
default: true
|
519
|
+
},
|
520
|
+
minOptionLength: {
|
521
|
+
type: Number,
|
522
|
+
default: MIN_OPTION_LENGTH
|
523
|
+
},
|
524
|
+
dropdownMenuPosition: {
|
525
|
+
type: String,
|
526
|
+
default: DROPDOWN_MENU_POSITIONS.Automatic // options: ['automatic', bottom]
|
441
527
|
}
|
442
528
|
},
|
443
529
|
|
@@ -456,6 +542,7 @@ export default {
|
|
456
542
|
Caret,
|
457
543
|
Selector,
|
458
544
|
inputText,
|
545
|
+
Teleport,
|
459
546
|
draggableInputHandle
|
460
547
|
},
|
461
548
|
|
@@ -467,23 +554,38 @@ export default {
|
|
467
554
|
isActive: false,
|
468
555
|
textSearch: '',
|
469
556
|
hoveredIndex: 0,
|
470
|
-
|
471
|
-
|
557
|
+
isClickOutsideActive: false,
|
558
|
+
dropdownPosition: {
|
559
|
+
left: null,
|
560
|
+
top: null
|
561
|
+
},
|
562
|
+
dropdownWidth: null,
|
563
|
+
hoveredValue: null
|
472
564
|
}
|
473
565
|
},
|
474
566
|
mounted() {
|
567
|
+
this.observeDropdownHeight()
|
568
|
+
this.observeSelectWidth()
|
569
|
+
window.addEventListener('resize', this.handleSetDropdownOffet)
|
570
|
+
},
|
571
|
+
beforeMount() {
|
475
572
|
this.selectedValue = this.value
|
476
573
|
document.addEventListener('click', this.clickOutside)
|
574
|
+
this.getDropdownPosition()
|
575
|
+
window.removeEventListener('resize', this.handleSetDropdownOffet)
|
576
|
+
if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
|
577
|
+
if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
|
477
578
|
},
|
478
|
-
|
579
|
+
unmounted() {
|
479
580
|
document.removeEventListener('click', this.clickOutside)
|
480
581
|
},
|
481
582
|
methods: {
|
482
583
|
focus() {
|
483
584
|
this.isActive = true
|
484
585
|
},
|
485
|
-
blur() {
|
586
|
+
blur(e) {
|
486
587
|
this.isActive = false
|
588
|
+
this.$emit('blur', e)
|
487
589
|
},
|
488
590
|
toggleDropdown() {
|
489
591
|
this.isDropdownOpen = !this.isDropdownOpen
|
@@ -499,6 +601,9 @@ export default {
|
|
499
601
|
this.blur()
|
500
602
|
this.isDropdownOpen = false
|
501
603
|
},
|
604
|
+
clearSearch() {
|
605
|
+
this.textSearch = ''
|
606
|
+
},
|
502
607
|
optionSelected(e) {
|
503
608
|
this.selectedValue = e
|
504
609
|
this.closeDropdown()
|
@@ -527,15 +632,15 @@ export default {
|
|
527
632
|
searchChange(value) {
|
528
633
|
this.textSearch = value
|
529
634
|
this.$emit('search-change', value)
|
530
|
-
this.$refs.dropdown.$children
|
531
|
-
|
532
|
-
.
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
635
|
+
const dropdownChildren = [...this.$refs.dropdown.$el.children]
|
636
|
+
dropdownChildren.forEach((el) => {
|
637
|
+
if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
|
638
|
+
el.style.display = 'none'
|
639
|
+
|
640
|
+
return
|
641
|
+
}
|
642
|
+
el.style.display = 'inherit'
|
643
|
+
})
|
539
644
|
},
|
540
645
|
clickOutside(event) {
|
541
646
|
const dropdownRef = this.$refs.dropdown
|
@@ -545,6 +650,7 @@ export default {
|
|
545
650
|
if (
|
546
651
|
this.$refs.select.$el == event.target ||
|
547
652
|
this.$refs.select.$el.contains(event.target) ||
|
653
|
+
event.target.id === 'more-button' ||
|
548
654
|
event.target.parentNode === dropdownRef.$el
|
549
655
|
) {
|
550
656
|
return
|
@@ -558,13 +664,101 @@ export default {
|
|
558
664
|
} else if (e.key == 'ArrowUp') {
|
559
665
|
this.onArrowPress(-1)
|
560
666
|
} else if (e.key == 'Enter') {
|
561
|
-
const optionHoveredComponent =
|
562
|
-
this
|
563
|
-
|
564
|
-
]
|
667
|
+
const optionHoveredComponent = [...this.$refs.dropdown.$el.children][
|
668
|
+
(this.hoveredIndex - 1 + this.optionLength) % this.optionLength
|
669
|
+
]
|
565
670
|
this.optionSelected(optionHoveredComponent.$el.dataset.value)
|
566
671
|
}
|
567
672
|
},
|
673
|
+
// If some part of the dropdown menu is outside viewport of the bottom of the screen,
|
674
|
+
// we need to offset it and display it at the top of the select dropdown instead
|
675
|
+
async getDropdownPosition() {
|
676
|
+
if (
|
677
|
+
!this.$refs.dropdownWrapperRef ||
|
678
|
+
!this.$refs.select ||
|
679
|
+
!this.$refs.dropdown
|
680
|
+
) {
|
681
|
+
return
|
682
|
+
}
|
683
|
+
await this.$nextTick()
|
684
|
+
const isDisplayedAtBottom = await this.generateDropdownPosition()
|
685
|
+
// If the dropdown menu is going to be displayed at the bottom,
|
686
|
+
// we need reverify its position after a dom update (nextTick)
|
687
|
+
await this.$nextTick()
|
688
|
+
if (isDisplayedAtBottom) this.generateDropdownPosition()
|
689
|
+
},
|
690
|
+
async generateDropdownPosition() {
|
691
|
+
const isDropdownNotCompletelyVisible =
|
692
|
+
await this.isBottomOfDropdownOutOfViewport()
|
693
|
+
const dropdownWrapperEl = this.$refs.dropdownWrapperRef.$el
|
694
|
+
const selectButtonHeight = this.$refs.select.$el.clientHeight
|
695
|
+
const dropdownHeight = this.$refs.dropdown.$el.clientHeight
|
696
|
+
const dropdownWrapperRelativeHeight =
|
697
|
+
dropdownWrapperEl.getBoundingClientRect().top +
|
698
|
+
window.scrollY +
|
699
|
+
DROPDOWN_HEIGHT_OFFSET
|
700
|
+
|
701
|
+
const top =
|
702
|
+
isDropdownNotCompletelyVisible ||
|
703
|
+
(!isDropdownNotCompletelyVisible &&
|
704
|
+
this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom)
|
705
|
+
? dropdownWrapperRelativeHeight
|
706
|
+
: dropdownWrapperRelativeHeight -
|
707
|
+
dropdownHeight -
|
708
|
+
selectButtonHeight -
|
709
|
+
DROPDOWN_TOP_OFFSET
|
710
|
+
const left = this.dropdownPosition.left
|
711
|
+
? this.dropdownPosition.left
|
712
|
+
: dropdownWrapperEl.getBoundingClientRect().left + window.scrollX
|
713
|
+
|
714
|
+
this.dropdownPosition = { left: Math.floor(left), top: Math.floor(top) }
|
715
|
+
|
716
|
+
return isDropdownNotCompletelyVisible
|
717
|
+
},
|
718
|
+
async isBottomOfDropdownOutOfViewport() {
|
719
|
+
if (
|
720
|
+
!this.$refs.dropdown ||
|
721
|
+
this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom
|
722
|
+
) {
|
723
|
+
return false
|
724
|
+
}
|
725
|
+
|
726
|
+
await this.$nextTick()
|
727
|
+
const rect = this.$refs.dropdown.$el.getBoundingClientRect()
|
728
|
+
const windowHeight =
|
729
|
+
window.innerHeight || document.documentElement.clientHeight
|
730
|
+
|
731
|
+
if (windowHeight <= 650) return true
|
732
|
+
|
733
|
+
// using Math.floor because the offsets may contain decimals we are not going to consider here
|
734
|
+
return Math.floor(rect.top) + Math.floor(rect.height) <= windowHeight
|
735
|
+
},
|
736
|
+
observeDropdownHeight() {
|
737
|
+
if (!this.$refs.dropdown) return
|
738
|
+
this.dropdownResizeObserver = new ResizeObserver(() => {
|
739
|
+
this.$nextTick(() => this.getDropdownPosition())
|
740
|
+
})
|
741
|
+
this.dropdownResizeObserver.observe(this.$refs.dropdown.$el)
|
742
|
+
},
|
743
|
+
handleSetDropdownOffet() {
|
744
|
+
if (!this.$refs.select) return
|
745
|
+
this.dropdownPosition.left = Math.floor(
|
746
|
+
this.$refs.select.$el.getBoundingClientRect().left
|
747
|
+
)
|
748
|
+
this.getDropdownWidth()
|
749
|
+
},
|
750
|
+
observeSelectWidth() {
|
751
|
+
if (!this.$refs.select) return
|
752
|
+
this.selectResizeObserver = new ResizeObserver(() =>
|
753
|
+
this.$nextTick(() => this.getDropdownWidth())
|
754
|
+
)
|
755
|
+
this.selectResizeObserver.observe(this.$refs.dropdown.$el)
|
756
|
+
},
|
757
|
+
async getDropdownWidth() {
|
758
|
+
if (!this.$refs.select) return
|
759
|
+
await this.$nextTick()
|
760
|
+
this.dropdownWidth = `${this.$refs.select.$el.clientWidth}px`
|
761
|
+
},
|
568
762
|
onArrowPress(dir) {
|
569
763
|
let newHoveredElem
|
570
764
|
const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
|
@@ -590,33 +784,67 @@ export default {
|
|
590
784
|
computed: {
|
591
785
|
optionLength() {
|
592
786
|
if (this.isDropdownOpen) {
|
593
|
-
return this.$refs.dropdown.$el.childElementCount
|
787
|
+
return this.$refs.dropdown.$el.childElementCount > 1
|
788
|
+
? this.$refs.dropdown.$el.childElementCount
|
789
|
+
: this.$refs.dropdown.$el.children[0].childElementCount
|
594
790
|
}
|
595
791
|
|
596
792
|
return 0
|
597
793
|
},
|
598
794
|
isSearchBarVisible() {
|
599
|
-
return
|
795
|
+
return (
|
796
|
+
this.isSearchable &&
|
797
|
+
this.optionLength >= this.minOptionLength &&
|
798
|
+
this.isDropdownOpen
|
799
|
+
)
|
800
|
+
},
|
801
|
+
getOptionWidth() {
|
802
|
+
if (this.optionWidth) return this.optionWidth
|
803
|
+
|
804
|
+
return this.dropdownWidth
|
805
|
+
},
|
806
|
+
isSelectDropdownShown() {
|
807
|
+
return (
|
808
|
+
this.isDropdownOpen &&
|
809
|
+
this.dropdownPosition.left !== null &&
|
810
|
+
(!this.isSearchable || this.isSearchable)
|
811
|
+
)
|
812
|
+
},
|
813
|
+
isMobileDevice() {
|
814
|
+
const userAgent = navigator.userAgent || navigator.vendor || window.opera
|
815
|
+
const touchCapable =
|
816
|
+
'ontouchstart' in window ||
|
817
|
+
navigator.maxTouchPoints > 0 ||
|
818
|
+
navigator.msMaxTouchPoints > 0
|
819
|
+
|
820
|
+
return (
|
821
|
+
/Android/i.test(userAgent) ||
|
822
|
+
/iPad|iPhone|iPod/.test(userAgent) ||
|
823
|
+
(/Macintosh/.test(userAgent) && touchCapable) ||
|
824
|
+
/windows phone/i.test(userAgent)
|
825
|
+
)
|
600
826
|
}
|
601
827
|
},
|
602
828
|
watch: {
|
603
829
|
value(val) {
|
604
830
|
this.selectedValue = val
|
605
831
|
},
|
606
|
-
isDropdownOpen(val) {
|
607
|
-
this.$emit('is-dropdown-open', val)
|
832
|
+
async isDropdownOpen(val) {
|
608
833
|
if (val) {
|
609
834
|
setTimeout(() => {
|
610
835
|
this.isClickOutsideActive = true
|
611
836
|
}, 10)
|
837
|
+
await this.$nextTick()
|
838
|
+
this.handleSetDropdownOffet()
|
612
839
|
} else {
|
840
|
+
this.dropdownPosition.left = null
|
613
841
|
setTimeout(() => {
|
614
842
|
this.isClickOutsideActive = false
|
615
843
|
}, 10)
|
616
844
|
}
|
617
845
|
if (val && this.isSearchable) {
|
618
846
|
this.$nextTick(() => {
|
619
|
-
if (this.$refs.searchInput) {
|
847
|
+
if (this.$refs.searchInput && !this.isMobileDevice) {
|
620
848
|
this.$refs.searchInput.$el.querySelector('input').focus()
|
621
849
|
}
|
622
850
|
})
|