@eturnity/eturnity_reusable_components 7.24.3-EPDM-11250.0 → 7.24.3-EPDM-11320.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.eslintrc.js +125 -0
  2. package/package.json +6 -20
  3. package/src/App.vue +75 -70
  4. package/src/components/addNewButton/index.vue +24 -27
  5. package/src/components/banner/actionBanner/index.vue +32 -30
  6. package/src/components/banner/banner/index.vue +88 -80
  7. package/src/components/banner/infoBanner/index.vue +36 -44
  8. package/src/components/buttons/buttonIcon/index.vue +83 -78
  9. package/src/components/buttons/closeButton/index.vue +26 -26
  10. package/src/components/buttons/mainButton/index.vue +80 -76
  11. package/src/components/card/index.vue +56 -52
  12. package/src/components/collapsableInfoText/index.vue +81 -76
  13. package/src/components/deleteIcon/index.vue +31 -28
  14. package/src/components/draggableInputHandle/index.vue +20 -17
  15. package/src/components/dropdown/Dropdown.stories.js +8 -8
  16. package/src/components/dropdown/index.vue +75 -72
  17. package/src/components/errorMessage/index.vue +23 -23
  18. package/src/components/filter/filterSettings.vue +349 -329
  19. package/src/components/filter/index.vue +130 -130
  20. package/src/components/filter/parentDropdown.vue +43 -40
  21. package/src/components/icon/Icons.stories.js +4 -4
  22. package/src/components/icon/iconCache.js +1 -1
  23. package/src/components/icon/iconCollection.vue +40 -37
  24. package/src/components/icon/index.vue +72 -65
  25. package/src/components/iconWrapper/index.vue +122 -118
  26. package/src/components/infoCard/index.vue +20 -17
  27. package/src/components/infoText/index.vue +88 -82
  28. package/src/components/inputs/checkbox/index.vue +91 -94
  29. package/src/components/inputs/inputNumber/index.vue +508 -488
  30. package/src/components/inputs/inputNumberQuestion/index.vue +127 -124
  31. package/src/components/inputs/inputText/index.vue +265 -252
  32. package/src/components/inputs/radioButton/index.vue +135 -120
  33. package/src/components/inputs/searchInput/index.vue +84 -81
  34. package/src/components/inputs/select/index.vue +644 -631
  35. package/src/components/inputs/select/option/index.vue +91 -91
  36. package/src/components/inputs/select/select.stories.js +7 -7
  37. package/src/components/inputs/slider/index.vue +46 -46
  38. package/src/components/inputs/switchField/index.vue +159 -152
  39. package/src/components/inputs/textAreaInput/index.vue +120 -113
  40. package/src/components/inputs/toggle/index.vue +137 -127
  41. package/src/components/label/index.vue +64 -61
  42. package/src/components/markerItem/index.vue +40 -40
  43. package/src/components/modals/actionModal/index.vue +32 -29
  44. package/src/components/modals/infoModal/index.vue +34 -27
  45. package/src/components/modals/modal/index.vue +88 -80
  46. package/src/components/navigationTabs/index.vue +50 -47
  47. package/src/components/pageSubtitle/index.vue +33 -29
  48. package/src/components/pageTitle/index.vue +47 -39
  49. package/src/components/pagination/index.vue +64 -62
  50. package/src/components/progressBar/index.vue +70 -67
  51. package/src/components/projectMarker/index.vue +172 -163
  52. package/src/components/rangeSlider/Slider.vue +449 -449
  53. package/src/components/rangeSlider/index.vue +282 -270
  54. package/src/components/rangeSlider/utils/dom.js +3 -3
  55. package/src/components/selectedOptions/index.vue +51 -51
  56. package/src/components/sideMenu/index.vue +117 -109
  57. package/src/components/spinner/index.vue +37 -34
  58. package/src/components/tableDropdown/index.vue +343 -326
  59. package/src/components/tables/mainTable/index.vue +109 -106
  60. package/src/components/tables/viewTable/index.vue +105 -92
  61. package/src/components/threeDots/index.vue +174 -171
  62. package/src/components/videoThumbnail/index.vue +67 -59
  63. package/src/components/videoThumbnail/videoThumbnail.stories.js +6 -6
  64. package/src/helpers/numberConverter.js +1 -3
  65. package/src/helpers/translateLang.js +10 -13
  66. package/.prettierrc +0 -7
  67. package/public/favicon.ico +0 -0
  68. package/public/index.html +0 -17
@@ -1,144 +1,157 @@
1
1
  <template>
2
2
  <Container
3
- :selectWidth="selectWidth"
4
- :noRelative="noRelative"
3
+ :no-relative="noRelative"
4
+ :select-width="selectWidth"
5
5
  @mouseenter="mouseEnterHandler"
6
6
  @mouseleave="mouseLeaveHandler"
7
7
  >
8
- <input-wrapper
9
- :hasLabel="!!label && label.length > 0"
10
- :alignItems="alignItems"
11
- :noRelative="noRelative"
8
+ <InputWrapper
9
+ :align-items="alignItems"
10
+ :has-label="!!label && label.length > 0"
11
+ :no-relative="noRelative"
12
12
  >
13
- <label-wrapper v-if="label" :data-id="labelDataId">
14
- <input-label
15
- :fontColor="
13
+ <LabelWrapper
14
+ v-if="label"
15
+ :data-id="labelDataId"
16
+ >
17
+ <InputLabel
18
+ :font-color="
16
19
  labelFontColor || colorMode == 'dark' ? 'white' : 'eturnityGrey'
17
20
  "
18
- :fontSize="fontSize"
19
- >{{ label }}
20
- <optionalLabel v-if="labelOptional">
21
- ({{ $gettext('Optional') }})</optionalLabel
22
- >
23
- </input-label>
24
- <info-text
21
+ :font-size="fontSize"
22
+ >
23
+ {{ label }}
24
+ <OptionalLabel v-if="labelOptional">
25
+ ({{ $gettext('Optional') }})
26
+ </OptionalLabel>
27
+ </InputLabel>
28
+ <InfoText
25
29
  v-if="infoTextMessage"
26
- :text="infoTextMessage"
27
30
  :size="infoTextSize"
31
+ :text="infoTextMessage"
28
32
  />
29
- </label-wrapper>
30
- <select-button-wrapper :disabled="disabled">
31
- <selectButton
33
+ </LabelWrapper>
34
+ <SelectButtonWrapper :disabled="disabled">
35
+ <SelectButton
32
36
  ref="select"
33
- class="select-button"
34
- @click="toggleDropdown"
35
- :selectWidth="selectWidth"
36
- :selectHeight="selectHeight"
37
- :height="height"
38
- :selectMinHeight="selectMinHeight"
39
- :bgColor="
37
+ :bg-color="
40
38
  buttonBgColor || colorMode == 'dark' ? 'transparentBlack1' : 'white'
41
39
  "
42
- :fontColor="
40
+ class="select-button"
41
+ :data-id="dataId"
42
+ :disabled="disabled"
43
+ :font-color="
43
44
  buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
44
45
  "
45
- :fontSize="fontSize"
46
- :hasError="hasError"
47
- :hasNoPadding="isSearchBarVisible || !hasSelectButtonPadding"
48
- :disabled="disabled"
46
+ :font-size="fontSize"
47
+ :has-error="hasError"
48
+ :has-no-padding="isSearchBarVisible || !hasSelectButtonPadding"
49
+ :height="height"
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"
49
59
  @keydown="onKeyDown"
50
- :showBorder="showBorder"
51
- :data-id="dataId"
52
- :paddingLeft="paddingLeft"
53
- :tablePaddingLeft="tablePaddingLeft"
54
- :noRelative="noRelative"
55
- :showDisabledBackground="showDisabledBackground"
56
60
  >
57
- <draggableInputHandle
61
+ <DraggableInputHandle
58
62
  v-if="isDraggable && !isSearchBarVisible"
59
63
  :height="selectHeight"
60
64
  />
61
- <inputText
65
+ <InputText
62
66
  v-if="isSearchBarVisible"
63
67
  ref="searchInput"
64
- tabindex="0"
65
- inputHeight="34px"
66
- :noBorder="true"
67
- :fontSize="fontSize"
68
- backgroundColor="transparent"
69
- :fontColor="
68
+ background-color="transparent"
69
+ :font-color="
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"
72
77
  :value="textSearch"
73
- :inputWidth="computedWidth"
74
- @keydown.stop="onKeyDown"
75
- @input-change="searchChange"
76
78
  @click.stop
79
+ @input-change="searchChange"
80
+ @keydown.stop="onKeyDown"
77
81
  />
78
- <selector
82
+ <Selector
79
83
  v-else
80
- :showBorder="showBorder"
81
- :selectWidth="selectWidth"
82
- :paddingLeft="paddingLeft"
84
+ :padding-left="paddingLeft"
85
+ :select-width="selectWidth"
86
+ :show-border="showBorder"
87
+ >
88
+ <slot
89
+ name="selector"
90
+ :selected-value="selectedValue"
91
+ ></slot>
92
+ </Selector>
93
+ <Caret
94
+ class="caret_dropdown"
95
+ @click.stop="toggleCaretDropdown"
83
96
  >
84
- <slot name="selector" :selectedValue="selectedValue"></slot>
85
- </selector>
86
- <Caret @click.stop="toggleCaretDropdown" class="caret_dropdown">
87
- <icon
97
+ <RCIcon
88
98
  v-if="isDropdownOpen"
89
- name="arrow_up"
90
- size="12px"
91
99
  :color="
92
100
  caretColor || colorMode == 'dark'
93
101
  ? 'white'
94
102
  : 'transparentBlack1'
95
103
  "
104
+ name="arrow_up"
105
+ size="12px"
96
106
  />
97
- <icon
107
+ <RCIcon
98
108
  v-else
99
- name="arrow_down"
100
- size="12px"
101
109
  :color="
102
110
  caretColor || colorMode == 'dark'
103
111
  ? 'white'
104
112
  : 'transparentBlack1'
105
113
  "
114
+ name="arrow_down"
115
+ size="12px"
106
116
  />
107
117
  </Caret>
108
- </selectButton>
109
- <DropdownWrapper ref="dropdownWrapperRef" :noRelative="noRelative">
118
+ </SelectButton>
119
+ <DropdownWrapper
120
+ ref="dropdownWrapperRef"
121
+ :no-relative="noRelative"
122
+ >
110
123
  <Teleport to="#portal-target">
111
- <selectDropdown
112
- ref="dropdown"
124
+ <SelectDropdown
113
125
  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="
126
+ ref="dropdown"
127
+ :bg-color="
123
128
  dropdownBgColor || colorMode == 'dark' ? 'black' : 'white'
124
129
  "
125
- :fontColor="
130
+ :dropdown-position="dropdownPosition"
131
+ :font-color="
126
132
  dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
127
133
  "
128
- :noRelative="noRelative"
129
- :fontSize="fontSize"
130
- :minWidth="minWidth"
131
- :selectedValue="selectedValue"
132
- @option-selected="optionSelected"
133
- @option-hovered="optionHovered"
134
+ :font-size="fontSize"
135
+ :hovered-bg-color="
136
+ colorMode == 'dark' ? '#000000' : dropdownBgColor
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"
134
145
  @mouseleave="optionLeave"
146
+ @option-hovered="optionHovered"
147
+ @option-selected="optionSelected"
135
148
  >
136
149
  <slot name="dropdown"></slot>
137
- </selectDropdown>
150
+ </SelectDropdown>
138
151
  </Teleport>
139
152
  </DropdownWrapper>
140
- </select-button-wrapper>
141
- </input-wrapper>
153
+ </SelectButtonWrapper>
154
+ </InputWrapper>
142
155
  </Container>
143
156
  </template>
144
157
 
@@ -166,17 +179,17 @@
166
179
  // </template>
167
180
  // </Select>
168
181
 
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'
182
+ import { Teleport } from 'vue'
183
+ import styled from 'vue3-styled-components'
184
+ import InfoText from '../../infoText'
185
+ import RCIcon from '../../icon'
186
+ import InputText from '../inputText'
187
+ import DraggableInputHandle from '../../draggableInputHandle'
175
188
 
176
- const CARET_WIDTH = '30px'
177
- const BORDER_WIDTH = '1px'
189
+ const CARET_WIDTH = '30px'
190
+ const BORDER_WIDTH = '1px'
178
191
 
179
- const Caret = styled.div`
192
+ const Caret = styled.div`
180
193
  display: flex;
181
194
  align-items: center;
182
195
  justify-content: center;
@@ -188,12 +201,12 @@ const Caret = styled.div`
188
201
  margin-left: auto;
189
202
  `
190
203
 
191
- const selectorProps = {
192
- selectWidth: String,
193
- paddingLeft: String,
194
- showBorder: Boolean
195
- }
196
- const Selector = styled('div', selectorProps)`
204
+ const selectorProps = {
205
+ selectWidth: String,
206
+ paddingLeft: String,
207
+ showBorder: Boolean
208
+ }
209
+ const Selector = styled('div', selectorProps)`
197
210
  ${(props) =>
198
211
  props.selectWidth === '100%'
199
212
  ? 'width: 100%;'
@@ -209,29 +222,29 @@ const Selector = styled('div', selectorProps)`
209
222
  overflow: hidden;`}
210
223
  `
211
224
 
212
- const labelAttrs = { fontSize: String, fontColor: String }
213
- const InputLabel = styled('div', labelAttrs)`
225
+ const labelAttrs = { fontSize: String, fontColor: String }
226
+ const InputLabel = styled('div', labelAttrs)`
214
227
  color: ${(props) =>
215
228
  props.theme.colors[props.fontColor]
216
229
  ? props.theme.colors[props.fontColor]
217
- : props.fontColor};
230
+ : props.fontColor};
218
231
  font-size: ${(props) => props.fontSize};
219
232
  font-weight: 700;
220
233
  `
221
- const optionalLabel = styled.span`
234
+ const OptionalLabel = styled.span`
222
235
  font-weight: 300;
223
236
  `
224
- const inputProps = {
225
- selectWidth: String,
226
- optionWidth: String,
227
- noRelative: Boolean
228
- }
229
- const Container = styled('div', inputProps)`
237
+ const inputProps = {
238
+ selectWidth: String,
239
+ optionWidth: String,
240
+ noRelative: Boolean
241
+ }
242
+ const Container = styled('div', inputProps)`
230
243
  width: ${(props) => props.selectWidth};
231
244
  position: ${(props) => (props.noRelative ? 'static' : 'relative')};
232
245
  display: inline-block;
233
246
  `
234
- const LabelWrapper = styled.div`
247
+ const LabelWrapper = styled.div`
235
248
  display: inline-grid;
236
249
  grid-template-columns: auto auto;
237
250
  grid-gap: 12px;
@@ -239,30 +252,30 @@ const LabelWrapper = styled.div`
239
252
  justify-content: start;
240
253
  `
241
254
 
242
- const SelectButtonWrapperAttrs = {
243
- disabled: Boolean
244
- }
245
- const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
255
+ const SelectButtonWrapperAttrs = {
256
+ disabled: Boolean
257
+ }
258
+ const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
246
259
  ${(props) => (props.disabled ? 'cursor: not-allowed' : 'cursor: pointer')};
247
260
  `
248
261
 
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)`
262
+ const selectButtonAttrs = {
263
+ bgColor: String,
264
+ fontColor: String,
265
+ hasError: Boolean,
266
+ disabled: Boolean,
267
+ selectHeight: String,
268
+ selectWidth: String,
269
+ height: String,
270
+ selectMinHeight: String,
271
+ hasNoPadding: Boolean,
272
+ showBorder: Boolean,
273
+ paddingLeft: String,
274
+ noRelative: Boolean,
275
+ tablePaddingLeft: String,
276
+ showDisabledBackground: Boolean
277
+ }
278
+ const SelectButton = styled('div', selectButtonAttrs)`
266
279
  position: ${(props) => (props.noRelative ? 'static' : 'relative')};
267
280
  box-sizing: border-box;
268
281
  border-radius: 4px;
@@ -276,7 +289,7 @@ const selectButton = styled('div', selectButtonAttrs)`
276
289
  : props.tablePaddingLeft
277
290
  ? props.tablePaddingLeft
278
291
  : props.paddingLeft
279
- }`};
292
+ }`};
280
293
  text-align: left;
281
294
  min-height: ${(props) =>
282
295
  props.selectHeight
@@ -285,7 +298,7 @@ const selectButton = styled('div', selectButtonAttrs)`
285
298
  ? props.selectMinHeight
286
299
  : props.height
287
300
  ? props.height
288
- : '36px'};
301
+ : '36px'};
289
302
  display: flex;
290
303
  align-items: center;
291
304
  height: ${(props) => props.selectHeight};
@@ -301,38 +314,38 @@ const selectButton = styled('div', selectButtonAttrs)`
301
314
  ? props.theme.colors.grey5
302
315
  : props.theme.colors[props.bgColor]
303
316
  ? props.theme.colors[props.bgColor]
304
- : props.bgColor};
317
+ : props.bgColor};
305
318
  color: ${(props) =>
306
319
  props.theme.colors[props.fontColor]
307
320
  ? props.theme.colors[props.fontColor]
308
- : props.fontColor};
321
+ : props.fontColor};
309
322
  ${(props) => (props.disabled ? 'pointer-events: none' : '')};
310
323
  overflow: hidden;
311
324
  & > .handle {
312
325
  border-right: ${(props) =>
313
- props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
326
+ props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
314
327
  1px solid;
315
328
  }
316
329
  `
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)`
330
+ const selectDropdownAttrs = {
331
+ hoveredBgColor: String,
332
+ bgColor: String,
333
+ fontColor: String,
334
+ optionWidth: String,
335
+ hoveredIndex: Number,
336
+ fontSize: String,
337
+ dropdownPosition: Object,
338
+ hoveredValue: Number | String,
339
+ selectedValue: Number | String,
340
+ noRelative: Boolean,
341
+ minWidth: String
342
+ }
343
+ const SelectDropdown = styled('div', selectDropdownAttrs)`
331
344
  box-sizing: border-box;
332
345
  z-index: ${(props) => (props.isActive ? '2' : '99999')};
333
346
  position: absolute;
334
347
  top: ${(props) =>
335
- props.noRelative ? 'auto' : props.dropdownPosition?.top + 'px'};
348
+ props.noRelative ? 'auto' : props.dropdownPosition?.top + 'px'};
336
349
  left: ${(props) => props.dropdownPosition?.left}px;
337
350
  border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
338
351
  border-radius: 4px;
@@ -347,36 +360,36 @@ const selectDropdown = styled('div', selectDropdownAttrs)`
347
360
  ? props.minWidth
348
361
  : props.optionWidth
349
362
  ? props.optionWidth
350
- : '100%'};
363
+ : '100%'};
351
364
  background-color: ${(props) =>
352
365
  props.theme.colors[props.bgColor]
353
366
  ? props.theme.colors[props.bgColor]
354
- : props.bgColor};
367
+ : props.bgColor};
355
368
  color: ${(props) =>
356
369
  props.theme.colors[props.fontColor]
357
370
  ? props.theme.colors[props.fontColor]
358
- : props.fontColor};
371
+ : props.fontColor};
359
372
  max-height: 300px;
360
373
  overflow-y: auto;
361
374
  & > div[data-value='${(props) => props.hoveredValue}'] {
362
375
  background-color: ${(props) =>
363
376
  props.theme.colors[props.hoveredBgColor]
364
377
  ? props.theme.colors[props.hoveredBgColor]
365
- : props.hoveredBgColor};
378
+ : props.hoveredBgColor};
366
379
  }
367
380
  font-size: ${(props) => props.fontSize};
368
381
  `
369
- selectDropdown.emits = ['option-hovered', 'option-selected']
370
- const DropdownAttrs = { noRelative: Boolean }
371
- const DropdownWrapper = styled('div', DropdownAttrs)`
382
+ selectDropdown.emits = ['option-hovered', 'option-selected']
383
+ const DropdownAttrs = { noRelative: Boolean }
384
+ const DropdownWrapper = styled('div', DropdownAttrs)`
372
385
  position: ${(props) => (props.noRelative ? 'static' : 'relative')};
373
386
  `
374
- const inputAttrs = {
375
- alignItems: String,
376
- hasLabel: Boolean,
377
- noRelative: Boolean
378
- }
379
- const InputWrapper = styled('div', inputAttrs)`
387
+ const inputAttrs = {
388
+ alignItems: String,
389
+ hasLabel: Boolean,
390
+ noRelative: Boolean
391
+ }
392
+ const InputWrapper = styled('div', inputAttrs)`
380
393
  position: ${(props) => (props.noRelative ? 'static' : 'relative')};
381
394
  display: grid;
382
395
  width: 100%;
@@ -384,502 +397,502 @@ const InputWrapper = styled('div', inputAttrs)`
384
397
  align-items: center;
385
398
  gap: 8px;
386
399
  grid-template-columns: ${(props) =>
387
- props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
400
+ props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
388
401
  `
389
402
 
390
- const DROPDOWN_HEIGHT_OFFSET = 4
391
- const DROPDOWN_TOP_OFFSET = 21
392
- const MIN_OPTION_LENGTH = 5
403
+ const DROPDOWN_HEIGHT_OFFSET = 4
404
+ const DROPDOWN_TOP_OFFSET = 21
405
+ const MIN_OPTION_LENGTH = 5
393
406
 
394
- const DROPDOWN_MENU_POSITIONS = {
395
- Automatic: 'automatic',
396
- Bottom: 'bottom'
397
- }
407
+ const DROPDOWN_MENU_POSITIONS = {
408
+ Automatic: 'automatic',
409
+ Bottom: 'bottom'
410
+ }
398
411
 
399
- export default {
400
- name: 'RCselect',
412
+ export default {
413
+ name: 'RCselect',
401
414
 
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
415
+ components: {
416
+ SelectButton,
417
+ SelectButtonWrapper,
418
+ SelectDropdown,
419
+ Container,
420
+ InputLabel,
421
+ LabelWrapper,
422
+ OptionalLabel,
423
+ InfoText,
424
+ InputWrapper,
425
+ DropdownWrapper,
426
+ RCIcon,
427
+ Caret,
428
+ Selector,
429
+ InputText,
430
+ Teleport,
431
+ DraggableInputHandle
444
432
  },
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
- },
552
-
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
433
 
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
641
- }
642
- },
643
- mouseLeaveHandler() {
644
- if (this.hoverDropdown) {
645
- this.blur()
434
+ props: {
435
+ value: {
436
+ required: false,
437
+ default: null
438
+ },
439
+ fontSize: {
440
+ required: false,
441
+ default: '13px'
442
+ },
443
+ noRelative: {
444
+ required: false,
445
+ default: false
446
+ },
447
+ label: {
448
+ required: false
449
+ },
450
+ labelOptional: {
451
+ required: false,
452
+ default: false
453
+ },
454
+ labelDataId: {
455
+ required: false,
456
+ default: ''
457
+ },
458
+ infoTextMessage: {
459
+ required: false
460
+ },
461
+ selectWidth: {
462
+ type: String,
463
+ required: false,
464
+ default: '100%'
465
+ },
466
+ minWidth: {
467
+ required: false
468
+ },
469
+ maxWidth: {
470
+ required: false
471
+ },
472
+ selectHeight: {
473
+ type: String,
474
+ required: false,
475
+ default: null
476
+ },
477
+ height: {
478
+ required: false,
479
+ default: null
480
+ },
481
+ selectMinHeight: {
482
+ required: false,
483
+ default: '36px'
484
+ },
485
+ optionWidth: {
486
+ required: false,
487
+ default: null
488
+ },
489
+ hoverDropdown: {
490
+ required: false,
491
+ default: false
492
+ },
493
+ dropdownAutoClose: {
494
+ required: false,
495
+ default: false
496
+ },
497
+ alignItems: {
498
+ required: false,
499
+ default: 'horizontal'
500
+ },
501
+ buttonBgColor: {
502
+ required: false
503
+ },
504
+ buttonFontColor: {
505
+ required: false
506
+ },
507
+ dropdownBgColor: {
508
+ required: false,
509
+ default: 'grey5'
510
+ },
511
+ dropdownFontColor: {
512
+ required: false
513
+ },
514
+ dropDownArrowVisible: {
515
+ required: false,
516
+ default: true
517
+ },
518
+ caretColor: {
519
+ required: false
520
+ },
521
+ labelFontColor: {
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]
646
582
  }
647
583
  },
648
- optionLeave() {
649
- if (this.dropdownAutoClose) {
650
- this.isDropdownOpen = false
584
+
585
+ data() {
586
+ return {
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
651
600
  }
652
601
  },
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'
660
-
661
- return
602
+ computed: {
603
+ optionLength() {
604
+ if (this.isDropdownOpen) {
605
+ return this.$refs.dropdown.$el.childElementCount > 1
606
+ ? this.$refs.dropdown.$el.childElementCount
607
+ : this.$refs.dropdown.$el.children[0].childElementCount
662
608
  }
663
609
 
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()
681
- }
682
- },
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)
693
- }
694
- },
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
610
+ return 0
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', ''))
622
+ }
722
623
 
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
624
+ return this.selectWidth === '100%'
625
+ ? '100%'
626
+ : removePX(this.selectWidth) - removePX(CARET_WIDTH) + 'px'
627
+ },
628
+ getOptionWidth() {
629
+ if (this.optionWidth) return this.optionWidth
735
630
 
736
- this.dropdownPosition = { left: Math.floor(left), top: Math.floor(top) }
631
+ return this.dropdownWidth
632
+ },
633
+ isSelectDropdownShown() {
634
+ return (
635
+ this.isDropdownOpen &&
636
+ this.dropdownPosition.left !== null &&
637
+ (!this.isSearchable || this.isSearchable)
638
+ )
639
+ },
640
+ isMobileDevice() {
641
+ const userAgent = navigator.userAgent || navigator.vendor || window.opera
642
+ const touchCapable =
643
+ 'ontouchstart' in window ||
644
+ navigator.maxTouchPoints > 0 ||
645
+ navigator.msMaxTouchPoints > 0
737
646
 
738
- return isDropdownNotCompletelyVisible
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
+ )
653
+ }
739
654
  },
740
- async isBottomOfDropdownOutOfViewport() {
741
- if (
742
- !this.$refs.dropdown ||
743
- this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom
744
- ) {
745
- return false
655
+ watch: {
656
+ value(val) {
657
+ this.selectedValue = val
658
+ },
659
+ async isDropdownOpen(val) {
660
+ if (val) {
661
+ this.$emit('on-dropdown-open')
662
+ setTimeout(() => {
663
+ this.isClickOutsideActive = true
664
+ }, 10)
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
+ }
746
680
  }
681
+ },
682
+ mounted() {
683
+ this.observeDropdownHeight()
684
+ this.observeSelectWidth()
685
+ window.addEventListener('resize', this.handleSetDropdownOffet)
686
+ },
687
+ beforeMount() {
688
+ this.selectedValue = this.value
689
+ document.addEventListener('click', this.clickOutside)
690
+ this.getDropdownPosition()
691
+ window.removeEventListener('resize', this.handleSetDropdownOffet)
692
+ if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
693
+ if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
694
+ },
695
+ unmounted() {
696
+ document.removeEventListener('click', this.clickOutside)
697
+ },
698
+ methods: {
699
+ focus() {
700
+ this.isActive = true
701
+ },
702
+ blur(e) {
703
+ this.isActive = false
704
+ this.$emit('blur', e)
705
+ },
706
+ toggleDropdown() {
707
+ this.isDropdownOpen = !this.isDropdownOpen
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'
747
753
 
748
- await this.$nextTick()
749
- const rect = this.$refs.dropdown.$el.getBoundingClientRect()
750
- const windowHeight =
751
- window.innerHeight || document.documentElement.clientHeight
752
-
753
- if (windowHeight <= 650) return true
754
+ return
755
+ }
754
756
 
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
757
+ el.style.display = 'inherit'
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
793
772
  } else {
794
- newHoveredElem = currentHoveredElem.previousElementSibling
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)
795
786
  }
796
- if (newHoveredElem) {
797
- this.hoveredValue = newHoveredElem.getAttribute('data-value')
798
- const topPos = newHoveredElem.offsetTop
799
- this.$refs.dropdown.$el.scrollTop = topPos
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
800
797
  }
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
- }
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
811
815
 
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
- }
816
+ const top =
817
+ isDropdownNotCompletelyVisible ||
818
+ (!isDropdownNotCompletelyVisible &&
819
+ this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom)
820
+ ? dropdownWrapperRelativeHeight
821
+ : dropdownWrapperRelativeHeight -
822
+ dropdownHeight -
823
+ selectButtonHeight -
824
+ DROPDOWN_TOP_OFFSET
825
+ const left = this.dropdownPosition.left
826
+ ? this.dropdownPosition.left
827
+ : dropdownWrapperEl.getBoundingClientRect().left + window.scrollX
825
828
 
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
829
+ this.dropdownPosition = { left: Math.floor(left), top: Math.floor(top) }
832
830
 
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
831
+ return isDropdownNotCompletelyVisible
832
+ },
833
+ async isBottomOfDropdownOutOfViewport() {
834
+ if (
835
+ !this.$refs.dropdown ||
836
+ this.dropdownMenuPosition === DROPDOWN_MENU_POSITIONS.Bottom
837
+ ) {
838
+ return false
839
+ }
848
840
 
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)
867
841
  await this.$nextTick()
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()
879
- }
842
+ const rect = this.$refs.dropdown.$el.getBoundingClientRect()
843
+ const windowHeight =
844
+ window.innerHeight || document.documentElement.clientHeight
845
+
846
+ if (windowHeight <= 650) return true
847
+
848
+ // using Math.floor because the offsets may contain decimals we are not going to consider here
849
+ return Math.floor(rect.top) + Math.floor(rect.height) <= windowHeight
850
+ },
851
+ observeDropdownHeight() {
852
+ if (!this.$refs.dropdown) return
853
+ this.dropdownResizeObserver = new ResizeObserver(() => {
854
+ this.$nextTick(() => this.getDropdownPosition())
880
855
  })
856
+ this.dropdownResizeObserver.observe(this.$refs.dropdown.$el)
857
+ },
858
+ handleSetDropdownOffet() {
859
+ if (!this.$refs.select) return
860
+ this.dropdownPosition.left = Math.floor(
861
+ this.$refs.select.$el.getBoundingClientRect().left
862
+ )
863
+ this.getDropdownWidth()
864
+ },
865
+ observeSelectWidth() {
866
+ if (!this.$refs.select) return
867
+ this.selectResizeObserver = new ResizeObserver(() =>
868
+ // eslint-disable-next-line vue/valid-next-tick
869
+ this.$nextTick(() => this.getDropdownWidth())
870
+ )
871
+ this.selectResizeObserver.observe(this.$refs.dropdown.$el)
872
+ },
873
+ async getDropdownWidth() {
874
+ if (!this.$refs.select) return
875
+ await this.$nextTick()
876
+ this.dropdownWidth = `${this.$refs.select.$el.clientWidth}px`
877
+ },
878
+ onArrowPress(dir) {
879
+ let newHoveredElem
880
+ const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
881
+ `[data-value="${this.hoveredValue}"]`
882
+ )
883
+ if (currentHoveredElem) {
884
+ if (dir > 0) {
885
+ newHoveredElem = currentHoveredElem.nextElementSibling
886
+ } else {
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
893
+ }
894
+ }
881
895
  }
882
896
  }
883
897
  }
884
- }
885
898
  </script>