@eturnity/eturnity_reusable_components 7.12.6-EPDM-7951.0 → 7.12.6-EPDM-10310

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 +642 -742
  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,742 +1,642 @@
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 v-if="isDraggable && !isSearchBarVisible" :height="selectHeight" />
52
- <inputText
53
- v-if="isSearchBarVisible"
54
- ref="searchInput"
55
- tabindex="0"
56
- inputHeight="34px"
57
- :noBorder="true"
58
- :fontSize="fontSize"
59
- backgroundColor="transparent"
60
- :fontColor="
61
- buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
62
- "
63
- :value="textSearch"
64
- @keydown.stop="onKeyDown"
65
- @input-change="searchChange"
66
- @click.stop
67
- />
68
- <selector v-else :selectWidth="selectWidth" :paddingLeft="paddingLeft">
69
- <slot name="selector" :selectedValue="selectedValue"></slot>
70
- </selector>
71
- <Caret @click.stop="toggleCaretDropdown">
72
- <icon
73
- v-if="isDropdownOpen"
74
- name="arrow_up"
75
- size="12px"
76
- :color="
77
- caretColor || colorMode == 'dark'
78
- ? 'white'
79
- : 'transparentBlack1'
80
- "
81
- />
82
- <icon
83
- v-else
84
- name="arrow_down"
85
- size="12px"
86
- :color="
87
- caretColor || colorMode == 'dark'
88
- ? 'white'
89
- : 'transparentBlack1'
90
- "
91
- />
92
- </Caret>
93
- </selectButton>
94
- <DropdownWrapper ref="dropdownWrapperRef">
95
- <Teleport to="#portal-target">
96
- <selectDropdown
97
- ref="dropdown"
98
- v-show="isSelectDropdownShown"
99
- :dropdownPosition="dropdownPosition"
100
- :hoveredIndex="hoveredIndex"
101
- :hoveredValue="hoveredValue"
102
- :isActive="isActive"
103
- :optionWidth="getOptionWidth"
104
- :hoveredBgColor="
105
- colorMode == 'dark' ? '#000000' : dropdownBgColor
106
- "
107
- :bgColor="
108
- dropdownBgColor || colorMode == 'dark' ? 'black' : 'white'
109
- "
110
- :fontColor="
111
- dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
112
- "
113
- :fontSize="fontSize"
114
- :selectedValue="selectedValue"
115
- @option-selected="optionSelected"
116
- @option-hovered="optionHovered"
117
- >
118
- <slot name="dropdown"></slot>
119
- </selectDropdown>
120
- </Teleport>
121
- </DropdownWrapper>
122
- </select-button-wrapper>
123
- </input-wrapper>
124
- </Container>
125
- </template>
126
-
127
- <script>
128
- //How to use it
129
- // <Select
130
- // hoverDropdown="true"
131
- // selectWidth="100%"
132
- // optionWidth="50%"
133
- // label="that is a label"
134
- // alignItems="vertical"
135
- // label-data-id="test-label-data-id"
136
- // data-id="test-data-id"
137
- // :hasSelectButtonPadding="false"
138
- // >
139
- // <template #selector="{selectedValue}">
140
- // value selected: {{selectedValue}}
141
- // </template>
142
- // <template #dropdown>
143
- // <Option value="1">value one</Option>
144
- // <Option value="2">value two</Option>
145
- // <Option value="3">value three</Option>
146
- // <Option value="4">value four</Option>
147
- // </template>
148
- // </Select>
149
-
150
- import { Teleport } from 'vue'
151
- import styled from 'vue3-styled-components'
152
- import InfoText from '../../infoText'
153
- import icon from '../../icon'
154
- import inputText from '../inputText'
155
- import draggableInputHandle from '../../draggableInputHandle'
156
-
157
- const CARET_WIDTH = '30px'
158
- const BORDER_WIDTH = '1px'
159
-
160
- const Caret = styled.div`
161
- display: flex;
162
- align-items: center;
163
- justify-content: center;
164
- width: ${CARET_WIDTH};
165
- min-width: ${CARET_WIDTH};
166
- height: 100%;
167
- align-items: stretch;
168
- cursor: pointer;
169
- margin-left: auto;
170
- `
171
-
172
- const Selector = styled('div', { selectWidth: String, paddingLeft: String })`
173
- width: ${(props) => `calc(${props.selectWidth} - (${CARET_WIDTH} + ${props.paddingLeft} + (${BORDER_WIDTH} * 2)))`};
174
- white-space: nowrap;
175
- text-overflow: ellipsis;
176
- overflow: hidden;
177
- `
178
-
179
- const labelAttrs = { fontSize: String, fontColor: String }
180
- const InputLabel = styled('div', labelAttrs)`
181
- color: ${(props) =>
182
- props.theme.colors[props.fontColor]
183
- ? props.theme.colors[props.fontColor]
184
- : props.fontColor};
185
- font-size: ${(props) => props.fontSize};
186
- font-weight: 700;
187
- `
188
- const optionalLabel = styled.span`
189
- font-weight: 300;
190
- `
191
- const inputProps = {
192
- selectWidth: String,
193
- optionWidth: String
194
- }
195
- const Container = styled('div', inputProps)`
196
- width: ${(props) => props.selectWidth};
197
- position: relative;
198
- display: inline-block;
199
- `
200
- const LabelWrapper = styled.div`
201
- display: inline-grid;
202
- grid-template-columns: auto auto;
203
- grid-gap: 12px;
204
- align-items: center;
205
- justify-content: start;
206
- `
207
-
208
- const SelectButtonWrapperAttrs = {
209
- disabled: Boolean
210
- }
211
- const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
212
- ${(props) => (props.disabled ? 'cursor: not-allowed' : 'cursor: pointer')};
213
- `
214
-
215
- const selectButtonAttrs = {
216
- bgColor: String,
217
- fontColor: String,
218
- hasError: Boolean,
219
- disabled: Boolean,
220
- selectHeight: String,
221
- selectWidth: String,
222
- height: String,
223
- selectMinHeight: String,
224
- hasNoPadding: Boolean,
225
- showBorder: Boolean,
226
- paddingLeft: String
227
- }
228
- const selectButton = styled('div', selectButtonAttrs)`
229
- position: relative;
230
- box-sizing: border-box;
231
- border-radius: 4px;
232
- max-width: ${(props) => (props.selectWidth ? props.selectWidth : '100%')};
233
- ${(props) => (props.hasNoPadding ? '' : `padding-left: ${props.paddingLeft}` )};
234
- text-align: left;
235
- min-height: ${(props) =>
236
- props.selectHeight
237
- ? props.selectHeight
238
- : props.selectMinHeight
239
- ? props.selectMinHeight
240
- : props.height
241
- ? props.height
242
- : '36px'};
243
- display: flex;
244
- align-items: center;
245
- height: ${(props) => props.selectHeight};
246
- ${({ showBorder, theme, hasError }) =>
247
- showBorder &&
248
- `
249
- border: ${BORDER_WIDTH} solid ${hasError ? theme.colors.red : theme.colors.grey4}
250
- `}
251
- background-color:${(props) =>
252
- props.disabled
253
- ? props.theme.colors.grey5
254
- : props.theme.colors[props.bgColor]
255
- ? props.theme.colors[props.bgColor]
256
- : props.bgColor};
257
- color: ${(props) =>
258
- props.theme.colors[props.fontColor]
259
- ? props.theme.colors[props.fontColor]
260
- : props.fontColor};
261
- ${(props) => (props.disabled ? 'pointer-events: none' : '')};
262
- overflow: hidden;
263
- & > .handle {
264
- border-right: ${(props) =>
265
- props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
266
- 1px solid;
267
- }
268
- `
269
- const selectDropdownAttrs = {
270
- hoveredBgColor: String,
271
- bgColor: String,
272
- fontColor: String,
273
- optionWidth: String,
274
- hoveredIndex: Number,
275
- fontSize: String,
276
- dropdownPosition: Object,
277
- hoveredValue: Number | String,
278
- selectedValue: Number | String
279
- }
280
- const selectDropdown = styled('div', selectDropdownAttrs)`
281
- box-sizing: border-box;
282
- z-index:${(props) => (props.isActive ? '2' : '99999')};
283
- position:absolute;
284
- top: ${(props) => props.dropdownPosition?.top}px;
285
- left: ${(props) => props.dropdownPosition?.left}px;
286
- border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
287
- border-radius:4px;
288
- display: flex;
289
- flex-direction: column;
290
- align-items: flex-start;
291
- padding: 0px;
292
- box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
293
- width: ${(props) => props.optionWidth};
294
- background-color:${(props) =>
295
- props.theme.colors[props.bgColor]
296
- ? props.theme.colors[props.bgColor]
297
- : props.bgColor};
298
- color:${(props) =>
299
- props.theme.colors[props.fontColor]
300
- ? props.theme.colors[props.fontColor]
301
- : props.fontColor};
302
- max-height:300px;
303
- overflow-y:auto;
304
- &>div[data-value="${(props) => props.hoveredValue}"]{
305
- background-color:${(props) =>
306
- props.theme.colors[props.hoveredBgColor]
307
- ? props.theme.colors[props.hoveredBgColor]
308
- : props.hoveredBgColor};
309
- }
310
- font-size: ${(props) => props.fontSize}
311
- `
312
- selectDropdown.emits = ['option-hovered', 'option-selected']
313
- const DropdownWrapper = styled('div')`
314
- position: relative;
315
- `
316
- const inputAttrs = { alignItems: String, hasLabel: Boolean }
317
- const InputWrapper = styled('div', inputAttrs)`
318
- position: relative;
319
- display: grid;
320
- align-items: center;
321
- gap: 8px;
322
- grid-template-columns: ${(props) =>
323
- props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
324
- `
325
-
326
- const DROPDOWN_HEIGHT_OFFSET = 4
327
- const DROPDOWN_TOP_OFFSET = 21
328
-
329
- export default {
330
- name: 'RCselect',
331
-
332
- props: {
333
- value: {
334
- required: false,
335
- default: null
336
- },
337
- fontSize: {
338
- required: false,
339
- default: '13px'
340
- },
341
- label: {
342
- required: false
343
- },
344
- labelOptional: {
345
- required: false,
346
- default: false
347
- },
348
- labelDataId: {
349
- required: false,
350
- default: ''
351
- },
352
- infoTextMessage: {
353
- required: false
354
- },
355
- selectWidth: {
356
- type: String,
357
- required: false,
358
- default: '100%'
359
- },
360
- selectHeight: {
361
- type: String,
362
- required: false,
363
- default: null
364
- },
365
- height: {
366
- required: false,
367
- default: null
368
- },
369
- selectMinHeight: {
370
- required: false,
371
- default: '36px'
372
- },
373
- optionWidth: {
374
- required: false,
375
- default: null
376
- },
377
- hoverDropdown: {
378
- required: false,
379
- default: false
380
- },
381
- dropdownAutoClose: {
382
- required: false,
383
- default: false
384
- },
385
- alignItems: {
386
- required: false,
387
- default: 'horizontal'
388
- },
389
- buttonBgColor: {
390
- required: false
391
- },
392
- buttonFontColor: {
393
- required: false
394
- },
395
- dropdownBgColor: {
396
- required: false,
397
- default: 'grey5'
398
- },
399
- dropdownFontColor: {
400
- required: false
401
- },
402
- caretColor: {
403
- required: false
404
- },
405
- labelFontColor: {
406
- required: false
407
- },
408
- colorMode: {
409
- required: false,
410
- default: 'light'
411
- },
412
- isSearchable: {
413
- required: false,
414
- default: true
415
- },
416
- hasError: {
417
- required: false,
418
- default: false
419
- },
420
- disabled: {
421
- required: false,
422
- default: false
423
- },
424
- isAutoSearch: {
425
- required: false,
426
- default: true
427
- },
428
- showBorder: {
429
- required: false,
430
- default: true
431
- },
432
- infoTextSize: {
433
- required: false,
434
- default: '14px'
435
- },
436
- dataId: {
437
- type: String,
438
- default: ''
439
- },
440
- hasSelectButtonPadding: {
441
- type: Boolean,
442
- default: true
443
- },
444
- isDraggable: {
445
- type: Boolean,
446
- default: false
447
- }
448
- },
449
-
450
- components: {
451
- selectButton,
452
- SelectButtonWrapper,
453
- selectDropdown,
454
- Container,
455
- InputLabel,
456
- LabelWrapper,
457
- optionalLabel,
458
- InfoText,
459
- InputWrapper,
460
- DropdownWrapper,
461
- icon,
462
- Caret,
463
- Selector,
464
- inputText,
465
- Teleport,
466
- draggableInputHandle
467
- },
468
-
469
- data() {
470
- return {
471
- selectedValue: null,
472
- paddingLeft: this.isDraggable ? '30px' : '15px',
473
- isDropdownOpen: false,
474
- isActive: false,
475
- textSearch: '',
476
- hoveredIndex: 0,
477
- isClickOutsideActive: false,
478
- dropdownPosition: {
479
- left: null,
480
- top: null
481
- },
482
- dropdownWidth: null,
483
- hoveredValue: null
484
- }
485
- },
486
- mounted() {
487
- this.observeDropdownHeight()
488
- this.observeSelectWidth()
489
- window.addEventListener('resize', this.handleSetDropdownOffet)
490
- },
491
- beforeMount() {
492
- this.selectedValue = this.value
493
- document.addEventListener('click', this.clickOutside)
494
- this.getDropdownPosition()
495
- window.removeEventListener('resize', this.handleSetDropdownOffet)
496
- if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
497
- if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
498
- },
499
- unmounted() {
500
- document.removeEventListener('click', this.clickOutside)
501
- },
502
- methods: {
503
- focus() {
504
- this.isActive = true
505
- },
506
- blur(e) {
507
- this.isActive = false
508
- this.$emit('blur', e)
509
- },
510
- toggleDropdown() {
511
- this.isDropdownOpen = !this.isDropdownOpen
512
- },
513
- toggleCaretDropdown() {
514
- this.isDropdownOpen = !this.isDropdownOpen
515
- },
516
- openDropdown() {
517
- this.focus()
518
- this.isDropdownOpen = true
519
- },
520
- closeDropdown() {
521
- this.blur()
522
- this.isDropdownOpen = false
523
- },
524
- clearSearch() {
525
- this.textSearch = ''
526
- },
527
- optionSelected(e) {
528
- this.selectedValue = e
529
- this.closeDropdown()
530
- this.blur()
531
- this.$emit('input-change', e)
532
- },
533
- optionHovered(e) {
534
- this.hoveredValue = e
535
- },
536
- mouseEnterHandler() {
537
- if (this.hoverDropdown) {
538
- this.focus()
539
- this.isDropdownOpen = true
540
- }
541
- },
542
- mouseLeaveHandler() {
543
- if (this.hoverDropdown) {
544
- this.blur()
545
- }
546
- },
547
- optionLeave() {
548
- if (this.dropdownAutoClose) {
549
- this.isDropdownOpen = false
550
- }
551
- },
552
- searchChange(value) {
553
- this.textSearch = value
554
- this.$emit('search-change', value)
555
- const dropdownChildren = [...this.$refs.dropdown.$el.children]
556
- dropdownChildren.forEach((el) => {
557
- if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
558
- el.style.display = 'none'
559
-
560
- return
561
- }
562
- el.style.display = 'inherit'
563
- })
564
- },
565
- clickOutside(event) {
566
- const dropdownRef = this.$refs.dropdown
567
- // we need to prevent closing on selecting an option, because in the case of
568
- // a disabled option, we don't want to close the dropdown
569
- if (!this.isClickOutsideActive) return
570
- if (
571
- this.$refs.select.$el == event.target ||
572
- this.$refs.select.$el.contains(event.target) ||
573
- event.target.id === 'more-button' ||
574
- event.target.parentNode === dropdownRef.$el
575
- ) {
576
- return
577
- } else {
578
- this.closeDropdown()
579
- }
580
- },
581
- onKeyDown(e) {
582
- if (e.key == 'ArrowDown') {
583
- this.onArrowPress(1)
584
- } else if (e.key == 'ArrowUp') {
585
- this.onArrowPress(-1)
586
- } else if (e.key == 'Enter') {
587
- const optionHoveredComponent = [...this.$refs.dropdown.$el.children][
588
- (this.hoveredIndex - 1 + this.optionLength) % this.optionLength
589
- ]
590
- this.optionSelected(optionHoveredComponent.$el.dataset.value)
591
- }
592
- },
593
- // If some part of the dropdown menu is outside viewport of the bottom of the screen,
594
- // we need to offset it and display it at the top of the select dropdown instead
595
- async getDropdownPosition() {
596
- if (
597
- !this.$refs.dropdownWrapperRef ||
598
- !this.$refs.select ||
599
- !this.$refs.dropdown
600
- ) {
601
- return
602
- }
603
- await this.$nextTick()
604
- const isDisplayedAtBottom = await this.generateDropdownPosition()
605
- await this.$nextTick()
606
- // If the dropdown menu is going to be displayed at the bottom,
607
- // we need reverify its position after a dom update (nextTick)
608
- if (isDisplayedAtBottom) this.generateDropdownPosition()
609
- },
610
- async generateDropdownPosition() {
611
- const isDropdownNotCompletelyVisible =
612
- await this.isBottomOfDropdownOutOfViewport()
613
- const dropdownWrapperEl = this.$refs.dropdownWrapperRef.$el
614
- const selectButtonHeight = this.$refs.select.$el.clientHeight
615
- const dropdownHeight = this.$refs.dropdown.$el.clientHeight
616
- const dropdownWrapperRelativeHeight =
617
- dropdownWrapperEl.getBoundingClientRect().top +
618
- window.scrollY +
619
- DROPDOWN_HEIGHT_OFFSET
620
-
621
- const top = isDropdownNotCompletelyVisible
622
- ? dropdownWrapperRelativeHeight
623
- : dropdownWrapperRelativeHeight -
624
- dropdownHeight -
625
- selectButtonHeight -
626
- DROPDOWN_TOP_OFFSET
627
- const left = this.dropdownPosition.left
628
- ? this.dropdownPosition.left
629
- : dropdownWrapperEl.getBoundingClientRect().left + window.scrollX
630
-
631
- this.dropdownPosition = { left: Math.floor(left), top: Math.floor(top) }
632
-
633
- return isDropdownNotCompletelyVisible
634
- },
635
- async isBottomOfDropdownOutOfViewport() {
636
- if (!this.$refs.dropdown) {
637
- return false
638
- }
639
- await this.$nextTick()
640
- const rect = this.$refs.dropdown.$el.getBoundingClientRect()
641
- const windowHeight =
642
- window.innerHeight || document.documentElement.clientHeight
643
-
644
- // using Math.floor because the offsets may contain decimals we are not going to consider here
645
- return Math.floor(rect.top) + Math.floor(rect.height) <= windowHeight
646
- },
647
- observeDropdownHeight() {
648
- if (!this.$refs.dropdown) return
649
- this.dropdownResizeObserver = new ResizeObserver(() => {
650
- this.$nextTick(() => this.getDropdownPosition())
651
- })
652
- this.dropdownResizeObserver.observe(this.$refs.dropdown.$el)
653
- },
654
- handleSetDropdownOffet() {
655
- if (!this.$refs.select) return
656
- this.dropdownPosition.left = Math.floor(
657
- this.$refs.select.$el.getBoundingClientRect().left
658
- )
659
- this.getDropdownWidth()
660
- },
661
- observeSelectWidth() {
662
- if (!this.$refs.select) return
663
- this.selectResizeObserver = new ResizeObserver(() =>
664
- this.$nextTick(() => this.getDropdownWidth())
665
- )
666
- this.selectResizeObserver.observe(this.$refs.dropdown.$el)
667
- },
668
- async getDropdownWidth() {
669
- if (!this.$refs.select) return
670
- await this.$nextTick()
671
- this.dropdownWidth = `${this.$refs.select.$el.clientWidth}px`
672
- },
673
- onArrowPress(dir) {
674
- let newHoveredElem
675
- const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
676
- `[data-value="${this.hoveredValue}"]`
677
- )
678
- if (currentHoveredElem) {
679
- if (dir > 0) {
680
- newHoveredElem = currentHoveredElem.nextElementSibling
681
- } else {
682
- newHoveredElem = currentHoveredElem.previousElementSibling
683
- }
684
- if (newHoveredElem) {
685
- this.hoveredValue = newHoveredElem.getAttribute('data-value')
686
- const topPos = newHoveredElem.offsetTop
687
- this.$refs.dropdown.$el.scrollTop = topPos
688
- }
689
- }
690
- },
691
- clearSearch() {
692
- this.textSearch = ''
693
- }
694
- },
695
- computed: {
696
- optionLength() {
697
- if (this.isDropdownOpen) {
698
- return this.$refs.dropdown.$el.childElementCount
699
- }
700
-
701
- return 0
702
- },
703
- isSearchBarVisible() {
704
- return this.isSearchable && this.optionLength >= 5 && this.isDropdownOpen
705
- },
706
- getOptionWidth() {
707
- if (this.optionWidth) return this.optionWidth
708
-
709
- return this.dropdownWidth
710
- },
711
- isSelectDropdownShown() {
712
- return this.isSearchable && this.isDropdownOpen && this.dropdownPosition.left !== null
713
- }
714
- },
715
- watch: {
716
- value(val) {
717
- this.selectedValue = val
718
- },
719
- async isDropdownOpen(val) {
720
- if (val) {
721
- setTimeout(() => {
722
- this.isClickOutsideActive = true
723
- }, 10)
724
- await this.$nextTick()
725
- this.handleSetDropdownOffet()
726
- } else {
727
- this.dropdownPosition.left = null
728
- setTimeout(() => {
729
- this.isClickOutsideActive = false
730
- }, 10)
731
- }
732
- if (val && this.isSearchable) {
733
- this.$nextTick(() => {
734
- if (this.$refs.searchInput) {
735
- this.$refs.searchInput.$el.querySelector('input').focus()
736
- }
737
- })
738
- }
739
- }
740
- }
741
- }
742
- </script>
1
+ <template>
2
+ <Container
3
+ ref="container"
4
+ :selectWidth="selectWidth"
5
+ @mouseenter="mouseEnterHandler"
6
+ @mouseleave="mouseLeaveHandler"
7
+ >
8
+ <input-wrapper
9
+ :hasLabel="!!label && label.length > 0"
10
+ :alignItems="alignItems"
11
+ >
12
+ <label-wrapper v-if="label" :data-id="labelDataId">
13
+ <input-label
14
+ :fontColor="
15
+ labelFontColor || colorMode == 'dark' ? 'white' : 'eturnityGrey'
16
+ "
17
+ :fontSize="fontSize"
18
+ >{{ label }}
19
+ <optionalLabel v-if="labelOptional">
20
+ ({{ $gettext('Optional') }})</optionalLabel
21
+ >
22
+ </input-label>
23
+ <info-text
24
+ v-if="infoTextMessage"
25
+ :text="infoTextMessage"
26
+ :size="infoTextSize"
27
+ />
28
+ </label-wrapper>
29
+ <select-button-wrapper :disabled="disabled">
30
+ <selectButton
31
+ ref="select"
32
+ @click="toggleDropdown"
33
+ :selectHeight="selectHeight"
34
+ :height="height"
35
+ :selectMinHeight="selectMinHeight"
36
+ :bgColor="
37
+ buttonBgColor || colorMode == 'dark' ? 'transparentBlack1' : 'white'
38
+ "
39
+ :fontColor="
40
+ buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
41
+ "
42
+ :hasError="hasError"
43
+ :isSearchBarVisible="isSearchBarVisible"
44
+ :disabled="disabled"
45
+ @keydown.native="onKeyDown"
46
+ :showBorder="showBorder"
47
+ :data-id="dataId"
48
+ :paddingLeft="paddingLeft"
49
+ >
50
+ <draggableInputHandle
51
+ v-if="isDraggable && !isSearchBarVisible"
52
+ :height="selectHeight"
53
+ />
54
+ <inputText
55
+ v-if="isSearchBarVisible"
56
+ ref="searchInput"
57
+ tabindex="0"
58
+ inputHeight="34px"
59
+ :noBorder="true"
60
+ :fontSize="fontSize"
61
+ backgroundColor="transparent"
62
+ :fontColor="
63
+ buttonFontColor || colorMode == 'dark' ? 'white' : 'black'
64
+ "
65
+ :value="textSearch"
66
+ @keydown.stop="onKeyDown"
67
+ @input-change="searchChange"
68
+ @click.native.stop
69
+ />
70
+ <selector
71
+ v-else
72
+ :showBorder="showBorder"
73
+ :selectorAvailableWidth="selectorAvailableWidth"
74
+ :selectWidth="selectWidth"
75
+ :paddingLeft="paddingLeft"
76
+ >
77
+ <slot name="selector" :selectedValue="selectedValue"></slot>
78
+ </selector>
79
+ <Caret @click.stop="toggleCaretDropdown">
80
+ <icon
81
+ v-if="isDropdownOpen"
82
+ name="arrow_up"
83
+ size="12px"
84
+ :color="
85
+ caretColor || colorMode == 'dark'
86
+ ? 'white'
87
+ : 'transparentBlack1'
88
+ "
89
+ />
90
+ <icon
91
+ v-else
92
+ name="arrow_down"
93
+ size="12px"
94
+ :color="
95
+ caretColor || colorMode == 'dark'
96
+ ? 'white'
97
+ : 'transparentBlack1'
98
+ "
99
+ />
100
+ </Caret>
101
+ </selectButton>
102
+ <DropdownWrapper>
103
+ <selectDropdown
104
+ ref="dropdown"
105
+ v-show="isDropdownOpen"
106
+ :hoveredIndex="hoveredIndex"
107
+ :hoveredValue="hoveredValue"
108
+ :isActive="isActive"
109
+ :optionWidth="optionWidth"
110
+ :hoveredBgColor="colorMode == 'dark' ? '#000000' : dropdownBgColor"
111
+ :bgColor="colorMode == 'dark' ? 'black' : dropdownBgColor"
112
+ :fontColor="
113
+ dropdownFontColor || colorMode == 'dark' ? 'white' : 'black'
114
+ "
115
+ :selectedValue="selectedValue"
116
+ @option-selected="optionSelected"
117
+ @option-hovered="optionHovered"
118
+ @mouseleave="optionLeave"
119
+ >
120
+ <slot name="dropdown"></slot>
121
+ </selectDropdown>
122
+ </DropdownWrapper>
123
+ </select-button-wrapper>
124
+ </input-wrapper>
125
+ </Container>
126
+ </template>
127
+
128
+ <script>
129
+ //How to use it
130
+ // <Select
131
+ // hoverDropdown="true"
132
+ // selectWidth="100%"
133
+ // optionWidth="50%"
134
+ // label="that is a label"
135
+ // alignItems="vertical"
136
+ // label-data-id="test-label0data-id"
137
+ // data-id="test-data-id"
138
+ // >
139
+ // <template #selector="{selectedValue}">
140
+ // value selected: {{selectedValue}}
141
+ // </template>
142
+ // <template #dropdown>
143
+ // <Option value="1">value one</Option>
144
+ // <Option value="2">value two</Option>
145
+ // <Option value="3">value three</Option>
146
+ // <Option value="4">value four</Option>
147
+ // </template>
148
+ // </Select>
149
+
150
+ import styled from 'vue-styled-components'
151
+ import InfoText from '../../infoText'
152
+ import icon from '../../icon'
153
+ import inputText from '../inputText'
154
+ import draggableInputHandle from '../../draggableInputHandle'
155
+
156
+ const CARET_WIDTH = '30px'
157
+ const BORDER_WIDTH = '1px'
158
+
159
+ const Caret = styled.div`
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ width: ${CARET_WIDTH};
164
+ min-width: ${CARET_WIDTH};
165
+ height: 100%;
166
+ align-items: stretch;
167
+ cursor: pointer;
168
+ margin-left: auto;
169
+ `
170
+
171
+ const selectorProps = {
172
+ selectWidth: String,
173
+ paddingLeft: String,
174
+ selectorAvailableWidth: String,
175
+ showBorder: Boolean
176
+ }
177
+ const Selector = styled('div', selectorProps)`
178
+ width: ${(props) =>
179
+ `calc(${props.selectorAvailableWidth} -
180
+ (
181
+ ${CARET_WIDTH} +
182
+ ${props.paddingLeft}
183
+ ${props.showBorder ? `+ (${BORDER_WIDTH} * 2)` : ''}
184
+ )
185
+ )`};
186
+ white-space: nowrap;
187
+ text-overflow: ellipsis;
188
+ overflow: hidden;
189
+ `
190
+
191
+ const labelAttrs = { fontSize: String, fontColor: String }
192
+ const InputLabel = styled('div', labelAttrs)`
193
+ color: ${(props) =>
194
+ props.theme.colors[props.fontColor]
195
+ ? props.theme.colors[props.fontColor]
196
+ : props.fontColor};
197
+ font-size: ${(props) => props.fontSize};
198
+ font-weight: 700;
199
+ `
200
+ const optionalLabel = styled.span`
201
+ font-weight: 300;
202
+ `
203
+ const inputProps = { selectWidth: String, optionWidth: String }
204
+ const Container = styled('div', inputProps)`
205
+ width: ${(props) => props.selectWidth};
206
+ position: relative;
207
+ display: inline-block;
208
+ `
209
+ const LabelWrapper = styled.div`
210
+ display: inline-grid;
211
+ grid-template-columns: auto auto;
212
+ grid-gap: 12px;
213
+ align-items: center;
214
+ justify-content: start;
215
+ `
216
+
217
+ const SelectButtonWrapperAttrs = {
218
+ disabled: Boolean
219
+ }
220
+ const SelectButtonWrapper = styled('div', SelectButtonWrapperAttrs)`
221
+ ${(props) => (props.disabled ? 'cursor: not-allowed' : 'cursor: pointer')};
222
+ `
223
+
224
+ const selectButtonAttrs = {
225
+ bgColor: String,
226
+ fontColor: String,
227
+ hasError: Boolean,
228
+ disabled: Boolean,
229
+ selectHeight: String,
230
+ height: String,
231
+ selectMinHeight: String,
232
+ isSearchBarVisible: 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
+ ${(props) =>
241
+ props.isSearchBarVisible ? '' : `padding-left: ${props.paddingLeft}`};
242
+ text-align: left;
243
+ min-height: ${(props) =>
244
+ props.selectHeight
245
+ ? props.selectHeight
246
+ : props.selectMinHeight
247
+ ? props.selectMinHeight
248
+ : props.height
249
+ ? props.height
250
+ : '36px'};
251
+ display: flex;
252
+ align-items: center;
253
+ max-height: ${(props) => props.selectHeight};
254
+ ${({ showBorder, theme, hasError }) =>
255
+ showBorder &&
256
+ `
257
+ border: ${BORDER_WIDTH} solid ${
258
+ hasError ? theme.colors.red : theme.colors.grey4
259
+ }
260
+ `}
261
+ background-color:${(props) =>
262
+ props.disabled
263
+ ? props.theme.colors.grey5
264
+ : props.theme.colors[props.bgColor]
265
+ ? props.theme.colors[props.bgColor]
266
+ : props.bgColor};
267
+ color: ${(props) =>
268
+ props.theme.colors[props.fontColor]
269
+ ? props.theme.colors[props.fontColor]
270
+ : props.fontColor};
271
+ ${(props) => (props.disabled ? 'pointer-events: none' : '')};
272
+ overflow: hidden;
273
+ & > .handle {
274
+ border-right: ${(props) =>
275
+ props.hasError ? props.theme.colors.red : props.theme.colors.grey4}
276
+ 1px solid;
277
+ }
278
+ `
279
+ const selectDropdownAttrs = {
280
+ hoveredBgColor: String,
281
+ bgColor: String,
282
+ fontColor: String,
283
+ optionWidth: String,
284
+ hoveredIndex: Number,
285
+ hoveredValue: Number | String,
286
+ selectedValue: Number | String
287
+ }
288
+ const selectDropdown = styled('div', selectDropdownAttrs)`
289
+ box-sizing: border-box;
290
+ z-index: ${(props) => (props.isActive ? '2' : '1')};
291
+ position: absolute;
292
+ top: 5px;
293
+ border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
294
+ border-radius: 4px;
295
+ display: flex;
296
+ flex-direction: column;
297
+ align-items: flex-start;
298
+ padding: 0px;
299
+ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
300
+ width: ${(props) => (props.optionWidth ? props.optionWidth : '100%')};
301
+ background-color: ${(props) =>
302
+ props.theme.colors[props.bgColor]
303
+ ? props.theme.colors[props.bgColor]
304
+ : props.bgColor};
305
+ color: ${(props) =>
306
+ props.theme.colors[props.fontColor]
307
+ ? props.theme.colors[props.fontColor]
308
+ : props.fontColor};
309
+ max-height: 300px;
310
+ overflow-y: auto;
311
+ & > div[data-value='${(props) => props.hoveredValue}'] {
312
+ background-color: ${(props) =>
313
+ props.theme.colors[props.hoveredBgColor]
314
+ ? props.theme.colors[props.hoveredBgColor]
315
+ : props.hoveredBgColor};
316
+ }
317
+ `
318
+ const DropdownWrapper = styled('div')`
319
+ position: relative;
320
+ `
321
+ const inputAttrs = { alignItems: String, hasLabel: Boolean }
322
+ const InputWrapper = styled('div', inputAttrs)`
323
+ position: relative;
324
+ display: grid;
325
+ align-items: center;
326
+ gap: 8px;
327
+ grid-template-columns: ${(props) =>
328
+ props.alignItems === 'vertical' || !props.hasLabel ? '1fr' : 'auto 1fr'};
329
+ `
330
+ export default {
331
+ name: 'RCselect',
332
+
333
+ props: {
334
+ value: {
335
+ required: false,
336
+ default: null
337
+ },
338
+ fontSize: {
339
+ required: false,
340
+ default: '13px'
341
+ },
342
+ label: {
343
+ required: false
344
+ },
345
+ labelOptional: {
346
+ required: false,
347
+ default: false
348
+ },
349
+ labelDataId: {
350
+ required: false,
351
+ default: ''
352
+ },
353
+ infoTextMessage: {
354
+ required: false
355
+ },
356
+ selectWidth: {
357
+ type: String,
358
+ required: false,
359
+ default: '100%'
360
+ },
361
+ selectHeight: {
362
+ type: String,
363
+ required: false,
364
+ default: null
365
+ },
366
+ height: {
367
+ required: false,
368
+ default: null
369
+ },
370
+ selectMinHeight: {
371
+ required: false,
372
+ default: '36px'
373
+ },
374
+ optionWidth: {
375
+ required: false,
376
+ default: null
377
+ },
378
+ hoverDropdown: {
379
+ required: false,
380
+ default: false
381
+ },
382
+ dropdownAutoClose: {
383
+ required: false,
384
+ default: false
385
+ },
386
+ alignItems: {
387
+ required: false,
388
+ default: 'horizontal'
389
+ },
390
+ buttonBgColor: {
391
+ required: false
392
+ },
393
+ buttonFontColor: {
394
+ required: false
395
+ },
396
+ dropdownBgColor: {
397
+ required: false,
398
+ default: 'grey5'
399
+ },
400
+ dropdownFontColor: {
401
+ required: false
402
+ },
403
+ caretColor: {
404
+ required: false
405
+ },
406
+ labelFontColor: {
407
+ required: false
408
+ },
409
+ colorMode: {
410
+ required: false,
411
+ default: 'light'
412
+ },
413
+ isSearchable: {
414
+ required: false,
415
+ default: true
416
+ },
417
+ hasError: {
418
+ required: false,
419
+ default: false
420
+ },
421
+ disabled: {
422
+ required: false,
423
+ default: false
424
+ },
425
+ isAutoSearch: {
426
+ required: false,
427
+ default: true
428
+ },
429
+ showBorder: {
430
+ required: false,
431
+ default: true
432
+ },
433
+ infoTextSize: {
434
+ required: false,
435
+ default: '14px'
436
+ },
437
+ dataId: {
438
+ type: String,
439
+ default: ''
440
+ },
441
+ isDraggable: {
442
+ type: Boolean,
443
+ default: false
444
+ }
445
+ },
446
+
447
+ components: {
448
+ selectButton,
449
+ SelectButtonWrapper,
450
+ selectDropdown,
451
+ Container,
452
+ InputLabel,
453
+ LabelWrapper,
454
+ optionalLabel,
455
+ InfoText,
456
+ InputWrapper,
457
+ DropdownWrapper,
458
+ icon,
459
+ Caret,
460
+ Selector,
461
+ inputText,
462
+ draggableInputHandle
463
+ },
464
+
465
+ data() {
466
+ return {
467
+ selectedValue: null,
468
+ paddingLeft: this.isDraggable ? '30px' : '15px',
469
+ isDropdownOpen: false,
470
+ isActive: false,
471
+ textSearch: '',
472
+ hoveredIndex: 0,
473
+ hoveredValue: null,
474
+ isClickOutsideActive: false,
475
+ selectorAvailableWidth: '100%'
476
+ }
477
+ },
478
+ mounted() {
479
+ this.selectedValue = this.value
480
+ document.addEventListener('click', this.clickOutside)
481
+ this.updateSelectorAvailableWidth()
482
+ },
483
+ beforeDestroy() {
484
+ document.removeEventListener('click', this.clickOutside)
485
+ },
486
+ methods: {
487
+ focus() {
488
+ this.isActive = true
489
+ },
490
+ blur() {
491
+ this.isActive = false
492
+ },
493
+ toggleDropdown() {
494
+ this.isDropdownOpen = !this.isDropdownOpen
495
+ },
496
+ toggleCaretDropdown() {
497
+ this.isDropdownOpen = !this.isDropdownOpen
498
+ },
499
+ openDropdown() {
500
+ this.focus()
501
+ this.isDropdownOpen = true
502
+ },
503
+ closeDropdown() {
504
+ this.blur()
505
+ this.isDropdownOpen = false
506
+ },
507
+ optionSelected(e) {
508
+ this.selectedValue = e
509
+ this.closeDropdown()
510
+ this.blur()
511
+ this.$emit('input-change', e)
512
+ },
513
+ optionHovered(e) {
514
+ this.hoveredValue = e
515
+ },
516
+ mouseEnterHandler() {
517
+ if (this.hoverDropdown) {
518
+ this.focus()
519
+ this.isDropdownOpen = true
520
+ }
521
+ },
522
+ mouseLeaveHandler() {
523
+ if (this.hoverDropdown) {
524
+ this.blur()
525
+ }
526
+ },
527
+ optionLeave() {
528
+ if (this.dropdownAutoClose) {
529
+ this.isDropdownOpen = false
530
+ }
531
+ },
532
+ searchChange(value) {
533
+ this.textSearch = value
534
+ this.$emit('search-change', value)
535
+ this.$refs.dropdown.$children
536
+ .map((component) => component.$el)
537
+ .forEach((el) => {
538
+ if (!el.textContent.toLowerCase().includes(value.toLowerCase())) {
539
+ el.style.display = 'none'
540
+ } else {
541
+ el.style.display = 'inherit'
542
+ }
543
+ })
544
+ },
545
+ clickOutside(event) {
546
+ const dropdownRef = this.$refs.dropdown
547
+ // we need to prevent closing on selecting an option, because in the case of
548
+ // a disabled option, we don't want to close the dropdown
549
+ if (!this.isClickOutsideActive) return
550
+ if (
551
+ this.$refs.select.$el == event.target ||
552
+ this.$refs.select.$el.contains(event.target) ||
553
+ event.target.parentNode === dropdownRef.$el
554
+ ) {
555
+ return
556
+ } else {
557
+ this.closeDropdown()
558
+ }
559
+ },
560
+ onKeyDown(e) {
561
+ if (e.key == 'ArrowDown') {
562
+ this.onArrowPress(1)
563
+ } else if (e.key == 'ArrowUp') {
564
+ this.onArrowPress(-1)
565
+ } else if (e.key == 'Enter') {
566
+ const optionHoveredComponent =
567
+ this.$refs.dropdown.$children[
568
+ (this.hoveredIndex - 1 + this.optionLength) % this.optionLength
569
+ ]
570
+ this.optionSelected(optionHoveredComponent.$el.dataset.value)
571
+ }
572
+ },
573
+ onArrowPress(dir) {
574
+ let newHoveredElem
575
+ const currentHoveredElem = this.$refs.dropdown.$el.querySelector(
576
+ `[data-value="${this.hoveredValue}"]`
577
+ )
578
+ if (currentHoveredElem) {
579
+ if (dir > 0) {
580
+ newHoveredElem = currentHoveredElem.nextElementSibling
581
+ } else {
582
+ newHoveredElem = currentHoveredElem.previousElementSibling
583
+ }
584
+ if (newHoveredElem) {
585
+ this.hoveredValue = newHoveredElem.getAttribute('data-value')
586
+ const topPos = newHoveredElem.offsetTop
587
+ this.$refs.dropdown.$el.scrollTop = topPos
588
+ }
589
+ }
590
+ },
591
+ clearSearch() {
592
+ this.textSearch = ''
593
+ },
594
+ updateSelectorAvailableWidth() {
595
+ this.selectorAvailableWidth = this.$refs.container.$el.clientWidth + 'px'
596
+ }
597
+ },
598
+ computed: {
599
+ optionLength() {
600
+ if (this.isDropdownOpen) {
601
+ return this.$refs.dropdown.$el.childElementCount
602
+ }
603
+
604
+ return 0
605
+ },
606
+ isSearchBarVisible() {
607
+ return this.isSearchable && this.isDropdownOpen
608
+ }
609
+ },
610
+ watch: {
611
+ value(val) {
612
+ this.selectedValue = val
613
+ },
614
+ isDropdownOpen(val) {
615
+ this.$emit('is-dropdown-open', val)
616
+ if (val) {
617
+ setTimeout(() => {
618
+ this.isClickOutsideActive = true
619
+ }, 10)
620
+ } else {
621
+ setTimeout(() => {
622
+ this.isClickOutsideActive = false
623
+ }, 10)
624
+ }
625
+ if (val && this.isSearchable) {
626
+ this.$nextTick(() => {
627
+ if (this.$refs.searchInput) {
628
+ this.$refs.searchInput.$el.querySelector('input').focus()
629
+ }
630
+ })
631
+ }
632
+ },
633
+ '$refs.container': {
634
+ deep: true,
635
+ handler() {
636
+ console.log('test')
637
+ this.updateSelectorAvailableWidth()
638
+ }
639
+ }
640
+ }
641
+ }
642
+ </script>