@eturnity/eturnity_reusable_components 7.12.6-EPDM-7951.3 → 7.12.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 (284) hide show
  1. package/.prettierrc +6 -6
  2. package/.storybook/main.js +8 -8
  3. package/.storybook/preview.js +46 -46
  4. package/README.md +29 -29
  5. package/babel.config.js +4 -4
  6. package/package.json +66 -61
  7. package/postcss.config.js +6 -6
  8. package/public/index.html +17 -17
  9. package/src/App.vue +109 -109
  10. package/src/assets/icons/arrow_down.svg +3 -3
  11. package/src/assets/icons/arrow_up_red.svg +3 -3
  12. package/src/assets/icons/black_spinner.svg +35 -35
  13. package/src/assets/icons/delete_icon.svg +11 -11
  14. package/src/assets/icons/delete_icon_gray.svg +11 -11
  15. package/src/assets/icons/drag_icon.svg +8 -8
  16. package/src/assets/icons/external_icon.svg +6 -6
  17. package/src/assets/icons/language_icon.svg +6 -6
  18. package/src/assets/icons/pdf_icon.svg +6 -6
  19. package/src/assets/icons/plus_button.svg +4 -4
  20. package/src/assets/icons/search_icon_black.svg +3 -3
  21. package/src/assets/icons/subposition_icon.svg +3 -3
  22. package/src/assets/icons/subposition_marker.svg +3 -3
  23. package/src/assets/icons/warning_icon.svg +3 -3
  24. package/src/assets/svgIcons/2d_active.svg +7 -7
  25. package/src/assets/svgIcons/2d_inactive.svg +8 -8
  26. package/src/assets/svgIcons/3d_active.svg +7 -7
  27. package/src/assets/svgIcons/3d_inactive.svg +8 -8
  28. package/src/assets/svgIcons/_readme.md +7 -7
  29. package/src/assets/svgIcons/accept.svg +5 -5
  30. package/src/assets/svgIcons/activate_panels_active.svg +22 -22
  31. package/src/assets/svgIcons/activate_panels_inactive.svg +20 -20
  32. package/src/assets/svgIcons/add_icon-1.svg +3 -3
  33. package/src/assets/svgIcons/add_icon.svg +4 -4
  34. package/src/assets/svgIcons/address_book.svg +3 -3
  35. package/src/assets/svgIcons/after_sale_as_a_service.svg +6 -6
  36. package/src/assets/svgIcons/all_good.svg +3 -3
  37. package/src/assets/svgIcons/angle_active.svg +5 -5
  38. package/src/assets/svgIcons/angle_inactive.svg +4 -4
  39. package/src/assets/svgIcons/area_active.svg +11 -11
  40. package/src/assets/svgIcons/area_inactive.svg +26 -26
  41. package/src/assets/svgIcons/areas_tool.svg +14 -14
  42. package/src/assets/svgIcons/arrow_down.svg +3 -3
  43. package/src/assets/svgIcons/arrow_left.svg +4 -4
  44. package/src/assets/svgIcons/arrow_right.svg +4 -4
  45. package/src/assets/svgIcons/arrow_up.svg +3 -3
  46. package/src/assets/svgIcons/attachment.svg +3 -3
  47. package/src/assets/svgIcons/base_layer.svg +3 -3
  48. package/src/assets/svgIcons/battery.svg +3 -3
  49. package/src/assets/svgIcons/bell.svg +3 -3
  50. package/src/assets/svgIcons/bold.svg +3 -3
  51. package/src/assets/svgIcons/bom.svg +3 -3
  52. package/src/assets/svgIcons/bom_generation.svg +10 -10
  53. package/src/assets/svgIcons/bookmaker.svg +3 -3
  54. package/src/assets/svgIcons/bubble.svg +3 -3
  55. package/src/assets/svgIcons/bug.svg +5 -5
  56. package/src/assets/svgIcons/bullet_list.svg +8 -8
  57. package/src/assets/svgIcons/calendar.svg +7 -7
  58. package/src/assets/svgIcons/calendar_icon.svg +7 -7
  59. package/src/assets/svgIcons/call.svg +3 -3
  60. package/src/assets/svgIcons/camera.svg +3 -3
  61. package/src/assets/svgIcons/car.svg +3 -3
  62. package/src/assets/svgIcons/cart.svg +3 -3
  63. package/src/assets/svgIcons/checkbox.svg +3 -3
  64. package/src/assets/svgIcons/clear_formatting.svg +7 -7
  65. package/src/assets/svgIcons/clickable_info.svg +4 -4
  66. package/src/assets/svgIcons/clip.svg +3 -3
  67. package/src/assets/svgIcons/clock.svg +17 -17
  68. package/src/assets/svgIcons/close_for_modals,_tool_tips.svg +4 -4
  69. package/src/assets/svgIcons/co_branding.svg +5 -5
  70. package/src/assets/svgIcons/collapse.svg +4 -4
  71. package/src/assets/svgIcons/collections.svg +3 -3
  72. package/src/assets/svgIcons/component_library.svg +7 -7
  73. package/src/assets/svgIcons/context_menu-1.svg +6 -6
  74. package/src/assets/svgIcons/context_menu-2.svg +5 -5
  75. package/src/assets/svgIcons/context_menu.svg +5 -5
  76. package/src/assets/svgIcons/context_menu_tabs.svg +5 -5
  77. package/src/assets/svgIcons/cross.svg +4 -4
  78. package/src/assets/svgIcons/current_variant.svg +4 -4
  79. package/src/assets/svgIcons/dashboard.svg +3 -3
  80. package/src/assets/svgIcons/deadline.svg +4 -4
  81. package/src/assets/svgIcons/deal_flow.svg +5 -5
  82. package/src/assets/svgIcons/delete.svg +4 -4
  83. package/src/assets/svgIcons/delete_area_active.svg +16 -16
  84. package/src/assets/svgIcons/delete_area_inactive.svg +15 -15
  85. package/src/assets/svgIcons/direction_active-1.svg +12 -12
  86. package/src/assets/svgIcons/direction_active.svg +5 -5
  87. package/src/assets/svgIcons/direction_arrow.svg +4 -4
  88. package/src/assets/svgIcons/direction_inactive.svg +4 -4
  89. package/src/assets/svgIcons/dislike.svg +3 -3
  90. package/src/assets/svgIcons/distance_tool.svg +8 -8
  91. package/src/assets/svgIcons/distances_active.svg +9 -9
  92. package/src/assets/svgIcons/distances_inactive.svg +8 -8
  93. package/src/assets/svgIcons/distort_tool.svg +10 -10
  94. package/src/assets/svgIcons/distort_tool2.svg +16 -16
  95. package/src/assets/svgIcons/document.svg +3 -3
  96. package/src/assets/svgIcons/documents.svg +4 -4
  97. package/src/assets/svgIcons/downarrow.svg +3 -3
  98. package/src/assets/svgIcons/download.svg +4 -4
  99. package/src/assets/svgIcons/draggable_corner.svg +5 -5
  100. package/src/assets/svgIcons/draw_tool.svg +3 -3
  101. package/src/assets/svgIcons/duplicate-1.svg +8 -8
  102. package/src/assets/svgIcons/duplicate-2.svg +5 -5
  103. package/src/assets/svgIcons/duplicate.svg +4 -4
  104. package/src/assets/svgIcons/e-mobility_configurator.svg +6 -6
  105. package/src/assets/svgIcons/e_signature.svg +5 -5
  106. package/src/assets/svgIcons/edit_button.svg +3 -3
  107. package/src/assets/svgIcons/email.svg +3 -3
  108. package/src/assets/svgIcons/ems-1.svg +3 -3
  109. package/src/assets/svgIcons/ems.svg +3 -3
  110. package/src/assets/svgIcons/end_of_the_list.svg +5 -5
  111. package/src/assets/svgIcons/erase.svg +4 -4
  112. package/src/assets/svgIcons/external_icon.svg +5 -5
  113. package/src/assets/svgIcons/fav_icon.svg +4 -4
  114. package/src/assets/svgIcons/finance.svg +3 -3
  115. package/src/assets/svgIcons/financing_for_pv-1.svg +5 -5
  116. package/src/assets/svgIcons/financing_for_pv-2.svg +3 -3
  117. package/src/assets/svgIcons/financing_for_pv.svg +6 -6
  118. package/src/assets/svgIcons/finish-1.svg +4 -4
  119. package/src/assets/svgIcons/finish.svg +3 -3
  120. package/src/assets/svgIcons/flatten.svg +11 -11
  121. package/src/assets/svgIcons/folder.svg +3 -3
  122. package/src/assets/svgIcons/free_technology.svg +5 -5
  123. package/src/assets/svgIcons/heat_calc.svg +7 -7
  124. package/src/assets/svgIcons/house.svg +3 -3
  125. package/src/assets/svgIcons/info.svg +3 -3
  126. package/src/assets/svgIcons/initial_situation.svg +3 -3
  127. package/src/assets/svgIcons/integrations.svg +3 -3
  128. package/src/assets/svgIcons/intro-tour-1.svg +3 -3
  129. package/src/assets/svgIcons/intro-tour.svg +3 -3
  130. package/src/assets/svgIcons/inverter-1.svg +5 -5
  131. package/src/assets/svgIcons/inverter.svg +3 -3
  132. package/src/assets/svgIcons/italic.svg +3 -3
  133. package/src/assets/svgIcons/key.svg +3 -3
  134. package/src/assets/svgIcons/layers_close.svg +4 -4
  135. package/src/assets/svgIcons/layers_open.svg +4 -4
  136. package/src/assets/svgIcons/lead_marketplace.svg +6 -6
  137. package/src/assets/svgIcons/lead_provider.svg +4 -4
  138. package/src/assets/svgIcons/length_in_2d_active.svg +12 -12
  139. package/src/assets/svgIcons/length_in_2d_inctive.svg +13 -13
  140. package/src/assets/svgIcons/light_bulb.svg +3 -3
  141. package/src/assets/svgIcons/like.svg +3 -3
  142. package/src/assets/svgIcons/line_graph.svg +3 -3
  143. package/src/assets/svgIcons/local_subsidies.svg +18 -18
  144. package/src/assets/svgIcons/location.svg +3 -3
  145. package/src/assets/svgIcons/lock.svg +3 -3
  146. package/src/assets/svgIcons/logout.svg +3 -3
  147. package/src/assets/svgIcons/loop.svg +3 -3
  148. package/src/assets/svgIcons/lunch.svg +4 -4
  149. package/src/assets/svgIcons/magic_tool.svg +6 -6
  150. package/src/assets/svgIcons/map_icon.svg +5 -5
  151. package/src/assets/svgIcons/map_settings.svg +3 -3
  152. package/src/assets/svgIcons/margin_tool.svg +4 -4
  153. package/src/assets/svgIcons/meeting.svg +6 -6
  154. package/src/assets/svgIcons/move_copy.svg +4 -4
  155. package/src/assets/svgIcons/new_area_inactive.svg +11 -11
  156. package/src/assets/svgIcons/next.svg +4 -4
  157. package/src/assets/svgIcons/not_equal_to.svg +3 -3
  158. package/src/assets/svgIcons/numbered_list.svg +6 -6
  159. package/src/assets/svgIcons/obstacle_tool.svg +9 -9
  160. package/src/assets/svgIcons/obstacle_tool_origin.svg +3 -3
  161. package/src/assets/svgIcons/offset_tool.svg +8 -8
  162. package/src/assets/svgIcons/outline_tool.svg +11 -11
  163. package/src/assets/svgIcons/pan_tool.svg +12 -12
  164. package/src/assets/svgIcons/panels_tool.svg +8 -8
  165. package/src/assets/svgIcons/pen_tool.svg +4 -4
  166. package/src/assets/svgIcons/picker_tool.svg +4 -4
  167. package/src/assets/svgIcons/picture.svg +3 -3
  168. package/src/assets/svgIcons/pin.svg +5 -5
  169. package/src/assets/svgIcons/presentation.svg +3 -3
  170. package/src/assets/svgIcons/previous.svg +4 -4
  171. package/src/assets/svgIcons/profile-1.svg +4 -4
  172. package/src/assets/svgIcons/profile.svg +4 -4
  173. package/src/assets/svgIcons/profitability.svg +3 -3
  174. package/src/assets/svgIcons/project_analysis.svg +4 -4
  175. package/src/assets/svgIcons/project_settings.svg +4 -4
  176. package/src/assets/svgIcons/pv.svg +3 -3
  177. package/src/assets/svgIcons/quotations.svg +6 -6
  178. package/src/assets/svgIcons/redo.svg +6 -6
  179. package/src/assets/svgIcons/resizer.svg +5 -5
  180. package/src/assets/svgIcons/roof_layer.svg +3 -3
  181. package/src/assets/svgIcons/rotate_tool.svg +3 -3
  182. package/src/assets/svgIcons/rotate_view.svg +5 -5
  183. package/src/assets/svgIcons/ruler_tool.svg +3 -3
  184. package/src/assets/svgIcons/run_simulation.svg +3 -3
  185. package/src/assets/svgIcons/scaling_tool.svg +8 -8
  186. package/src/assets/svgIcons/search.svg +3 -3
  187. package/src/assets/svgIcons/security.svg +3 -3
  188. package/src/assets/svgIcons/settings.svg +3 -3
  189. package/src/assets/svgIcons/show_in_a_new_tab.svg +12 -12
  190. package/src/assets/svgIcons/smartphone.svg +4 -4
  191. package/src/assets/svgIcons/solar_calc.svg +13 -13
  192. package/src/assets/svgIcons/sorting.svg +4 -4
  193. package/src/assets/svgIcons/split.svg +94 -94
  194. package/src/assets/svgIcons/start_of_the_list.svg +5 -5
  195. package/src/assets/svgIcons/strikethrough.svg +4 -4
  196. package/src/assets/svgIcons/subscriptions.svg +3 -3
  197. package/src/assets/svgIcons/subsidies-1.svg +5 -5
  198. package/src/assets/svgIcons/subsidies-2.svg +3 -3
  199. package/src/assets/svgIcons/subsidies.svg +3 -3
  200. package/src/assets/svgIcons/subtract_icon.svg +3 -3
  201. package/src/assets/svgIcons/suitcase.svg +3 -3
  202. package/src/assets/svgIcons/template_icon_not_clickable.svg +6 -6
  203. package/src/assets/svgIcons/transfer.svg +4 -4
  204. package/src/assets/svgIcons/trim_tool.svg +4 -4
  205. package/src/assets/svgIcons/truck.svg +3 -3
  206. package/src/assets/svgIcons/underlined.svg +3 -3
  207. package/src/assets/svgIcons/undo.svg +6 -6
  208. package/src/assets/svgIcons/uparrow.svg +3 -3
  209. package/src/assets/svgIcons/update.svg +3 -3
  210. package/src/assets/svgIcons/upload_avatar-1.svg +12 -12
  211. package/src/assets/svgIcons/upload_avatar.svg +5 -5
  212. package/src/assets/svgIcons/upload_image.svg +8 -8
  213. package/src/assets/svgIcons/upload_image_tool.svg +7 -7
  214. package/src/assets/svgIcons/variants.svg +6 -6
  215. package/src/assets/svgIcons/vertical_tool.svg +3 -3
  216. package/src/assets/svgIcons/virtual_storage.svg +4 -4
  217. package/src/assets/svgIcons/warning.svg +4 -4
  218. package/src/assets/svgIcons/way.svg +5 -5
  219. package/src/assets/svgIcons/wifi.svg +3 -3
  220. package/src/assets/svgIcons/winter.svg +3 -3
  221. package/src/assets/svgIcons/workflow_template.svg +11 -11
  222. package/src/assets/theme.js +41 -41
  223. package/src/components/addNewButton/AddNewButton.stories.js +24 -24
  224. package/src/components/addNewButton/index.vue +62 -64
  225. package/src/components/buttons/buttonIcon/index.vue +142 -142
  226. package/src/components/buttons/closeButton/CloseButton.stories.js +29 -29
  227. package/src/components/buttons/closeButton/index.vue +61 -61
  228. package/src/components/buttons/mainButton/index.vue +107 -112
  229. package/src/components/deleteIcon/DeleteIcon.stories.js +29 -29
  230. package/src/components/deleteIcon/index.vue +61 -65
  231. package/src/components/draggableInputHandle/index.vue +47 -46
  232. package/src/components/dropdown/Dropdown.stories.js +54 -54
  233. package/src/components/dropdown/index.vue +119 -138
  234. package/src/components/errorMessage/index.vue +59 -59
  235. package/src/components/filter/filterSettings.vue +650 -608
  236. package/src/components/filter/index.vue +143 -143
  237. package/src/components/filter/parentDropdown.vue +91 -91
  238. package/src/components/icon/Icons.stories.js +41 -41
  239. package/src/components/icon/iconCollection.vue +68 -68
  240. package/src/components/icon/index.vue +116 -122
  241. package/src/components/iconWrapper/index.vue +156 -153
  242. package/src/components/infoCard/index.vue +36 -35
  243. package/src/components/infoText/index.vue +160 -160
  244. package/src/components/inputs/checkbox/Checkbox.stories.js +57 -57
  245. package/src/components/inputs/checkbox/index.vue +187 -202
  246. package/src/components/inputs/inputNumber/InputNumber.stories.js +150 -150
  247. package/src/components/inputs/inputNumber/index.vue +717 -714
  248. package/src/components/inputs/inputNumberQuestion/index.vue +215 -215
  249. package/src/components/inputs/inputText/InputText.stories.js +75 -75
  250. package/src/components/inputs/inputText/index.vue +359 -359
  251. package/src/components/inputs/radioButton/RadioButton.stories.js +58 -58
  252. package/src/components/inputs/radioButton/index.vue +267 -267
  253. package/src/components/inputs/searchInput/SearchInput.stories.js +40 -40
  254. package/src/components/inputs/searchInput/index.vue +133 -132
  255. package/src/components/inputs/select/index.vue +627 -757
  256. package/src/components/inputs/select/option/index.vue +111 -111
  257. package/src/components/inputs/select/select.stories.js +59 -59
  258. package/src/components/inputs/slider/index.vue +126 -126
  259. package/src/components/inputs/switchField/index.vue +256 -256
  260. package/src/components/inputs/textAreaInput/TextAreaInput.stories.js +127 -127
  261. package/src/components/inputs/textAreaInput/index.vue +200 -200
  262. package/src/components/inputs/toggle/Toggle.stories.js +77 -77
  263. package/src/components/inputs/toggle/index.vue +288 -288
  264. package/src/components/label/index.vue +103 -99
  265. package/src/components/modals/modal/index.vue +192 -188
  266. package/src/components/modals/modal/modal.stories.js +31 -31
  267. package/src/components/navigationTabs/index.vue +105 -112
  268. package/src/components/pageSubtitle/index.vue +61 -61
  269. package/src/components/pageTitle/index.vue +73 -73
  270. package/src/components/pagination/index.vue +144 -144
  271. package/src/components/progressBar/index.vue +125 -125
  272. package/src/components/projectMarker/index.vue +291 -294
  273. package/src/components/sideMenu/index.vue +270 -270
  274. package/src/components/spinner/index.vue +72 -67
  275. package/src/components/tableDropdown/index.vue +637 -632
  276. package/src/components/tables/mainTable/exampleNested.vue +328 -328
  277. package/src/components/tables/mainTable/index.vue +446 -447
  278. package/src/components/tables/viewTable/index.vue +195 -195
  279. package/src/components/threeDots/index.vue +393 -393
  280. package/src/components/videoThumbnail/index.vue +108 -103
  281. package/src/components/videoThumbnail/videoThumbnail.stories.js +35 -35
  282. package/src/helpers/numberConverter.js +103 -103
  283. package/src/helpers/translateLang.js +127 -127
  284. package/src/main.js +13 -6
@@ -1,757 +1,627 @@
1
- <template>
2
- <Container
3
- :selectWidth="selectWidth"
4
- @mouseenter="mouseEnterHandler"
5
- @mouseleave="mouseLeaveHandler"
6
- >
7
- <input-wrapper
8
- :hasLabel="!!label && label.length > 0"
9
- :alignItems="alignItems"
10
- >
11
- <label-wrapper v-if="label" :data-id="labelDataId">
12
- <input-label
13
- :fontColor="
14
- labelFontColor || colorMode == 'dark' ? 'white' : 'eturnityGrey'
15
- "
16
- :fontSize="fontSize"
17
- >{{ label }}
18
- <optionalLabel v-if="labelOptional">
19
- ({{ $gettext('Optional') }})</optionalLabel
20
- >
21
- </input-label>
22
- <info-text
23
- v-if="infoTextMessage"
24
- :text="infoTextMessage"
25
- :size="infoTextSize"
26
- />
27
- </label-wrapper>
28
- <select-button-wrapper :disabled="disabled">
29
- <selectButton
30
- ref="select"
31
- class="select-button"
32
- @click="toggleDropdown"
33
- :selectWidth="selectWidth"
34
- :selectHeight="selectHeight"
35
- :height="height"
36
- :selectMinHeight="selectMinHeight"
37
- :bgColor="
38
- buttonBgColor || colorMode == 'dark' ? 'transparentBlack1' : 'white'
39
- "
40
- :fontColor="
41
- buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
42
- "
43
- :hasError="hasError"
44
- :hasNoPadding="isSearchBarVisible || !hasSelectButtonPadding"
45
- :disabled="disabled"
46
- @keydown="onKeyDown"
47
- :showBorder="showBorder"
48
- :data-id="dataId"
49
- :paddingLeft="paddingLeft"
50
- >
51
- <draggableInputHandle
52
- v-if="isDraggable && !isSearchBarVisible"
53
- :height="selectHeight"
54
- />
55
- <inputText
56
- v-if="isSearchBarVisible"
57
- ref="searchInput"
58
- tabindex="0"
59
- inputHeight="34px"
60
- :noBorder="true"
61
- :fontSize="fontSize"
62
- backgroundColor="transparent"
63
- :fontColor="
64
- buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
65
- "
66
- :value="textSearch"
67
- @keydown.stop="onKeyDown"
68
- @input-change="searchChange"
69
- @click.stop
70
- />
71
- <selector
72
- v-else
73
- :selectWidth="selectWidth"
74
- :paddingLeft="paddingLeft"
75
- >
76
- <slot name="selector" :selectedValue="selectedValue"></slot>
77
- </selector>
78
- <Caret @click.stop="toggleCaretDropdown">
79
- <icon
80
- v-if="isDropdownOpen"
81
- name="arrow_up"
82
- size="12px"
83
- :color="
84
- caretColor || colorMode == 'dark'
85
- ? 'white'
86
- : 'transparentBlack1'
87
- "
88
- />
89
- <icon
90
- v-else
91
- name="arrow_down"
92
- size="12px"
93
- :color="
94
- caretColor || colorMode == 'dark'
95
- ? 'white'
96
- : 'transparentBlack1'
97
- "
98
- />
99
- </Caret>
100
- </selectButton>
101
- <DropdownWrapper ref="dropdownWrapperRef">
102
- <Teleport to="#portal-target">
103
- <selectDropdown
104
- ref="dropdown"
105
- v-show="isSelectDropdownShown"
106
- :dropdownPosition="dropdownPosition"
107
- :hoveredIndex="hoveredIndex"
108
- :hoveredValue="hoveredValue"
109
- :isActive="isActive"
110
- :optionWidth="getOptionWidth"
111
- :hoveredBgColor="
112
- colorMode == 'dark' ? '#000000' : dropdownBgColor
113
- "
114
- :bgColor="
115
- dropdownBgColor || colorMode == 'dark' ? 'black' : 'white'
116
- "
117
- :fontColor="
118
- dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
119
- "
120
- :fontSize="fontSize"
121
- :selectedValue="selectedValue"
122
- @option-selected="optionSelected"
123
- @option-hovered="optionHovered"
124
- >
125
- <slot name="dropdown"></slot>
126
- </selectDropdown>
127
- </Teleport>
128
- </DropdownWrapper>
129
- </select-button-wrapper>
130
- </input-wrapper>
131
- </Container>
132
- </template>
133
-
134
- <script>
135
- //How to use it
136
- // <Select
137
- // hoverDropdown="true"
138
- // selectWidth="100%"
139
- // optionWidth="50%"
140
- // label="that is a label"
141
- // alignItems="vertical"
142
- // label-data-id="test-label-data-id"
143
- // data-id="test-data-id"
144
- // :hasSelectButtonPadding="false"
145
- // >
146
- // <template #selector="{selectedValue}">
147
- // value selected: {{selectedValue}}
148
- // </template>
149
- // <template #dropdown>
150
- // <Option value="1">value one</Option>
151
- // <Option value="2">value two</Option>
152
- // <Option value="3">value three</Option>
153
- // <Option value="4">value four</Option>
154
- // </template>
155
- // </Select>
156
-
157
- import { Teleport } from 'vue'
158
- import styled from 'vue3-styled-components'
159
- import InfoText from '../../infoText'
160
- import icon from '../../icon'
161
- import inputText from '../inputText'
162
- import draggableInputHandle from '../../draggableInputHandle'
163
-
164
- const CARET_WIDTH = '30px'
165
- const BORDER_WIDTH = '1px'
166
-
167
- const Caret = styled.div`
168
- display: flex;
169
- align-items: center;
170
- justify-content: center;
171
- width: ${CARET_WIDTH};
172
- min-width: ${CARET_WIDTH};
173
- height: 100%;
174
- align-items: center;
175
- cursor: pointer;
176
- margin-left: auto;
177
- `
178
-
179
- const Selector = styled('div', { selectWidth: String, paddingLeft: String })`
180
- width: ${(props) =>
181
- `calc(${props.selectWidth} - (${CARET_WIDTH} + ${props.paddingLeft} + (${BORDER_WIDTH} * 2)))`};
182
- white-space: nowrap;
183
- text-overflow: ellipsis;
184
- overflow: hidden;
185
- `
186
-
187
- const labelAttrs = { fontSize: String, fontColor: String }
188
- const InputLabel = styled('div', labelAttrs)`
189
- color: ${(props) =>
190
- props.theme.colors[props.fontColor]
191
- ? props.theme.colors[props.fontColor]
192
- : props.fontColor};
193
- font-size: ${(props) => props.fontSize};
194
- font-weight: 700;
195
- `
196
- const optionalLabel = styled.span`
197
- font-weight: 300;
198
- `
199
- const inputProps = {
200
- selectWidth: String,
201
- optionWidth: String
202
- }
203
- const Container = styled('div', inputProps)`
204
- width: ${(props) => props.selectWidth};
205
- position: relative;
206
- display: inline-block;
207
- `
208
- const LabelWrapper = styled.div`
209
- display: inline-grid;
210
- grid-template-columns: auto auto;
211
- grid-gap: 12px;
212
- align-items: center;
213
- justify-content: start;
214
- `
215
-
216
- const SelectButtonWrapperAttrs = {
217
- disabled: Boolean
218
- }
219
- const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
220
- ${(props) => (props.disabled ? 'cursor: not-allowed' : 'cursor: pointer')};
221
- `
222
-
223
- const selectButtonAttrs = {
224
- bgColor: String,
225
- fontColor: String,
226
- hasError: Boolean,
227
- disabled: Boolean,
228
- selectHeight: String,
229
- selectWidth: String,
230
- height: String,
231
- selectMinHeight: String,
232
- hasNoPadding: Boolean,
233
- showBorder: Boolean,
234
- paddingLeft: String
235
- }
236
- const selectButton = styled('div', selectButtonAttrs)`
237
- position: relative;
238
- box-sizing: border-box;
239
- border-radius: 4px;
240
- max-width: ${(props) => (props.selectWidth ? props.selectWidth : '100%')};
241
- ${(props) =>
242
- props.hasNoPadding ? '' : `padding-left: ${props.paddingLeft}`};
243
- text-align: left;
244
- min-height: ${(props) =>
245
- props.selectHeight
246
- ? props.selectHeight
247
- : props.selectMinHeight
248
- ? props.selectMinHeight
249
- : props.height
250
- ? props.height
251
- : '36px'};
252
- display: flex;
253
- align-items: center;
254
- height: ${(props) => props.selectHeight};
255
- ${({ showBorder, theme, hasError }) =>
256
- showBorder &&
257
- `
258
- border: ${BORDER_WIDTH} solid ${
259
- hasError ? theme.colors.red : theme.colors.grey4
260
- }
261
- `}
262
- background-color:${(props) =>
263
- props.disabled
264
- ? props.theme.colors.grey5
265
- : props.theme.colors[props.bgColor]
266
- ? props.theme.colors[props.bgColor]
267
- : props.bgColor};
268
- color: ${(props) =>
269
- props.theme.colors[props.fontColor]
270
- ? props.theme.colors[props.fontColor]
271
- : props.fontColor};
272
- ${(props) => (props.disabled ? 'pointer-events: none' : '')};
273
- overflow: hidden;
274
- & > .handle {
275
- border-right: ${(props) =>
276
- props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
277
- 1px solid;
278
- }
279
- `
280
- const selectDropdownAttrs = {
281
- hoveredBgColor: String,
282
- bgColor: String,
283
- fontColor: String,
284
- optionWidth: String,
285
- hoveredIndex: Number,
286
- fontSize: String,
287
- dropdownPosition: Object,
288
- hoveredValue: Number | String,
289
- selectedValue: Number | String
290
- }
291
- const selectDropdown = styled('div', selectDropdownAttrs)`
292
- box-sizing: border-box;
293
- z-index: ${(props) => (props.isActive ? '2' : '99999')};
294
- position: absolute;
295
- top: ${(props) => props.dropdownPosition?.top}px;
296
- left: ${(props) => props.dropdownPosition?.left}px;
297
- border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
298
- border-radius: 4px;
299
- display: flex;
300
- flex-direction: column;
301
- align-items: flex-start;
302
- padding: 0px;
303
- box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
304
- width: ${(props) => props.optionWidth};
305
- background-color: ${(props) =>
306
- props.theme.colors[props.bgColor]
307
- ? props.theme.colors[props.bgColor]
308
- : props.bgColor};
309
- color: ${(props) =>
310
- props.theme.colors[props.fontColor]
311
- ? props.theme.colors[props.fontColor]
312
- : props.fontColor};
313
- max-height: 300px;
314
- overflow-y: auto;
315
- & > div[data-value='${(props) => props.hoveredValue}'] {
316
- background-color: ${(props) =>
317
- props.theme.colors[props.hoveredBgColor]
318
- ? props.theme.colors[props.hoveredBgColor]
319
- : props.hoveredBgColor};
320
- }
321
- font-size: ${(props) => props.fontSize};
322
- `
323
- selectDropdown.emits = ['option-hovered', 'option-selected']
324
- const DropdownWrapper = styled('div')`
325
- position: relative;
326
- `
327
- const inputAttrs = { alignItems: String, hasLabel: Boolean }
328
- const InputWrapper = styled('div', inputAttrs)`
329
- position: relative;
330
- display: grid;
331
- align-items: center;
332
- gap: 8px;
333
- grid-template-columns: ${(props) =>
334
- props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
335
- `
336
-
337
- const DROPDOWN_HEIGHT_OFFSET = 4
338
- const DROPDOWN_TOP_OFFSET = 21
339
-
340
- export default {
341
- name: 'RCselect',
342
-
343
- props: {
344
- value: {
345
- required: false,
346
- default: null
347
- },
348
- fontSize: {
349
- required: false,
350
- default: '13px'
351
- },
352
- label: {
353
- required: false
354
- },
355
- labelOptional: {
356
- required: false,
357
- default: false
358
- },
359
- labelDataId: {
360
- required: false,
361
- default: ''
362
- },
363
- infoTextMessage: {
364
- required: false
365
- },
366
- selectWidth: {
367
- type: String,
368
- required: false,
369
- default: '100%'
370
- },
371
- selectHeight: {
372
- type: String,
373
- required: false,
374
- default: null
375
- },
376
- height: {
377
- required: false,
378
- default: null
379
- },
380
- selectMinHeight: {
381
- required: false,
382
- default: '36px'
383
- },
384
- optionWidth: {
385
- required: false,
386
- default: null
387
- },
388
- hoverDropdown: {
389
- required: false,
390
- default: false
391
- },
392
- dropdownAutoClose: {
393
- required: false,
394
- default: false
395
- },
396
- alignItems: {
397
- required: false,
398
- default: 'horizontal'
399
- },
400
- buttonBgColor: {
401
- required: false
402
- },
403
- buttonFontColor: {
404
- required: false
405
- },
406
- dropdownBgColor: {
407
- required: false,
408
- default: 'grey5'
409
- },
410
- dropdownFontColor: {
411
- required: false
412
- },
413
- caretColor: {
414
- required: false
415
- },
416
- labelFontColor: {
417
- required: false
418
- },
419
- colorMode: {
420
- required: false,
421
- default: 'light'
422
- },
423
- isSearchable: {
424
- required: false,
425
- default: true
426
- },
427
- hasError: {
428
- required: false,
429
- default: false
430
- },
431
- disabled: {
432
- required: false,
433
- default: false
434
- },
435
- isAutoSearch: {
436
- required: false,
437
- default: true
438
- },
439
- showBorder: {
440
- required: false,
441
- default: true
442
- },
443
- infoTextSize: {
444
- required: false,
445
- default: '14px'
446
- },
447
- dataId: {
448
- type: String,
449
- default: ''
450
- },
451
- hasSelectButtonPadding: {
452
- type: Boolean,
453
- default: true
454
- },
455
- isDraggable: {
456
- type: Boolean,
457
- default: false
458
- }
459
- },
460
-
461
- components: {
462
- selectButton,
463
- SelectButtonWrapper,
464
- selectDropdown,
465
- Container,
466
- InputLabel,
467
- LabelWrapper,
468
- optionalLabel,
469
- InfoText,
470
- InputWrapper,
471
- DropdownWrapper,
472
- icon,
473
- Caret,
474
- Selector,
475
- inputText,
476
- Teleport,
477
- draggableInputHandle
478
- },
479
-
480
- data() {
481
- return {
482
- selectedValue: null,
483
- paddingLeft: this.isDraggable ? '30px' : '15px',
484
- isDropdownOpen: false,
485
- isActive: false,
486
- textSearch: '',
487
- hoveredIndex: 0,
488
- isClickOutsideActive: false,
489
- dropdownPosition: {
490
- left: null,
491
- top: null
492
- },
493
- dropdownWidth: null,
494
- hoveredValue: null
495
- }
496
- },
497
- mounted() {
498
- this.observeDropdownHeight()
499
- this.observeSelectWidth()
500
- window.addEventListener('resize', this.handleSetDropdownOffet)
501
- },
502
- beforeMount() {
503
- this.selectedValue = this.value
504
- document.addEventListener('click', this.clickOutside)
505
- this.getDropdownPosition()
506
- window.removeEventListener('resize', this.handleSetDropdownOffet)
507
- if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
508
- if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
509
- },
510
- unmounted() {
511
- document.removeEventListener('click', this.clickOutside)
512
- },
513
- methods: {
514
- focus() {
515
- this.isActive = true
516
- },
517
- blur(e) {
518
- this.isActive = false
519
- this.$emit('blur', e)
520
- },
521
- toggleDropdown() {
522
- this.isDropdownOpen = !this.isDropdownOpen
523
- },
524
- toggleCaretDropdown() {
525
- this.isDropdownOpen = !this.isDropdownOpen
526
- },
527
- openDropdown() {
528
- this.focus()
529
- this.isDropdownOpen = true
530
- },
531
- closeDropdown() {
532
- this.blur()
533
- this.isDropdownOpen = false
534
- },
535
- clearSearch() {
536
- this.textSearch = ''
537
- },
538
- optionSelected(e) {
539
- this.selectedValue = e
540
- this.closeDropdown()
541
- this.blur()
542
- this.$emit('input-change', e)
543
- },
544
- optionHovered(e) {
545
- this.hoveredValue = e
546
- },
547
- mouseEnterHandler() {
548
- if (this.hoverDropdown) {
549
- this.focus()
550
- this.isDropdownOpen = true
551
- }
552
- },
553
- mouseLeaveHandler() {
554
- if (this.hoverDropdown) {
555
- this.blur()
556
- }
557
- },
558
- optionLeave() {
559
- if (this.dropdownAutoClose) {
560
- this.isDropdownOpen = false
561
- }
562
- },
563
- searchChange(value) {
564
- this.textSearch = value
565
- this.$emit('search-change', value)
566
- const dropdownChildren = [...this.$refs.dropdown.$el.children]
567
- dropdownChildren.forEach((el) => {
568
- if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
569
- el.style.display = 'none'
570
-
571
- return
572
- }
573
- el.style.display = 'inherit'
574
- })
575
- },
576
- clickOutside(event) {
577
- const dropdownRef = this.$refs.dropdown
578
- // we need to prevent closing on selecting an option, because in the case of
579
- // a disabled option, we don't want to close the dropdown
580
- if (!this.isClickOutsideActive) return
581
- if (
582
- this.$refs.select.$el == event.target ||
583
- this.$refs.select.$el.contains(event.target) ||
584
- event.target.id === 'more-button' ||
585
- event.target.parentNode === dropdownRef.$el
586
- ) {
587
- return
588
- } else {
589
- this.closeDropdown()
590
- }
591
- },
592
- onKeyDown(e) {
593
- if (e.key == 'ArrowDown') {
594
- this.onArrowPress(1)
595
- } else if (e.key == 'ArrowUp') {
596
- this.onArrowPress(-1)
597
- } else if (e.key == 'Enter') {
598
- const optionHoveredComponent = [...this.$refs.dropdown.$el.children][
599
- (this.hoveredIndex - 1 + this.optionLength) % this.optionLength
600
- ]
601
- this.optionSelected(optionHoveredComponent.$el.dataset.value)
602
- }
603
- },
604
- // If some part of the dropdown menu is outside viewport of the bottom of the screen,
605
- // we need to offset it and display it at the top of the select dropdown instead
606
- async getDropdownPosition() {
607
- if (
608
- !this.$refs.dropdownWrapperRef ||
609
- !this.$refs.select ||
610
- !this.$refs.dropdown
611
- ) {
612
- return
613
- }
614
- await this.$nextTick()
615
- const isDisplayedAtBottom = await this.generateDropdownPosition()
616
- await this.$nextTick()
617
- // If the dropdown menu is going to be displayed at the bottom,
618
- // we need reverify its position after a dom update (nextTick)
619
- if (isDisplayedAtBottom) this.generateDropdownPosition()
620
- },
621
- async generateDropdownPosition() {
622
- const isDropdownNotCompletelyVisible =
623
- await this.isBottomOfDropdownOutOfViewport()
624
- const dropdownWrapperEl = this.$refs.dropdownWrapperRef.$el
625
- const selectButtonHeight = this.$refs.select.$el.clientHeight
626
- const dropdownHeight = this.$refs.dropdown.$el.clientHeight
627
- const dropdownWrapperRelativeHeight =
628
- dropdownWrapperEl.getBoundingClientRect().top +
629
- window.scrollY +
630
- DROPDOWN_HEIGHT_OFFSET
631
-
632
- const top = isDropdownNotCompletelyVisible
633
- ? dropdownWrapperRelativeHeight
634
- : dropdownWrapperRelativeHeight -
635
- dropdownHeight -
636
- selectButtonHeight -
637
- DROPDOWN_TOP_OFFSET
638
- const left = this.dropdownPosition.left
639
- ? this.dropdownPosition.left
640
- : dropdownWrapperEl.getBoundingClientRect().left + window.scrollX
641
-
642
- this.dropdownPosition = { left: Math.floor(left), top: Math.floor(top) }
643
-
644
- return isDropdownNotCompletelyVisible
645
- },
646
- async isBottomOfDropdownOutOfViewport() {
647
- if (!this.$refs.dropdown) {
648
- return false
649
- }
650
- await this.$nextTick()
651
- const rect = this.$refs.dropdown.$el.getBoundingClientRect()
652
- const windowHeight =
653
- window.innerHeight || document.documentElement.clientHeight
654
-
655
- // using Math.floor because the offsets may contain decimals we are not going to consider here
656
- return Math.floor(rect.top) + Math.floor(rect.height) <= windowHeight
657
- },
658
- observeDropdownHeight() {
659
- if (!this.$refs.dropdown) return
660
- this.dropdownResizeObserver = new ResizeObserver(() => {
661
- this.$nextTick(() => this.getDropdownPosition())
662
- })
663
- this.dropdownResizeObserver.observe(this.$refs.dropdown.$el)
664
- },
665
- handleSetDropdownOffet() {
666
- if (!this.$refs.select) return
667
- this.dropdownPosition.left = Math.floor(
668
- this.$refs.select.$el.getBoundingClientRect().left
669
- )
670
- this.getDropdownWidth()
671
- },
672
- observeSelectWidth() {
673
- if (!this.$refs.select) return
674
- this.selectResizeObserver = new ResizeObserver(() =>
675
- this.$nextTick(() => this.getDropdownWidth())
676
- )
677
- this.selectResizeObserver.observe(this.$refs.dropdown.$el)
678
- },
679
- async getDropdownWidth() {
680
- if (!this.$refs.select) return
681
- await this.$nextTick()
682
- this.dropdownWidth = `${this.$refs.select.$el.clientWidth}px`
683
- },
684
- onArrowPress(dir) {
685
- let newHoveredElem
686
- const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
687
- `[data-value="${this.hoveredValue}"]`
688
- )
689
- if (currentHoveredElem) {
690
- if (dir > 0) {
691
- newHoveredElem = currentHoveredElem.nextElementSibling
692
- } else {
693
- newHoveredElem = currentHoveredElem.previousElementSibling
694
- }
695
- if (newHoveredElem) {
696
- this.hoveredValue = newHoveredElem.getAttribute('data-value')
697
- const topPos = newHoveredElem.offsetTop
698
- this.$refs.dropdown.$el.scrollTop = topPos
699
- }
700
- }
701
- },
702
- clearSearch() {
703
- this.textSearch = ''
704
- }
705
- },
706
- computed: {
707
- optionLength() {
708
- if (this.isDropdownOpen) {
709
- return this.$refs.dropdown.$el.childElementCount
710
- }
711
-
712
- return 0
713
- },
714
- isSearchBarVisible() {
715
- return this.isSearchable && this.optionLength >= 5 && this.isDropdownOpen
716
- },
717
- getOptionWidth() {
718
- if (this.optionWidth) return this.optionWidth
719
-
720
- return this.dropdownWidth
721
- },
722
- isSelectDropdownShown() {
723
- return (
724
- this.isSearchable &&
725
- this.isDropdownOpen &&
726
- this.dropdownPosition.left !== null
727
- )
728
- }
729
- },
730
- watch: {
731
- value(val) {
732
- this.selectedValue = val
733
- },
734
- async isDropdownOpen(val) {
735
- if (val) {
736
- setTimeout(() => {
737
- this.isClickOutsideActive = true
738
- }, 10)
739
- await this.$nextTick()
740
- this.handleSetDropdownOffet()
741
- } else {
742
- this.dropdownPosition.left = null
743
- setTimeout(() => {
744
- this.isClickOutsideActive = false
745
- }, 10)
746
- }
747
- if (val && this.isSearchable) {
748
- this.$nextTick(() => {
749
- if (this.$refs.searchInput) {
750
- this.$refs.searchInput.$el.querySelector('input').focus()
751
- }
752
- })
753
- }
754
- }
755
- }
756
- }
757
- </script>
1
+ <template>
2
+ <Container
3
+ :selectWidth="selectWidth"
4
+ @mouseenter="mouseEnterHandler"
5
+ @mouseleave="mouseLeaveHandler"
6
+ >
7
+ <input-wrapper
8
+ :hasLabel="!!label && label.length > 0"
9
+ :alignItems="alignItems"
10
+ >
11
+ <label-wrapper v-if="label" :data-id="labelDataId">
12
+ <input-label
13
+ :fontColor="
14
+ labelFontColor || colorMode == 'dark' ? 'white' : 'eturnityGrey'
15
+ "
16
+ :fontSize="fontSize"
17
+ >{{ label }}
18
+ <optionalLabel v-if="labelOptional">
19
+ ({{ $gettext('Optional') }})</optionalLabel
20
+ >
21
+ </input-label>
22
+ <info-text
23
+ v-if="infoTextMessage"
24
+ :text="infoTextMessage"
25
+ :size="infoTextSize"
26
+ />
27
+ </label-wrapper>
28
+ <select-button-wrapper :disabled="disabled">
29
+ <selectButton
30
+ ref="select"
31
+ @click="toggleDropdown"
32
+ :selectHeight="selectHeight"
33
+ :height="height"
34
+ :selectMinHeight="selectMinHeight"
35
+ :bgColor="
36
+ buttonBgColor || colorMode == 'dark' ? 'transparentBlack1' : 'white'
37
+ "
38
+ :fontColor="
39
+ buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
40
+ "
41
+ :hasError="hasError"
42
+ :isSearchBarVisible="isSearchBarVisible"
43
+ :disabled="disabled"
44
+ @keydown.native="onKeyDown"
45
+ :showBorder="showBorder"
46
+ :data-id="dataId"
47
+ :paddingLeft="paddingLeft"
48
+ >
49
+ <draggableInputHandle
50
+ v-if="isDraggable && !isSearchBarVisible"
51
+ :height="selectHeight"
52
+ />
53
+ <inputText
54
+ v-if="isSearchBarVisible"
55
+ ref="searchInput"
56
+ tabindex="0"
57
+ inputHeight="34px"
58
+ :noBorder="true"
59
+ :fontSize="fontSize"
60
+ backgroundColor="transparent"
61
+ :fontColor="
62
+ buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
63
+ "
64
+ :value="textSearch"
65
+ @keydown.stop="onKeyDown"
66
+ @input-change="searchChange"
67
+ @click.native.stop
68
+ />
69
+ <selector
70
+ v-else
71
+ :showBorder="showBorder"
72
+ :selectWidth="selectWidth"
73
+ :paddingLeft="paddingLeft"
74
+ >
75
+ <slot name="selector" :selectedValue="selectedValue"></slot>
76
+ </selector>
77
+ <Caret @click.stop="toggleCaretDropdown">
78
+ <icon
79
+ v-if="isDropdownOpen"
80
+ name="arrow_up"
81
+ size="12px"
82
+ :color="
83
+ caretColor || colorMode == 'dark'
84
+ ? 'white'
85
+ : 'transparentBlack1'
86
+ "
87
+ />
88
+ <icon
89
+ v-else
90
+ name="arrow_down"
91
+ size="12px"
92
+ :color="
93
+ caretColor || colorMode == 'dark'
94
+ ? 'white'
95
+ : 'transparentBlack1'
96
+ "
97
+ />
98
+ </Caret>
99
+ </selectButton>
100
+ <DropdownWrapper>
101
+ <selectDropdown
102
+ ref="dropdown"
103
+ v-show="isDropdownOpen"
104
+ :hoveredIndex="hoveredIndex"
105
+ :hoveredValue="hoveredValue"
106
+ :isActive="isActive"
107
+ :optionWidth="optionWidth"
108
+ :hoveredBgColor="colorMode == 'dark' ? '#000000' : dropdownBgColor"
109
+ :bgColor="colorMode == 'dark' ? 'black' : dropdownBgColor"
110
+ :fontColor="
111
+ dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
112
+ "
113
+ :selectedValue="selectedValue"
114
+ @option-selected="optionSelected"
115
+ @option-hovered="optionHovered"
116
+ @mouseleave="optionLeave"
117
+ >
118
+ <slot name="dropdown"></slot>
119
+ </selectDropdown>
120
+ </DropdownWrapper>
121
+ </select-button-wrapper>
122
+ </input-wrapper>
123
+ </Container>
124
+ </template>
125
+
126
+ <script>
127
+ //How to use it
128
+ // <Select
129
+ // hoverDropdown="true"
130
+ // selectWidth="100%"
131
+ // optionWidth="50%"
132
+ // label="that is a label"
133
+ // alignItems="vertical"
134
+ // label-data-id="test-label0data-id"
135
+ // data-id="test-data-id"
136
+ // >
137
+ // <template #selector="{selectedValue}">
138
+ // value selected: {{selectedValue}}
139
+ // </template>
140
+ // <template #dropdown>
141
+ // <Option value="1">value one</Option>
142
+ // <Option value="2">value two</Option>
143
+ // <Option value="3">value three</Option>
144
+ // <Option value="4">value four</Option>
145
+ // </template>
146
+ // </Select>
147
+
148
+ import styled from 'vue-styled-components'
149
+ import InfoText from '../../infoText'
150
+ import icon from '../../icon'
151
+ import inputText from '../inputText'
152
+ import draggableInputHandle from '../../draggableInputHandle'
153
+
154
+ const CARET_WIDTH = '30px'
155
+ const BORDER_WIDTH = '1px'
156
+
157
+ const Caret = styled.div`
158
+ display: flex;
159
+ align-items: center;
160
+ justify-content: center;
161
+ width: ${CARET_WIDTH};
162
+ min-width: ${CARET_WIDTH};
163
+ height: 100%;
164
+ align-items: stretch;
165
+ cursor: pointer;
166
+ margin-left: auto;
167
+ `
168
+
169
+ const selectorProps = {
170
+ selectWidth: String,
171
+ paddingLeft: String,
172
+ showBorder: Boolean
173
+ }
174
+ const Selector = styled('div', selectorProps)`
175
+ ${(props) => props.selectWidth === '100%' ? 'width: 100%;' : `width: calc(${props.selectWidth} -
176
+ (
177
+ ${CARET_WIDTH} +
178
+ ${props.paddingLeft}
179
+ ${props.showBorder ? `+ (${BORDER_WIDTH} * 2)` : ''}
180
+ )
181
+ );
182
+ white-space: nowrap;
183
+ text-overflow: ellipsis;
184
+ overflow: hidden;`
185
+ }
186
+ `
187
+
188
+ const labelAttrs = { fontSize: String, fontColor: String }
189
+ const InputLabel = styled('div', labelAttrs)`
190
+ color: ${(props) =>
191
+ props.theme.colors[props.fontColor]
192
+ ? props.theme.colors[props.fontColor]
193
+ : props.fontColor};
194
+ font-size: ${(props) => props.fontSize};
195
+ font-weight: 700;
196
+ `
197
+ const optionalLabel = styled.span`
198
+ font-weight: 300;
199
+ `
200
+ const inputProps = { selectWidth: String, optionWidth: String }
201
+ const Container = styled('div', inputProps)`
202
+ width: ${(props) => props.selectWidth};
203
+ position: relative;
204
+ display: inline-block;
205
+ `
206
+ const LabelWrapper = styled.div`
207
+ display: inline-grid;
208
+ grid-template-columns: auto auto;
209
+ grid-gap: 12px;
210
+ align-items: center;
211
+ justify-content: start;
212
+ `
213
+
214
+ const SelectButtonWrapperAttrs = {
215
+ disabled: Boolean
216
+ }
217
+ const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
218
+ ${(props) => (props.disabled ? 'cursor: not-allowed' : 'cursor: pointer')};
219
+ `
220
+
221
+ const selectButtonAttrs = {
222
+ bgColor: String,
223
+ fontColor: String,
224
+ hasError: Boolean,
225
+ disabled: Boolean,
226
+ selectHeight: String,
227
+ height: String,
228
+ selectMinHeight: String,
229
+ isSearchBarVisible: Boolean,
230
+ showBorder: Boolean,
231
+ paddingLeft: String
232
+ }
233
+ const selectButton = styled('div', selectButtonAttrs)`
234
+ position: relative;
235
+ box-sizing: border-box;
236
+ border-radius: 4px;
237
+ ${(props) =>
238
+ props.isSearchBarVisible ? '' : `padding-left: ${props.paddingLeft}`};
239
+ text-align: left;
240
+ min-height: ${(props) =>
241
+ props.selectHeight
242
+ ? props.selectHeight
243
+ : props.selectMinHeight
244
+ ? props.selectMinHeight
245
+ : props.height
246
+ ? props.height
247
+ : '36px'};
248
+ display: flex;
249
+ align-items: center;
250
+ max-height: ${(props) => props.selectHeight};
251
+ ${({ showBorder, theme, hasError }) =>
252
+ showBorder &&
253
+ `
254
+ border: ${BORDER_WIDTH} solid ${
255
+ hasError ? theme.colors.red : theme.colors.grey4
256
+ }
257
+ `}
258
+ background-color:${(props) =>
259
+ props.disabled
260
+ ? props.theme.colors.grey5
261
+ : props.theme.colors[props.bgColor]
262
+ ? props.theme.colors[props.bgColor]
263
+ : props.bgColor};
264
+ color: ${(props) =>
265
+ props.theme.colors[props.fontColor]
266
+ ? props.theme.colors[props.fontColor]
267
+ : props.fontColor};
268
+ ${(props) => (props.disabled ? 'pointer-events: none' : '')};
269
+ overflow: hidden;
270
+ & > .handle {
271
+ border-right: ${(props) =>
272
+ props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
273
+ 1px solid;
274
+ }
275
+ `
276
+ const selectDropdownAttrs = {
277
+ hoveredBgColor: String,
278
+ bgColor: String,
279
+ fontColor: String,
280
+ optionWidth: String,
281
+ hoveredIndex: Number,
282
+ hoveredValue: Number | String,
283
+ selectedValue: Number | String
284
+ }
285
+ const selectDropdown = styled('div', selectDropdownAttrs)`
286
+ box-sizing: border-box;
287
+ z-index: ${(props) => (props.isActive ? '2' : '1')};
288
+ position: absolute;
289
+ top: 5px;
290
+ border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
291
+ border-radius: 4px;
292
+ display: flex;
293
+ flex-direction: column;
294
+ align-items: flex-start;
295
+ padding: 0px;
296
+ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
297
+ width: ${(props) => (props.optionWidth ? props.optionWidth : '100%')};
298
+ background-color: ${(props) =>
299
+ props.theme.colors[props.bgColor]
300
+ ? props.theme.colors[props.bgColor]
301
+ : props.bgColor};
302
+ color: ${(props) =>
303
+ props.theme.colors[props.fontColor]
304
+ ? props.theme.colors[props.fontColor]
305
+ : props.fontColor};
306
+ max-height: 300px;
307
+ overflow-y: auto;
308
+ & > div[data-value='${(props) => props.hoveredValue}'] {
309
+ background-color: ${(props) =>
310
+ props.theme.colors[props.hoveredBgColor]
311
+ ? props.theme.colors[props.hoveredBgColor]
312
+ : props.hoveredBgColor};
313
+ }
314
+ `
315
+ const DropdownWrapper = styled('div')`
316
+ position: relative;
317
+ `
318
+ const inputAttrs = { alignItems: String, hasLabel: Boolean }
319
+ const InputWrapper = styled('div', inputAttrs)`
320
+ position: relative;
321
+ display: grid;
322
+ align-items: center;
323
+ gap: 8px;
324
+ grid-template-columns: ${(props) =>
325
+ props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
326
+ `
327
+ export default {
328
+ name: 'RCselect',
329
+
330
+ props: {
331
+ value: {
332
+ required: false,
333
+ default: null
334
+ },
335
+ fontSize: {
336
+ required: false,
337
+ default: '13px'
338
+ },
339
+ label: {
340
+ required: false
341
+ },
342
+ labelOptional: {
343
+ required: false,
344
+ default: false
345
+ },
346
+ labelDataId: {
347
+ required: false,
348
+ default: ''
349
+ },
350
+ infoTextMessage: {
351
+ required: false
352
+ },
353
+ selectWidth: {
354
+ type: String,
355
+ required: false,
356
+ default: '100%'
357
+ },
358
+ selectHeight: {
359
+ type: String,
360
+ required: false,
361
+ default: null
362
+ },
363
+ height: {
364
+ required: false,
365
+ default: null
366
+ },
367
+ selectMinHeight: {
368
+ required: false,
369
+ default: '36px'
370
+ },
371
+ optionWidth: {
372
+ required: false,
373
+ default: null
374
+ },
375
+ hoverDropdown: {
376
+ required: false,
377
+ default: false
378
+ },
379
+ dropdownAutoClose: {
380
+ required: false,
381
+ default: false
382
+ },
383
+ alignItems: {
384
+ required: false,
385
+ default: 'horizontal'
386
+ },
387
+ buttonBgColor: {
388
+ required: false
389
+ },
390
+ buttonFontColor: {
391
+ required: false
392
+ },
393
+ dropdownBgColor: {
394
+ required: false,
395
+ default: 'grey5'
396
+ },
397
+ dropdownFontColor: {
398
+ required: false
399
+ },
400
+ caretColor: {
401
+ required: false
402
+ },
403
+ labelFontColor: {
404
+ required: false
405
+ },
406
+ colorMode: {
407
+ required: false,
408
+ default: 'light'
409
+ },
410
+ isSearchable: {
411
+ required: false,
412
+ default: true
413
+ },
414
+ hasError: {
415
+ required: false,
416
+ default: false
417
+ },
418
+ disabled: {
419
+ required: false,
420
+ default: false
421
+ },
422
+ isAutoSearch: {
423
+ required: false,
424
+ default: true
425
+ },
426
+ showBorder: {
427
+ required: false,
428
+ default: true
429
+ },
430
+ infoTextSize: {
431
+ required: false,
432
+ default: '14px'
433
+ },
434
+ dataId: {
435
+ type: String,
436
+ default: ''
437
+ },
438
+ isDraggable: {
439
+ type: Boolean,
440
+ default: false
441
+ }
442
+ },
443
+
444
+ components: {
445
+ selectButton,
446
+ SelectButtonWrapper,
447
+ selectDropdown,
448
+ Container,
449
+ InputLabel,
450
+ LabelWrapper,
451
+ optionalLabel,
452
+ InfoText,
453
+ InputWrapper,
454
+ DropdownWrapper,
455
+ icon,
456
+ Caret,
457
+ Selector,
458
+ inputText,
459
+ draggableInputHandle
460
+ },
461
+
462
+ data() {
463
+ return {
464
+ selectedValue: null,
465
+ paddingLeft: this.isDraggable ? '30px' : '15px',
466
+ isDropdownOpen: false,
467
+ isActive: false,
468
+ textSearch: '',
469
+ hoveredIndex: 0,
470
+ hoveredValue: null,
471
+ isClickOutsideActive: false
472
+ }
473
+ },
474
+ mounted() {
475
+ this.selectedValue = this.value
476
+ document.addEventListener('click', this.clickOutside)
477
+ },
478
+ beforeDestroy() {
479
+ document.removeEventListener('click', this.clickOutside)
480
+ },
481
+ methods: {
482
+ focus() {
483
+ this.isActive = true
484
+ },
485
+ blur() {
486
+ this.isActive = false
487
+ },
488
+ toggleDropdown() {
489
+ this.isDropdownOpen = !this.isDropdownOpen
490
+ },
491
+ toggleCaretDropdown() {
492
+ this.isDropdownOpen = !this.isDropdownOpen
493
+ },
494
+ openDropdown() {
495
+ this.focus()
496
+ this.isDropdownOpen = true
497
+ },
498
+ closeDropdown() {
499
+ this.blur()
500
+ this.isDropdownOpen = false
501
+ },
502
+ optionSelected(e) {
503
+ this.selectedValue = e
504
+ this.closeDropdown()
505
+ this.blur()
506
+ this.$emit('input-change', e)
507
+ },
508
+ optionHovered(e) {
509
+ this.hoveredValue = e
510
+ },
511
+ mouseEnterHandler() {
512
+ if (this.hoverDropdown) {
513
+ this.focus()
514
+ this.isDropdownOpen = true
515
+ }
516
+ },
517
+ mouseLeaveHandler() {
518
+ if (this.hoverDropdown) {
519
+ this.blur()
520
+ }
521
+ },
522
+ optionLeave() {
523
+ if (this.dropdownAutoClose) {
524
+ this.isDropdownOpen = false
525
+ }
526
+ },
527
+ searchChange(value) {
528
+ this.textSearch = value
529
+ this.$emit('search-change', value)
530
+ this.$refs.dropdown.$children
531
+ .map((component) => component.$el)
532
+ .forEach((el) => {
533
+ if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
534
+ el.style.display = 'none'
535
+ } else {
536
+ el.style.display = 'inherit'
537
+ }
538
+ })
539
+ },
540
+ clickOutside(event) {
541
+ const dropdownRef = this.$refs.dropdown
542
+ // we need to prevent closing on selecting an option, because in the case of
543
+ // a disabled option, we don't want to close the dropdown
544
+ if (!this.isClickOutsideActive) return
545
+ if (
546
+ this.$refs.select.$el == event.target ||
547
+ this.$refs.select.$el.contains(event.target) ||
548
+ event.target.parentNode === dropdownRef.$el
549
+ ) {
550
+ return
551
+ } else {
552
+ this.closeDropdown()
553
+ }
554
+ },
555
+ onKeyDown(e) {
556
+ if (e.key == 'ArrowDown') {
557
+ this.onArrowPress(1)
558
+ } else if (e.key == 'ArrowUp') {
559
+ this.onArrowPress(-1)
560
+ } else if (e.key == 'Enter') {
561
+ const optionHoveredComponent =
562
+ this.$refs.dropdown.$children[
563
+ (this.hoveredIndex - 1 + this.optionLength) % this.optionLength
564
+ ]
565
+ this.optionSelected(optionHoveredComponent.$el.dataset.value)
566
+ }
567
+ },
568
+ onArrowPress(dir) {
569
+ let newHoveredElem
570
+ const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
571
+ `[data-value="${this.hoveredValue}"]`
572
+ )
573
+ if (currentHoveredElem) {
574
+ if (dir > 0) {
575
+ newHoveredElem = currentHoveredElem.nextElementSibling
576
+ } else {
577
+ newHoveredElem = currentHoveredElem.previousElementSibling
578
+ }
579
+ if (newHoveredElem) {
580
+ this.hoveredValue = newHoveredElem.getAttribute('data-value')
581
+ const topPos = newHoveredElem.offsetTop
582
+ this.$refs.dropdown.$el.scrollTop = topPos
583
+ }
584
+ }
585
+ },
586
+ clearSearch() {
587
+ this.textSearch = ''
588
+ }
589
+ },
590
+ computed: {
591
+ optionLength() {
592
+ if (this.isDropdownOpen) {
593
+ return this.$refs.dropdown.$el.childElementCount
594
+ }
595
+
596
+ return 0
597
+ },
598
+ isSearchBarVisible() {
599
+ return this.isSearchable && this.isDropdownOpen
600
+ }
601
+ },
602
+ watch: {
603
+ value(val) {
604
+ this.selectedValue = val
605
+ },
606
+ isDropdownOpen(val) {
607
+ this.$emit('is-dropdown-open', val)
608
+ if (val) {
609
+ setTimeout(() => {
610
+ this.isClickOutsideActive = true
611
+ }, 10)
612
+ } else {
613
+ setTimeout(() => {
614
+ this.isClickOutsideActive = false
615
+ }, 10)
616
+ }
617
+ if (val && this.isSearchable) {
618
+ this.$nextTick(() => {
619
+ if (this.$refs.searchInput) {
620
+ this.$refs.searchInput.$el.querySelector('input').focus()
621
+ }
622
+ })
623
+ }
624
+ }
625
+ }
626
+ }
627
+ </script>