@eturnity/eturnity_reusable_components 8.16.2--EPDM-14330.5 → 8.16.2--EPDM-14330.7

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 (103) hide show
  1. package/package.json +1 -1
  2. package/src/assets/svgIcons/ac_power.svg +4 -0
  3. package/src/assets/svgIcons/arrow_long_left.svg +3 -0
  4. package/src/assets/svgIcons/arrow_long_right.svg +3 -0
  5. package/src/assets/svgIcons/chassis_ground_symbol.svg +27 -0
  6. package/src/assets/svgIcons/dc_power.svg +8 -0
  7. package/src/assets/svgIcons/double_arrow_long.svg +4 -0
  8. package/src/assets/svgIcons/ed_ac.svg +3 -0
  9. package/src/assets/svgIcons/ed_acgrid.svg +4 -0
  10. package/src/assets/svgIcons/ed_arrow_both.svg +7 -0
  11. package/src/assets/svgIcons/ed_arrow_left.svg +7 -0
  12. package/src/assets/svgIcons/ed_arrow_right.svg +7 -0
  13. package/src/assets/svgIcons/ed_battery.svg +10 -0
  14. package/src/assets/svgIcons/ed_batteryacinverter.svg +16 -0
  15. package/src/assets/svgIcons/ed_batteryintegratedinverter.svg +19 -0
  16. package/src/assets/svgIcons/ed_cirquitbreaker.svg +4 -0
  17. package/src/assets/svgIcons/ed_cirquitbreaker_magnetic.svg +6 -0
  18. package/src/assets/svgIcons/ed_cirquitbreaker_thermal.svg +4 -0
  19. package/src/assets/svgIcons/ed_cirquitbreaker_thermal_magnetic.svg +5 -0
  20. package/src/assets/svgIcons/ed_consumption.svg +3 -0
  21. package/src/assets/svgIcons/ed_dc.svg +6 -0
  22. package/src/assets/svgIcons/ed_disconnector.svg +4 -0
  23. package/src/assets/svgIcons/ed_disconnector_fuse.svg +4 -0
  24. package/src/assets/svgIcons/ed_disconnector_fuse_switch.svg +4 -0
  25. package/src/assets/svgIcons/ed_disconnector_loadbreak switch.svg +4 -0
  26. package/src/assets/svgIcons/ed_disconnector_switch.svg +4 -0
  27. package/src/assets/svgIcons/ed_disconnector_switch_auto_release.svg +5 -0
  28. package/src/assets/svgIcons/ed_energymanagement_rectangle.svg +3 -0
  29. package/src/assets/svgIcons/ed_evcharger.svg +19 -0
  30. package/src/assets/svgIcons/ed_flexiblecomponent_circle.svg +3 -0
  31. package/src/assets/svgIcons/ed_flexiblecomponent_square.svg +3 -0
  32. package/src/assets/svgIcons/ed_fuse.svg +3 -0
  33. package/src/assets/svgIcons/ed_ground.svg +5 -0
  34. package/src/assets/svgIcons/ed_heatpump.svg +4 -0
  35. package/src/assets/svgIcons/ed_icon_battery.svg +9 -0
  36. package/src/assets/svgIcons/ed_icon_circle.svg +3 -0
  37. package/src/assets/svgIcons/ed_icon_heatpump.svg +3 -0
  38. package/src/assets/svgIcons/ed_icon_inverter.svg +8 -0
  39. package/src/assets/svgIcons/ed_icon_optimizer.svg +11 -0
  40. package/src/assets/svgIcons/ed_integratedbatteryinverter.svg +10 -0
  41. package/src/assets/svgIcons/ed_inverter-blank.svg +3 -0
  42. package/src/assets/svgIcons/ed_mainsconnection.svg +3 -0
  43. package/src/assets/svgIcons/ed_meter_arrowleft.svg +4 -0
  44. package/src/assets/svgIcons/ed_meter_arrowright.svg +4 -0
  45. package/src/assets/svgIcons/ed_meter_bidirectional.svg +5 -0
  46. package/src/assets/svgIcons/ed_networkandsystemprotection_double.svg +14 -0
  47. package/src/assets/svgIcons/ed_networkandsystemprotection_single.svg +7 -0
  48. package/src/assets/svgIcons/ed_pvpanel.svg +7 -0
  49. package/src/assets/svgIcons/ed_rcd.svg +5 -0
  50. package/src/assets/svgIcons/ed_rcd_simple.svg +3 -0
  51. package/src/assets/svgIcons/ed_spd.svg +6 -0
  52. package/src/assets/svgIcons/ed_stringwithoptimizer.svg +33 -0
  53. package/src/assets/svgIcons/ed_stringwithoutoptimizer.svg +17 -0
  54. package/src/assets/svgIcons/ed_transformer.svg +3 -0
  55. package/src/assets/svgIcons/filter.svg +3 -0
  56. package/src/assets/svgIcons/ground_symbol.svg +28 -0
  57. package/src/assets/svgIcons/move_left.svg +3 -0
  58. package/src/assets/svgIcons/move_right.svg +3 -0
  59. package/src/assets/svgIcons/rectangle.svg +3 -0
  60. package/src/assets/svgIcons/refresh.svg +3 -0
  61. package/src/assets/svgIcons/text_icon.svg +3 -0
  62. package/src/assets/theme.js +17 -1
  63. package/src/components/banner/infoBanner/InfoBanner.spec.js +29 -42
  64. package/src/components/barchart/BottomFields.vue +253 -0
  65. package/src/components/barchart/ChartControls.vue +113 -0
  66. package/src/components/barchart/SelectionBox.vue +150 -0
  67. package/src/components/barchart/composables/index.js +5 -0
  68. package/src/components/barchart/composables/useAxisCalculations.js +104 -0
  69. package/src/components/barchart/composables/useChartData.js +114 -0
  70. package/src/components/barchart/composables/useChartScroll.js +61 -0
  71. package/src/components/barchart/composables/useSelection.js +75 -0
  72. package/src/components/barchart/composables/useTooltip.js +100 -0
  73. package/src/components/barchart/index.vue +385 -0
  74. package/src/components/barchart/styles/bottomFields.js +66 -0
  75. package/src/components/barchart/styles/chart.js +272 -0
  76. package/src/components/barchart/styles/chartControls.js +59 -0
  77. package/src/components/buttons/buttonIcon/index.vue +35 -1
  78. package/src/components/buttons/splitButtons/index.vue +86 -0
  79. package/src/components/collapsableInfoText/index.vue +2 -2
  80. package/src/components/errorMessage/errorMessage.spec.js +34 -0
  81. package/src/components/errorMessage/errorMessage.stories.js +35 -0
  82. package/src/components/filter/filterSettings.vue +2 -0
  83. package/src/components/filterComponent/viewFilter.vue +589 -0
  84. package/src/components/filterComponent/viewSettings.vue +63 -2
  85. package/src/components/filterComponent/viewSort.vue +18 -5
  86. package/src/components/icon/index.vue +32 -9
  87. package/src/components/infoText/index.vue +2 -2
  88. package/src/components/infoText/infoText.spec.js +6 -1
  89. package/src/components/inputs/inputNumber/index.vue +14 -2
  90. package/src/components/inputs/searchInput/index.vue +19 -3
  91. package/src/components/inputs/select/index.vue +108 -19
  92. package/src/components/inputs/select/option/index.vue +5 -0
  93. package/src/components/modals/actionModal/actionModal.spec.js +52 -0
  94. package/src/components/modals/actionModal/actionModal.stories.js +53 -0
  95. package/src/components/modals/actionModal/index.vue +6 -6
  96. package/src/components/modals/infoModal/index.vue +49 -19
  97. package/src/components/modals/infoModal/infoModal.spec.js +55 -0
  98. package/src/components/modals/infoModal/infoModal.stories.js +47 -0
  99. package/src/components/modals/modal/index.vue +16 -5
  100. package/src/components/pageSubtitle/PageSubtitle.stories.js +0 -1
  101. package/src/helpers/isObjectEqual.js +22 -0
  102. package/src/helpers/translateLang.js +95 -24
  103. package/src/main.js +1 -0
@@ -3,6 +3,7 @@
3
3
  <ButtonIcon
4
4
  class="button-icon"
5
5
  icon-name="sorting"
6
+ :number-count="getNumberCount()"
6
7
  :text="$gettext('sort')"
7
8
  type="filter"
8
9
  @click="toggleOptions"
@@ -22,6 +23,7 @@
22
23
  class="sort-dropdown"
23
24
  :dropdown-auto-close="false"
24
25
  select-height="40px"
26
+ @click.stop
25
27
  @input-change="
26
28
  onSelectSort({
27
29
  type: 'column',
@@ -52,6 +54,7 @@
52
54
  class="sort-dropdown"
53
55
  :dropdown-auto-close="false"
54
56
  select-height="40px"
57
+ @click.stop
55
58
  @input-change="
56
59
  onSelectSort({
57
60
  type: 'direction',
@@ -97,6 +100,7 @@
97
100
  class="sort-dropdown"
98
101
  :dropdown-auto-close="false"
99
102
  select-height="40px"
103
+ @click.stop
100
104
  @input-change="
101
105
  onSelectSort({
102
106
  type: 'column',
@@ -124,6 +128,7 @@
124
128
  class="sort-dropdown"
125
129
  :dropdown-auto-close="false"
126
130
  select-height="40px"
131
+ @click.stop
127
132
  @input-change="
128
133
  onSelectSort({
129
134
  type: 'direction',
@@ -267,17 +272,28 @@
267
272
  handleClickOutside(event) {
268
273
  const buttonIcon = this.$el.querySelector('.button-icon')
269
274
  const boxContainer = this.$el.querySelector('.box-container')
270
- const isClickInDropdown = event.target.closest('.sort-dropdown')
275
+ const isClickInSelect =
276
+ event.target.closest('.sort-dropdown') ||
277
+ event.target.closest('.rc-select-dropdown') ||
278
+ event.target.closest('.select-button') ||
279
+ event.target.closest('.caret_dropdown')
271
280
 
272
281
  if (
273
282
  !buttonIcon.contains(event.target) &&
274
283
  !boxContainer.contains(event.target) &&
275
- !isClickInDropdown
284
+ !isClickInSelect
276
285
  ) {
277
286
  this.isOptionsVisible = false
278
287
  document.removeEventListener('click', this.handleClickOutside)
279
288
  }
280
289
  },
290
+ getNumberCount() {
291
+ return this.selectedSort.filter((item) => {
292
+ const hasColumn = !!item.column
293
+ const hasDirection = !!item.direction
294
+ return hasColumn && hasDirection
295
+ }).length
296
+ },
281
297
  toggleOptions() {
282
298
  this.isOptionsVisible = !this.isOptionsVisible
283
299
  if (this.isOptionsVisible) {
@@ -287,7 +303,6 @@
287
303
  }
288
304
  },
289
305
  getSelectedLabel({ type, value }) {
290
- // debugger
291
306
  if (!value) return
292
307
  if (type === 'column') {
293
308
  return this.sortOptions.find((option) => option.value === value).label
@@ -297,8 +312,6 @@
297
312
  }
298
313
  },
299
314
  onSelectSort({ type, value, index }) {
300
- console.log(type, value, index)
301
-
302
315
  this.$emit('on-sort-change', {
303
316
  type,
304
317
  value,
@@ -3,13 +3,15 @@
3
3
  :cursor="cursor"
4
4
  data-test-id="icon_wrapper"
5
5
  :disabled="disabled"
6
- :size="size"
6
+ :height="height ? height : size"
7
+ :width="width ? width : size"
7
8
  >
8
9
  <IconImage
9
10
  :animation="animation"
10
11
  :background-color="backgroundColor"
11
12
  :color="color"
12
13
  data-test-id="icon_image"
14
+ :disable-hover="disableHover"
13
15
  :fill-type="fillType"
14
16
  :hovered-color="hoveredColor"
15
17
  >
@@ -67,6 +69,16 @@
67
69
  default: '30px',
68
70
  type: String,
69
71
  },
72
+ width: {
73
+ type: String,
74
+ required: false,
75
+ default: '',
76
+ },
77
+ height: {
78
+ type: String,
79
+ required: false,
80
+ default: '',
81
+ },
70
82
  cursor: {
71
83
  required: false,
72
84
  default: null,
@@ -97,10 +109,15 @@
97
109
  default: 'fill',
98
110
  type: String,
99
111
  },
112
+ disableHover: {
113
+ type: Boolean,
114
+ default: false,
115
+ },
100
116
  })
101
117
 
102
118
  const Wrapper = styled('div', {
103
- size: String,
119
+ height: String,
120
+ width: String,
104
121
  disabled: Boolean,
105
122
  cursor: String,
106
123
  })`
@@ -108,10 +125,10 @@
108
125
  position: relative;
109
126
  align-content: center;
110
127
  justify-content: center;
111
- width: ${(props) => props.size};
112
- height: ${(props) => props.size};
113
- min-width: ${(props) => props.size};
114
- min-height: ${(props) => props.size};
128
+ width: ${(props) => props.width};
129
+ height: ${(props) => props.height};
130
+ min-width: ${(props) => props.width};
131
+ min-height: ${(props) => props.height};
115
132
  cursor: ${(props) => (props.disabled ? 'not-allowed' : props.cursor)};
116
133
  line-height: 0;
117
134
  `
@@ -152,6 +169,7 @@
152
169
  hoveredColor: String,
153
170
  animation: String,
154
171
  fillType: String,
172
+ disableHover: Boolean,
155
173
  }
156
174
  const IconImage = styled('div', IconImageAttrs)`
157
175
  animation: ${(props) => props.animation};
@@ -168,12 +186,17 @@
168
186
  ${({ theme, color, fillType }) =>
169
187
  color && `${fillType}: ${theme.colors[color] || color};`}
170
188
  }
171
- &:hover svg path:not(.fix) {
172
- ${(props) => `${props.fillType}: ${props.hoveredColor || props.color};`}
189
+ ${(props) =>
190
+ !props.disableHover &&
191
+ `
192
+ &:hover svg path:not(.fix) {
193
+ ${`${props.fillType}: ${props.hoveredColor || props.color};`}
173
194
  }
174
195
  &:hover + div {
175
- background-color: ${(props) => props.hoveredColor};
196
+ background-color: ${props.hoveredColor};
176
197
  }
198
+ `}
199
+
177
200
  @keyframes fade {
178
201
  50% {
179
202
  opacity: 0.3;
@@ -46,7 +46,7 @@
46
46
  </IconWrapper>
47
47
  </div>
48
48
  <Teleport v-if="isVisible" to="body">
49
- <TextWrapper :style="wrapperStyle">
49
+ <TextWrapper data-test-id="info_text_wrapper" :style="wrapperStyle">
50
50
  <TextOverlay
51
51
  ref="infoBox"
52
52
  :app-theme="appTheme"
@@ -137,7 +137,7 @@
137
137
  `
138
138
 
139
139
  const TextWrapper = styled('div')`
140
- z-index: 99999;
140
+ z-index: 9999999999;
141
141
  position: absolute;
142
142
  `
143
143
 
@@ -29,6 +29,9 @@ describe('InfoText Component', () => {
29
29
  provide: {
30
30
  theme,
31
31
  },
32
+ stubs: {
33
+ teleport: true
34
+ }
32
35
  },
33
36
  })
34
37
  })
@@ -38,7 +41,6 @@ describe('InfoText Component', () => {
38
41
  expect(wrapper.vm.text).toContain('default text')
39
42
  expect(wrapper.vm.size).toContain('14px')
40
43
  expect(wrapper.vm.infoPosition).toContain('bottom')
41
- expect(wrapper.vm.alignArrow).toContain('center')
42
44
  })
43
45
 
44
46
  test('openTrigger prop is set to onClick', async () => {
@@ -48,8 +50,11 @@ describe('InfoText Component', () => {
48
50
  expect(wrapper.find('[data-test-id="info_text_wrapper"]').exists()).toBe(
49
51
  false
50
52
  )
53
+
51
54
  //should see text upon click
52
55
  await wrapper.find('[data-test-id="infoText_trigger"]').trigger('click')
56
+ expect(wrapper.vm.isVisible).toBe(true)
57
+
53
58
  expect(wrapper.find('[data-test-id="info_text_wrapper"]').exists()).toBe(
54
59
  true
55
60
  )
@@ -56,6 +56,7 @@
56
56
  :min-width="minWidth"
57
57
  :no-border="noBorder"
58
58
  :placeholder="displayedPlaceholder"
59
+ :read-only="isReadOnly"
59
60
  :show-arrow-controls="showArrowControls"
60
61
  :show-linear-unit-name="showLinearUnitName"
61
62
  :slot-size="slotSize"
@@ -163,6 +164,7 @@
163
164
  // labelInfoAlign="left"
164
165
  // :minNumber="0"
165
166
  // fontColor="blue"
167
+ // :isReadOnly="true"
166
168
  // colorMode="transparent" // Makes background transparent, border white, and font white
167
169
  // >
168
170
  //<template name=label><img>....</template>
@@ -202,6 +204,7 @@
202
204
  showLinearUnitName: Boolean,
203
205
  colorMode: String,
204
206
  showArrowControls: Boolean,
207
+ readOnly: Boolean,
205
208
  }
206
209
 
207
210
  const Container = styled('div', inputProps)`
@@ -250,7 +253,8 @@
250
253
  ? '0 4px 4px 0'
251
254
  : '4px'};
252
255
  text-align: ${(props) => props.textAlign};
253
- cursor: ${(props) => (props.isDisabled ? 'not-allowed' : 'auto')};
256
+ cursor: ${(props) =>
257
+ props.isDisabled || props.readOnly ? 'not-allowed' : 'auto'};
254
258
  font-size: ${(props) => (props.fontSize ? props.fontSize : '13px')};
255
259
  color: ${(props) =>
256
260
  props.isError
@@ -263,7 +267,9 @@
263
267
  ? props.fontColor + ' !important'
264
268
  : props.theme.colors.black};
265
269
  background-color: ${(props) =>
266
- props.isDisabled
270
+ props.readOnly
271
+ ? props.theme.semanticColors.grey[300]
272
+ : props.isDisabled
267
273
  ? props.colorMode === 'transparent'
268
274
  ? 'transparent'
269
275
  : props.theme.colors.grey5
@@ -276,6 +282,8 @@
276
282
  box-sizing: border-box;
277
283
  opacity: ${(props) =>
278
284
  props.isDisabled && props.colorMode === 'transparent' ? '0.4' : '1'};
285
+ pointer-events: ${(props) => (props.readOnly ? 'none' : 'auto')};
286
+ user-select: ${(props) => (props.readOnly ? 'none' : 'auto')};
279
287
 
280
288
  &::placeholder {
281
289
  color: ${(props) => props.theme.colors.grey2};
@@ -686,6 +694,10 @@
686
694
  type: Boolean,
687
695
  default: false,
688
696
  },
697
+ isReadOnly: {
698
+ type: Boolean,
699
+ default: false,
700
+ },
689
701
  },
690
702
  data() {
691
703
  return {
@@ -1,6 +1,10 @@
1
1
  <template>
2
2
  <Container :input-width="inputWidth">
3
- <InputWrapper :icon-color="iconColor" :icon-position="iconPosition">
3
+ <InputWrapper
4
+ :icon-color="iconColor"
5
+ :icon-position="iconPosition"
6
+ :is-full-height="isFullHeight"
7
+ >
4
8
  <SearchIconSvg class="search-icn" />
5
9
  <InputContainer
6
10
  ref="inputElement"
@@ -11,6 +15,7 @@
11
15
  :input-width="inputWidth"
12
16
  :is-disabled="disabled"
13
17
  :is-filter="isFilter"
18
+ :is-full-height="isFullHeight"
14
19
  :placeholder="placeholder"
15
20
  :value="value"
16
21
  @input="onChangeHandler($event)"
@@ -41,6 +46,7 @@
41
46
  isDisabled: Boolean,
42
47
  inputWidth: String,
43
48
  isFilter: Boolean,
49
+ isFullHeight: Boolean,
44
50
  }
45
51
  const Container = styled('div', inputAttrs)`
46
52
  width: ${(props) => (props.inputWidth ? props.inputWidth : '100%')};
@@ -50,11 +56,12 @@
50
56
  const InputContainer = styled('input', inputAttrs)`
51
57
  border: 1px solid ${(props) => props.theme.colors.grey4};
52
58
  padding: ${(props) =>
53
- props.isFilter ? '7px 30px 7px 10px' : '11px 30px 11px 10px'};
59
+ props.isFilter ? '8px 30px 8px 10px' : '11px 30px 11px 10px'};
54
60
  border-radius: 4px;
55
61
  font-size: 13px;
56
62
  color: ${(props) => props.theme.colors.black};
57
63
  width: ${(props) => (props.inputWidth ? props.inputWidth : '100%')};
64
+ height: ${(props) => (props.isFullHeight ? '100%' : 'auto')};
58
65
  box-sizing: border-box;
59
66
  cursor: ${(props) => (props.isDisabled ? 'not-allowed' : 'auto')};
60
67
  background: ${(props) => props.theme.colors.white} !important;
@@ -67,9 +74,14 @@
67
74
  }
68
75
  `
69
76
 
70
- const wrapperAttrs = { iconColor: String, iconPosition: String }
77
+ const wrapperAttrs = {
78
+ iconColor: String,
79
+ iconPosition: String,
80
+ isFullHeight: Boolean,
81
+ }
71
82
  const InputWrapper = styled('div', wrapperAttrs)`
72
83
  position: relative;
84
+ height: ${(props) => (props.isFullHeight ? '100%' : 'auto')};
73
85
 
74
86
  svg {
75
87
  position: absolute;
@@ -142,6 +154,10 @@
142
154
  type: String,
143
155
  default: 'black',
144
156
  },
157
+ isFullHeight: {
158
+ type: Boolean,
159
+ default: false,
160
+ },
145
161
  },
146
162
  emits: ['on-change'],
147
163
  watch: {
@@ -109,11 +109,7 @@
109
109
  >
110
110
  <slot name="selector" :selected-value="selectedValue"></slot>
111
111
  </Selector>
112
- <Caret
113
- class="caret_dropdown"
114
- :color-mode="colorMode"
115
- @click.stop="toggleCaretDropdown"
116
- >
112
+ <Caret class="caret_dropdown" :color-mode="colorMode">
117
113
  <Icon
118
114
  v-if="isDropdownOpen"
119
115
  :color="
@@ -137,17 +133,19 @@
137
133
  </Caret>
138
134
  </SelectButton>
139
135
  <DropdownWrapper ref="dropdownWrapperRef" :no-relative="noRelative">
140
- <Teleport to="body">
136
+ <Component
137
+ :is="shouldUseTeleport ? 'Teleport' : 'div'"
138
+ :to="shouldUseTeleport ? 'body' : undefined"
139
+ >
141
140
  <SelectDropdown
142
141
  v-show="isSelectDropdownShown"
143
142
  ref="dropdown"
144
143
  :bg-color="
145
- dropdownBgColor ||
146
- colorMode == 'dark' ||
147
- colorMode == 'transparent'
144
+ colorMode == 'dark' || colorMode == 'transparent'
148
145
  ? 'black'
149
146
  : 'white'
150
147
  "
148
+ class="rc-select-dropdown"
151
149
  :dropdown-position="dropdownPosition"
152
150
  :font-color="
153
151
  dropdownFontColor ||
@@ -167,10 +165,22 @@
167
165
  :hovered-index="hoveredIndex"
168
166
  :hovered-value="hoveredValue"
169
167
  :is-active="isActive"
168
+ :is-fixed-dropdown-position="isFixedDropdownPosition"
169
+ :is-parent-modal="isParentModal"
170
+ :is-teleport="shouldUseTeleport"
170
171
  :min-width="minWidth"
171
172
  :no-relative="noRelative"
172
173
  :option-width="getOptionWidth"
173
174
  :selected-value="selectedValue"
175
+ :style="
176
+ shouldUseTeleport
177
+ ? {
178
+ transform: `translate(${dropdownPosition?.left}px, ${
179
+ noRelative ? 'auto' : `${dropdownPosition?.top}px`
180
+ })`,
181
+ }
182
+ : undefined
183
+ "
174
184
  @click.stop
175
185
  @mouseleave="optionLeave"
176
186
  @option-hovered="optionHovered"
@@ -178,7 +188,7 @@
178
188
  >
179
189
  <slot name="dropdown"></slot>
180
190
  </SelectDropdown>
181
- </Teleport>
191
+ </Component>
182
192
  </DropdownWrapper>
183
193
  </SelectButtonWrapper>
184
194
  </InputWrapper>
@@ -209,7 +219,7 @@
209
219
  // </template>
210
220
  // </Select>
211
221
 
212
- import { Teleport } from 'vue'
222
+ import { Teleport, inject } from 'vue'
213
223
  import styled from 'vue3-styled-components'
214
224
  import InfoText from '../../infoText'
215
225
  import Icon from '../../icon'
@@ -393,14 +403,18 @@
393
403
  selectedValue: Number | String,
394
404
  noRelative: Boolean,
395
405
  minWidth: String,
406
+ isParentModal: Boolean,
407
+ isFixedDropdownPosition: Boolean,
408
+ isTeleport: Boolean,
396
409
  }
397
410
  const SelectDropdown = styled('div', selectDropdownAttrs)`
398
411
  box-sizing: border-box;
399
- z-index: ${(props) => (props.isActive ? '2' : '99999')};
400
- position: absolute;
401
- top: ${(props) =>
402
- props.noRelative ? 'auto' : props.dropdownPosition?.top + 'px'};
403
- left: ${(props) => props.dropdownPosition?.left}px;
412
+ z-index: ${(props) =>
413
+ props.isActive ? '2' : props.isParentModal ? '9999999' : '99999'};
414
+ position: ${(props) =>
415
+ props.isFixedDropdownPosition ? 'fixed' : 'absolute'};
416
+ top: ${(props) => (props.isTeleport ? '0px' : '4px')};
417
+ left: 0px;
404
418
  border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
405
419
  border-radius: 4px;
406
420
  display: flex;
@@ -648,6 +662,23 @@
648
662
  type: String,
649
663
  required: false,
650
664
  },
665
+ isFixedDropdownPosition: {
666
+ type: Boolean,
667
+ required: false,
668
+ default: false,
669
+ },
670
+ shouldUseTeleport: {
671
+ type: Boolean,
672
+ required: false,
673
+ default: true,
674
+ },
675
+ },
676
+ setup() {
677
+ const modalRef = inject('modalRef')
678
+
679
+ return {
680
+ modalRef,
681
+ }
651
682
  },
652
683
 
653
684
  data() {
@@ -665,6 +696,10 @@
665
696
  },
666
697
  dropdownWidth: null,
667
698
  hoveredValue: null,
699
+ isDisplayedAtBottom: true,
700
+ selectTopPosition: 0,
701
+ selectAndDropdownDistance: 0,
702
+ animationFrameId: null,
668
703
  }
669
704
  },
670
705
  computed: {
@@ -722,6 +757,9 @@
722
757
  /windows phone/i.test(userAgent)
723
758
  )
724
759
  },
760
+ isParentModal() {
761
+ return !!this.modalRef
762
+ },
725
763
  },
726
764
  watch: {
727
765
  value(val) {
@@ -735,8 +773,13 @@
735
773
  }, 10)
736
774
  await this.$nextTick()
737
775
  this.handleSetDropdownOffet()
776
+ if (!this.isFixedDropdownPosition) this.calculateSelectTopPosition()
738
777
  } else {
739
778
  this.dropdownPosition.left = null
779
+ if (this.animationFrameId) {
780
+ cancelAnimationFrame(this.animationFrameId)
781
+ this.animationFrameId = null
782
+ }
740
783
  setTimeout(() => {
741
784
  this.isClickOutsideActive = false
742
785
  }, 10)
@@ -749,11 +792,30 @@
749
792
  })
750
793
  }
751
794
  },
795
+ isSelectDropdownShown(isShown) {
796
+ if (!isShown) return
797
+ // Need to wait for 1ms to make sure the dropdown menu is shown in the DOM
798
+ // before getting the distance between the select and the dropdown menu
799
+ setTimeout(() => {
800
+ this.getDistanceBetweenSelectAndDropdownMenu()
801
+ }, 100)
802
+ },
803
+ selectTopPosition() {
804
+ this.dropdownPosition.top =
805
+ this.selectTopPosition +
806
+ this.$refs.select.$el.clientHeight +
807
+ this.selectAndDropdownDistance
808
+ },
752
809
  },
753
810
  mounted() {
754
811
  this.observeDropdownHeight()
755
812
  this.observeSelectWidth()
756
813
  window.addEventListener('resize', this.handleSetDropdownOffet)
814
+ if (!this.isFixedDropdownPosition)
815
+ document.body.addEventListener(
816
+ 'scroll',
817
+ this.calculateSelectTopPosition
818
+ )
757
819
  },
758
820
  beforeMount() {
759
821
  this.selectedValue = this.value
@@ -762,6 +824,12 @@
762
824
  window.removeEventListener('resize', this.handleSetDropdownOffet)
763
825
  if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
764
826
  if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
827
+ if (!this.isFixedDropdownPosition) {
828
+ document.body.removeEventListener(
829
+ 'scroll',
830
+ this.calculateSelectTopPosition
831
+ )
832
+ }
765
833
  },
766
834
  unmounted() {
767
835
  document.removeEventListener('click', this.clickOutside)
@@ -837,7 +905,9 @@
837
905
  this.$refs.select.$el == event.target ||
838
906
  this.$refs.select.$el.contains(event.target) ||
839
907
  event.target.id === 'more-button' ||
840
- event.target.parentNode === dropdownRef.$el
908
+ event.target.closest('.options-container') ||
909
+ event.target.parentNode === dropdownRef.$el ||
910
+ dropdownRef.$el.contains(event.target)
841
911
  ) {
842
912
  return
843
913
  } else {
@@ -867,11 +937,11 @@
867
937
  return
868
938
  }
869
939
  await this.$nextTick()
870
- const isDisplayedAtBottom = await this.generateDropdownPosition()
940
+ this.isDisplayedAtBottom = await this.generateDropdownPosition()
871
941
  // If the dropdown menu is going to be displayed at the bottom,
872
942
  // we need reverify its position after a dom update (nextTick)
873
943
  await this.$nextTick()
874
- if (isDisplayedAtBottom) this.generateDropdownPosition()
944
+ if (this.isDisplayedAtBottom) this.generateDropdownPosition()
875
945
  },
876
946
  async generateDropdownPosition() {
877
947
  const isDropdownNotCompletelyVisible =
@@ -964,6 +1034,25 @@
964
1034
  }
965
1035
  }
966
1036
  },
1037
+ getDistanceBetweenSelectAndDropdownMenu() {
1038
+ const wholeSelectTopPosition =
1039
+ this.selectTopPosition + this.$refs.select.$el.clientHeight
1040
+ this.selectAndDropdownDistance =
1041
+ this.dropdownPosition.top - wholeSelectTopPosition
1042
+ },
1043
+ calculateSelectTopPosition() {
1044
+ const selectRef = this.$refs.select
1045
+ if (selectRef) {
1046
+ const currentTopPosition =
1047
+ selectRef.$el.getBoundingClientRect().top + window.scrollY
1048
+ if (this.selectTopPosition !== currentTopPosition) {
1049
+ this.selectTopPosition = currentTopPosition
1050
+ }
1051
+ }
1052
+ this.animationFrameId = requestAnimationFrame(
1053
+ this.calculateSelectTopPosition
1054
+ )
1055
+ },
967
1056
  },
968
1057
  }
969
1058
  </script>
@@ -142,6 +142,11 @@
142
142
  required: false,
143
143
  default: 'inherit',
144
144
  },
145
+ showFullName: {
146
+ type: Boolean,
147
+ required: false,
148
+ default: false,
149
+ },
145
150
  },
146
151
  emits: ['option-hovered', 'option-selected'],
147
152
  data() {
@@ -0,0 +1,52 @@
1
+ /* eslint-disable */
2
+ import { mount } from '@vue/test-utils'
3
+ import ActionModal from '@/components/modals/actionModal'
4
+ import theme from '@/assets/theme'
5
+
6
+ describe('ActionModal Component', () => {
7
+ let wrapper
8
+
9
+ beforeEach(() => {
10
+ wrapper = mount(ActionModal, {
11
+ props: {
12
+ isOpen: true,
13
+ buttonText: 'Close',
14
+ },
15
+ slots: {
16
+ title: 'Sample title',
17
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tincidunt commodo mollis. Fusce urna felis, malesuada sed elementum et, fermentum ac massa. Integer in massa vel orci fermentum bibendum in ut ante. Donec risus risus, luctus quis ex a, pulvinar placerat lacus. Sed pharetra augue a elit volutpat, eu dignissim ex pretium. Aenean imperdiet, nulla in pharetra rutrum, mauris mauris tincidunt tellus, non tempus quam lorem laoreet lectus.',
18
+ buttons: '<button @click="closeAction">Close</button>',
19
+ },
20
+ global: {
21
+ provide: {
22
+ theme,
23
+ },
24
+ },
25
+ })
26
+ })
27
+
28
+ test('renders ActionModal component with default props', () => {
29
+ expect(wrapper.find('[data-test-id="actionModal"]').exists()).toBe(true)
30
+
31
+ expect(wrapper.vm.isOpen).toBe(true)
32
+ })
33
+
34
+ test('action modal slots is display when user passed slots content', () => {
35
+ const modalTitleEl = wrapper.find('[data-test-id="modal_title"]')
36
+ expect(modalTitleEl.text()).toBe('Sample title')
37
+
38
+ const modalBodyEl = wrapper.find('[data-test-id="modal_body"]')
39
+ expect(modalBodyEl.text()).toContain('Lorem ipsum dolor sit amet')
40
+
41
+ const modalActionButton = wrapper.find('[data-test-id="modal_buttons"]')
42
+ expect(modalActionButton.text()).toContain('Close')
43
+ })
44
+
45
+ test('action modal on-close event is emitted when modal close button is clicked', async () => {
46
+ const modalCloseButton = wrapper.find('.close')
47
+
48
+ modalCloseButton.trigger('click')
49
+ await wrapper.vm.$nextTick()
50
+ expect(wrapper.emitted('on-close')).toBeTruthy()
51
+ })
52
+ })