@eturnity/eturnity_reusable_components 7.45.5-EPDM-11692.0 → 7.45.5-EPDM-11313-EPDM-11314.2

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