@dhis2-ui/select 10.16.2 → 10.16.3

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 (274) hide show
  1. package/package.json +17 -16
  2. package/src/index.js +9 -0
  3. package/src/locales/ar/translations.json +7 -0
  4. package/src/locales/ar_IQ/translations.json +7 -0
  5. package/src/locales/ckb/translations.json +7 -0
  6. package/src/locales/cs/translations.json +7 -0
  7. package/src/locales/da/translations.json +7 -0
  8. package/src/locales/en/translations.json +11 -0
  9. package/src/locales/en_US/translations.json +9 -0
  10. package/src/locales/es/translations.json +7 -0
  11. package/src/locales/es_419/translations.json +7 -0
  12. package/src/locales/fr/translations.json +7 -0
  13. package/src/locales/hi_IN/translations.json +7 -0
  14. package/src/locales/id/translations.json +7 -0
  15. package/src/locales/index.js +80 -0
  16. package/src/locales/km/translations.json +7 -0
  17. package/src/locales/lo/translations.json +7 -0
  18. package/src/locales/my/translations.json +7 -0
  19. package/src/locales/nb/translations.json +7 -0
  20. package/src/locales/nl/translations.json +7 -0
  21. package/src/locales/prs/translations.json +7 -0
  22. package/src/locales/ps/translations.json +7 -0
  23. package/src/locales/pt/translations.json +7 -0
  24. package/src/locales/pt_BR/translations.json +7 -0
  25. package/src/locales/ru/translations.json +7 -0
  26. package/src/locales/sv/translations.json +7 -0
  27. package/src/locales/tet/translations.json +7 -0
  28. package/src/locales/tg/translations.json +7 -0
  29. package/src/locales/uk/translations.json +7 -0
  30. package/src/locales/ur/translations.json +7 -0
  31. package/src/locales/uz_Latn/translations.json +7 -0
  32. package/src/locales/uz_UZ_Cyrl/translations.json +7 -0
  33. package/src/locales/uz_UZ_Latn/translations.json +7 -0
  34. package/src/locales/vi/translations.json +7 -0
  35. package/src/locales/zh/translations.json +9 -0
  36. package/src/locales/zh_CN/translations.json +7 -0
  37. package/src/multi-select/__tests__/multi-select.test.js +23 -0
  38. package/src/multi-select/__tests__/selection-list.test.js +102 -0
  39. package/src/multi-select/features/accepts_blur_cb/index.js +14 -0
  40. package/src/multi-select/features/accepts_blur_cb.feature +8 -0
  41. package/src/multi-select/features/accepts_focus_cb/index.js +14 -0
  42. package/src/multi-select/features/accepts_focus_cb.feature +6 -0
  43. package/src/multi-select/features/accepts_initial_focus/index.js +5 -0
  44. package/src/multi-select/features/accepts_initial_focus.feature +5 -0
  45. package/src/multi-select/features/accepts_loading/index.js +22 -0
  46. package/src/multi-select/features/accepts_loading.feature +14 -0
  47. package/src/multi-select/features/accepts_max_height/index.js +31 -0
  48. package/src/multi-select/features/accepts_max_height.feature +11 -0
  49. package/src/multi-select/features/accepts_placeholder/index.js +25 -0
  50. package/src/multi-select/features/accepts_placeholder.feature +10 -0
  51. package/src/multi-select/features/accepts_prefix/index.js +19 -0
  52. package/src/multi-select/features/accepts_prefix.feature +10 -0
  53. package/src/multi-select/features/allows_invalid_options/index.js +27 -0
  54. package/src/multi-select/features/allows_invalid_options.feature +12 -0
  55. package/src/multi-select/features/allows_selecting/index.js +81 -0
  56. package/src/multi-select/features/allows_selecting.feature +44 -0
  57. package/src/multi-select/features/can_be_cleared/index.js +22 -0
  58. package/src/multi-select/features/can_be_cleared.feature +6 -0
  59. package/src/multi-select/features/can_be_disabled/index.js +36 -0
  60. package/src/multi-select/features/can_be_disabled.feature +32 -0
  61. package/src/multi-select/features/can_be_empty/index.js +28 -0
  62. package/src/multi-select/features/can_be_empty.feature +16 -0
  63. package/src/multi-select/features/can_be_filtered/index.js +23 -0
  64. package/src/multi-select/features/can_be_filtered.feature +14 -0
  65. package/src/multi-select/features/can_be_opened_and_closed/index.js +32 -0
  66. package/src/multi-select/features/can_be_opened_and_closed.feature +41 -0
  67. package/src/multi-select/features/common/index.js +49 -0
  68. package/src/multi-select/features/duplicate_option_values/index.js +21 -0
  69. package/src/multi-select/features/duplicate_option_values.feature +7 -0
  70. package/src/multi-select/features/menu_width_matches_input/index.js +53 -0
  71. package/src/multi-select/features/menu_width_matches_input.feature +11 -0
  72. package/src/multi-select/features/position/index.js +160 -0
  73. package/src/multi-select/features/position.feature +46 -0
  74. package/src/multi-select/features/shows_selections/index.js +18 -0
  75. package/src/multi-select/features/shows_selections.feature +9 -0
  76. package/src/multi-select/filterable-menu.js +43 -0
  77. package/src/multi-select/index.js +1 -0
  78. package/src/multi-select/input.js +129 -0
  79. package/src/multi-select/menu.js +91 -0
  80. package/src/multi-select/multi-select.e2e.stories.js +407 -0
  81. package/src/multi-select/multi-select.js +148 -0
  82. package/src/multi-select/multi-select.prod.stories.js +408 -0
  83. package/src/multi-select/selection-list.js +79 -0
  84. package/src/multi-select-field/__tests__/multi-select-field.test.js +29 -0
  85. package/src/multi-select-field/features/accepts_help_text/index.js +9 -0
  86. package/src/multi-select-field/features/accepts_help_text.feature +5 -0
  87. package/src/multi-select-field/features/accepts_label/index.js +9 -0
  88. package/src/multi-select-field/features/accepts_label.feature +5 -0
  89. package/src/multi-select-field/features/accepts_validation_text/index.js +9 -0
  90. package/src/multi-select-field/features/accepts_validation_text.feature +5 -0
  91. package/src/multi-select-field/features/can_be_required/index.js +11 -0
  92. package/src/multi-select-field/features/can_be_required.feature +5 -0
  93. package/src/multi-select-field/features/has_default_clear_text/index.js +16 -0
  94. package/src/multi-select-field/features/has_default_clear_text.feature +6 -0
  95. package/src/multi-select-field/features/has_default_empty_text/index.js +13 -0
  96. package/src/multi-select-field/features/has_default_empty_text.feature +6 -0
  97. package/src/multi-select-field/features/has_default_filter_nomatch_text/index.js +17 -0
  98. package/src/multi-select-field/features/has_default_filter_nomatch_text.feature +7 -0
  99. package/src/multi-select-field/features/has_default_filter_placeholder/index.js +15 -0
  100. package/src/multi-select-field/features/has_default_filter_placeholder.feature +6 -0
  101. package/src/multi-select-field/features/has_default_loading_text/index.js +13 -0
  102. package/src/multi-select-field/features/has_default_loading_text.feature +6 -0
  103. package/src/multi-select-field/index.js +1 -0
  104. package/src/multi-select-field/multi-select-field.e2e.stories.js +45 -0
  105. package/src/multi-select-field/multi-select-field.js +178 -0
  106. package/src/multi-select-field/multi-select-field.prod.stories.js +137 -0
  107. package/src/multi-select-option/index.js +1 -0
  108. package/src/multi-select-option/multi-select-option.js +70 -0
  109. package/src/select/__tests__/select.test.js +31 -0
  110. package/src/select/debounce/debounce.js +30 -0
  111. package/src/select/debounce/debounce.spec.js +35 -0
  112. package/src/select/empty.js +28 -0
  113. package/src/select/filter-input.js +42 -0
  114. package/src/select/filterable-menu.js +106 -0
  115. package/src/select/index.js +14 -0
  116. package/src/select/input-clear-button.js +66 -0
  117. package/src/select/input-placeholder.js +30 -0
  118. package/src/select/input-prefix.js +32 -0
  119. package/src/select/input-wrapper.js +114 -0
  120. package/src/select/loading.js +33 -0
  121. package/src/select/menu-wrapper.js +52 -0
  122. package/src/select/no-match.js +28 -0
  123. package/src/select/option-helpers.js +34 -0
  124. package/src/select/select.js +256 -0
  125. package/src/simple-single-select/__stories__/DefaultPosition.js +37 -0
  126. package/src/simple-single-select/__stories__/Dense.js +17 -0
  127. package/src/simple-single-select/__stories__/Empty.js +15 -0
  128. package/src/simple-single-select/__stories__/EmptyWithEmptyNode.js +27 -0
  129. package/src/simple-single-select/__stories__/EmptyWithEmptyText.js +16 -0
  130. package/src/simple-single-select/__stories__/FlippedPosition.js +36 -0
  131. package/src/simple-single-select/__stories__/InfiniteLoading.js +65 -0
  132. package/src/simple-single-select/__stories__/Loading.js +15 -0
  133. package/src/simple-single-select/__stories__/ShiftedIntoView.js +35 -0
  134. package/src/simple-single-select/__stories__/WithClearButton.js +26 -0
  135. package/src/simple-single-select/__stories__/WithCustomLowMaxHeight.js +17 -0
  136. package/src/simple-single-select/__stories__/WithCustomOptions.js +78 -0
  137. package/src/simple-single-select/__stories__/WithDisabledOption.js +25 -0
  138. package/src/simple-single-select/__stories__/WithFilterField.js +30 -0
  139. package/src/simple-single-select/__stories__/WithInitialFocus.js +29 -0
  140. package/src/simple-single-select/__stories__/WithManyOptions.js +19 -0
  141. package/src/simple-single-select/__stories__/WithMultipleSelectsAndScrollableParent.js +65 -0
  142. package/src/simple-single-select/__stories__/WithNoMatchText.js +25 -0
  143. package/src/simple-single-select/__stories__/WithOnBlur.js +22 -0
  144. package/src/simple-single-select/__stories__/WithOnFocus.js +22 -0
  145. package/src/simple-single-select/__stories__/WithOptionsAndDisabled.js +17 -0
  146. package/src/simple-single-select/__stories__/WithOptionsAndLoading.js +23 -0
  147. package/src/simple-single-select/__stories__/WithOptionsAndLoadingText.js +24 -0
  148. package/src/simple-single-select/__stories__/WithPlaceholder.js +18 -0
  149. package/src/simple-single-select/__stories__/WithPlaceholderAndSelection.js +20 -0
  150. package/src/simple-single-select/__stories__/WithPrefix.js +17 -0
  151. package/src/simple-single-select/__stories__/WithPrefixAndSelection.js +20 -0
  152. package/src/simple-single-select/__stories__/WithRTL.js +29 -0
  153. package/src/simple-single-select/__stories__/WithScrollingParent.js +51 -0
  154. package/src/simple-single-select/__stories__/WithSelection.js +19 -0
  155. package/src/simple-single-select/__stories__/WithSelectionAndDisabled.js +20 -0
  156. package/src/simple-single-select/__stories__/WithServerSideFilteringDemo.js +245 -0
  157. package/src/simple-single-select/__stories__/WithSimpleFilteringDemo.js +50 -0
  158. package/src/simple-single-select/__stories__/WithoutOptionsAndLoading.js +16 -0
  159. package/src/simple-single-select/__stories__/WithoutSelection.js +17 -0
  160. package/src/simple-single-select/__stories__/options.js +96 -0
  161. package/src/simple-single-select/__stories__/simple-single-select-server-side-filtering/CustomDataProvider.js +70 -0
  162. package/src/simple-single-select/__stories__/simple-single-select-server-side-filtering/dataElements.js +4271 -0
  163. package/src/simple-single-select/__stories__/simple-single-select-server-side-filtering/index.js +1 -0
  164. package/src/simple-single-select/features/keyboard-interactions.test.e2e.js +581 -0
  165. package/src/simple-single-select/features/menu-positioning.test.e2e.js +187 -0
  166. package/src/simple-single-select/index.js +2 -0
  167. package/src/simple-single-select/is-option-hidden.js +21 -0
  168. package/src/simple-single-select/menu/empty.js +27 -0
  169. package/src/simple-single-select/menu/filter.js +61 -0
  170. package/src/simple-single-select/menu/index.js +1 -0
  171. package/src/simple-single-select/menu/loading.js +38 -0
  172. package/src/simple-single-select/menu/menu.js +171 -0
  173. package/src/simple-single-select/menu/no-match.js +28 -0
  174. package/src/simple-single-select/menu/option.js +161 -0
  175. package/src/simple-single-select/menu/options-list.js +107 -0
  176. package/src/simple-single-select/selected-value/clear-button.js +71 -0
  177. package/src/simple-single-select/selected-value/container.js +146 -0
  178. package/src/simple-single-select/selected-value/index.js +1 -0
  179. package/src/simple-single-select/selected-value/placeholder.js +24 -0
  180. package/src/simple-single-select/selected-value/prefix.js +26 -0
  181. package/src/simple-single-select/selected-value/selected-value.js +174 -0
  182. package/src/simple-single-select/shared-prop-types.js +8 -0
  183. package/src/simple-single-select/simple-single-select.e2e.stories.js +216 -0
  184. package/src/simple-single-select/simple-single-select.js +389 -0
  185. package/src/simple-single-select/simple-single-select.prod.stories.js +41 -0
  186. package/src/simple-single-select/simple-single-select.test.js +1136 -0
  187. package/src/simple-single-select/use-handle-key-press/index.js +2 -0
  188. package/src/simple-single-select/use-handle-key-press/use-focus-option.js +24 -0
  189. package/src/simple-single-select/use-handle-key-press/use-handle-key-press-on-combobox.js +259 -0
  190. package/src/simple-single-select/use-handle-key-press/use-handle-key-press-on-filter-input.js +147 -0
  191. package/src/simple-single-select/use-handle-key-press/use-handle-typing.js +79 -0
  192. package/src/simple-single-select/use-handle-key-press/use-highlight-first-option-on-previous-page.js +62 -0
  193. package/src/simple-single-select/use-handle-key-press/use-highlight-first-visible-option.js +38 -0
  194. package/src/simple-single-select/use-handle-key-press/use-highlight-last-option-on-next-page.js +60 -0
  195. package/src/simple-single-select/use-handle-key-press/use-highlight-last-visible-option.js +52 -0
  196. package/src/simple-single-select/use-handle-key-press/use-page-down.js +50 -0
  197. package/src/simple-single-select/use-handle-key-press/use-page-up.js +50 -0
  198. package/src/simple-single-select/use-handle-key-press/utils.js +23 -0
  199. package/src/simple-single-select-field/index.js +1 -0
  200. package/src/simple-single-select-field/simple-single-select-field.js +198 -0
  201. package/src/simple-single-select-field/simple-single-select-field.prod.stories.js +188 -0
  202. package/src/simple-single-select-field/simple-single-select-field.test.js +144 -0
  203. package/src/single-select/__tests__/selection.test.js +102 -0
  204. package/src/single-select/__tests__/single-select.test.js +23 -0
  205. package/src/single-select/features/accepts_blur_cb/index.js +14 -0
  206. package/src/single-select/features/accepts_blur_cb.feature +8 -0
  207. package/src/single-select/features/accepts_focus_cb/index.js +14 -0
  208. package/src/single-select/features/accepts_focus_cb.feature +6 -0
  209. package/src/single-select/features/accepts_initial_focus/index.js +5 -0
  210. package/src/single-select/features/accepts_initial_focus.feature +5 -0
  211. package/src/single-select/features/accepts_loading/index.js +22 -0
  212. package/src/single-select/features/accepts_loading.feature +14 -0
  213. package/src/single-select/features/accepts_max_height/index.js +31 -0
  214. package/src/single-select/features/accepts_max_height.feature +11 -0
  215. package/src/single-select/features/accepts_placeholder/index.js +25 -0
  216. package/src/single-select/features/accepts_placeholder.feature +10 -0
  217. package/src/single-select/features/accepts_prefix/index.js +19 -0
  218. package/src/single-select/features/accepts_prefix.feature +10 -0
  219. package/src/single-select/features/allows_invalid_options/index.js +28 -0
  220. package/src/single-select/features/allows_invalid_options.feature +12 -0
  221. package/src/single-select/features/allows_selecting/index.js +38 -0
  222. package/src/single-select/features/allows_selecting.feature +21 -0
  223. package/src/single-select/features/can_be_cleared/index.js +22 -0
  224. package/src/single-select/features/can_be_cleared.feature +6 -0
  225. package/src/single-select/features/can_be_disabled/index.js +39 -0
  226. package/src/single-select/features/can_be_disabled.feature +32 -0
  227. package/src/single-select/features/can_be_empty/index.js +28 -0
  228. package/src/single-select/features/can_be_empty.feature +16 -0
  229. package/src/single-select/features/can_be_filtered/index.js +23 -0
  230. package/src/single-select/features/can_be_filtered.feature +14 -0
  231. package/src/single-select/features/can_be_opened_and_closed/index.js +32 -0
  232. package/src/single-select/features/can_be_opened_and_closed.feature +41 -0
  233. package/src/single-select/features/common/index.js +44 -0
  234. package/src/single-select/features/duplicate_option_values/index.js +26 -0
  235. package/src/single-select/features/duplicate_option_values.feature +7 -0
  236. package/src/single-select/features/menu_width_matches_input/index.js +53 -0
  237. package/src/single-select/features/menu_width_matches_input.feature +11 -0
  238. package/src/single-select/features/position/index.js +111 -0
  239. package/src/single-select/features/position.feature +26 -0
  240. package/src/single-select/features/shows_selections/index.js +9 -0
  241. package/src/single-select/features/shows_selections.feature +5 -0
  242. package/src/single-select/filterable-menu.js +41 -0
  243. package/src/single-select/index.js +1 -0
  244. package/src/single-select/input.js +101 -0
  245. package/src/single-select/menu.js +75 -0
  246. package/src/single-select/selection.js +60 -0
  247. package/src/single-select/single-select.e2e.stories.js +376 -0
  248. package/src/single-select/single-select.js +146 -0
  249. package/src/single-select/single-select.prod.stories.js +358 -0
  250. package/src/single-select-field/__tests__/single-select-field.test.js +29 -0
  251. package/src/single-select-field/features/accepts_help_text/index.js +9 -0
  252. package/src/single-select-field/features/accepts_help_text.feature +5 -0
  253. package/src/single-select-field/features/accepts_label/index.js +9 -0
  254. package/src/single-select-field/features/accepts_label.feature +5 -0
  255. package/src/single-select-field/features/accepts_validation_text/index.js +9 -0
  256. package/src/single-select-field/features/accepts_validation_text.feature +5 -0
  257. package/src/single-select-field/features/can_be_required/index.js +11 -0
  258. package/src/single-select-field/features/can_be_required.feature +5 -0
  259. package/src/single-select-field/features/has_default_clear_text/index.js +16 -0
  260. package/src/single-select-field/features/has_default_clear_text.feature +6 -0
  261. package/src/single-select-field/features/has_default_empty_text/index.js +13 -0
  262. package/src/single-select-field/features/has_default_empty_text.feature +6 -0
  263. package/src/single-select-field/features/has_default_filter_nomatch_text/index.js +17 -0
  264. package/src/single-select-field/features/has_default_filter_nomatch_text.feature +7 -0
  265. package/src/single-select-field/features/has_default_filter_placeholder/index.js +15 -0
  266. package/src/single-select-field/features/has_default_filter_placeholder.feature +6 -0
  267. package/src/single-select-field/features/has_default_loading_text/index.js +13 -0
  268. package/src/single-select-field/features/has_default_loading_text.feature +6 -0
  269. package/src/single-select-field/index.js +1 -0
  270. package/src/single-select-field/single-select-field.e2e.stories.js +45 -0
  271. package/src/single-select-field/single-select-field.js +178 -0
  272. package/src/single-select-field/single-select-field.prod.stories.js +146 -0
  273. package/src/single-select-option/index.js +1 -0
  274. package/src/single-select-option/single-select-option.js +84 -0
@@ -0,0 +1,358 @@
1
+ import { sharedPropTypes } from '@dhis2/ui-constants'
2
+ import PropTypes from 'prop-types'
3
+ import React, { useEffect } from 'react'
4
+ import { SingleSelectOption } from '../index.js'
5
+ import { SingleSelect } from './index.js'
6
+
7
+ const description = `
8
+ Use a select component wherever the user needs to make a selection of one or more options from a list of 6 or more options. If there are less than 6 options to choose from and space permits, use checkboxes for multiple selection and radio buttons for single selection. If the user needs to make a complex selection with a specific ordering, use a transfer instead.
9
+
10
+ Learn more about using Selects at [Design System: Select](https://github.com/dhis2/design-system/blob/master/molecules/select.md).
11
+
12
+ \`\`\`js
13
+ import { SingleSelect, SingleSelectOption } from '@dhis2/ui'
14
+ \`\`\`
15
+
16
+ _**Note:** Due to demo limitations on this page, only one representative example is rendered here. For more (interactive) examples, see individual stories in the 'Canvas' tab._
17
+ `
18
+
19
+ const eventHandler = (handlerName) => (payload, event) => {
20
+ console.log(`${handlerName} payload`, payload)
21
+ console.log(`${handlerName} event`, event)
22
+ }
23
+
24
+ const onChange = eventHandler('onChange')
25
+ const onFocus = eventHandler('onFocus')
26
+ const onBlur = eventHandler('onBlur')
27
+
28
+ const CustomSingleSelectOption = ({ label, onClick }) => (
29
+ <div onClick={(e) => onClick({}, e)}>{label}</div>
30
+ )
31
+
32
+ CustomSingleSelectOption.propTypes = {
33
+ label: PropTypes.string,
34
+ onClick: PropTypes.func,
35
+ }
36
+
37
+ const requiredIfArgType = {
38
+ table: { type: { summary: 'string' }, control: { type: 'string' } },
39
+ }
40
+
41
+ export default {
42
+ title: 'Single Select',
43
+ component: SingleSelect,
44
+ parameters: {
45
+ docs: {
46
+ description: { component: description },
47
+ // Disable stories in docs page by default, then use one representative examples
48
+ disable: true,
49
+ // Use iframe to keep dropdown menu inside story for docs page
50
+ inlineStories: false,
51
+ iframeHeight: '300px',
52
+ },
53
+ },
54
+ // Use 'onChange' as a default arg, otherwise components throw an error when interacted with
55
+ // (Maybe this could be handled in the component - as a required prop)
56
+ args: { className: 'select', onChange },
57
+ argTypes: {
58
+ valid: { ...sharedPropTypes.statusArgType },
59
+ warning: { ...sharedPropTypes.statusArgType },
60
+ error: { ...sharedPropTypes.statusArgType },
61
+ clearText: { ...requiredIfArgType },
62
+ noMatchText: { ...requiredIfArgType },
63
+ },
64
+ }
65
+
66
+ const WithOptionsTemplate = (args) => (
67
+ <SingleSelect {...args}>
68
+ <SingleSelectOption value="1" label="option one" />
69
+ <SingleSelectOption value="2" label="option two" />
70
+ <SingleSelectOption value="3" label="option three" />
71
+ </SingleSelect>
72
+ )
73
+
74
+ const EmptyTemplate = (args) => <SingleSelect {...args} />
75
+
76
+ export const WithOptionsAndOnChange = WithOptionsTemplate.bind({})
77
+ WithOptionsAndOnChange.storyName = 'With options and onChange'
78
+
79
+ export const WithOptionsAndASelection = WithOptionsTemplate.bind({})
80
+ WithOptionsAndASelection.args = { selected: '1' }
81
+ // Enable this story as the primary for docs as a representative example
82
+ WithOptionsAndASelection.parameters = { docs: { disable: false } }
83
+ WithOptionsAndASelection.storyName = 'With options and a selection'
84
+
85
+ export const WithOnFocus = WithOptionsTemplate.bind({})
86
+ WithOnFocus.args = { onFocus }
87
+ WithOnFocus.storyName = 'With on focus'
88
+
89
+ export const WithOnBlur = WithOptionsTemplate.bind({})
90
+ WithOnBlur.args = { onBlur }
91
+ WithOnBlur.storyName = 'With onBlur'
92
+
93
+ export const WithCustomOptionsAndOnChange = (args) => (
94
+ <SingleSelect {...args}>
95
+ <CustomSingleSelectOption value="1" label="option one" />
96
+ <CustomSingleSelectOption value="2" label="option two" />
97
+ <CustomSingleSelectOption value="3" label="option three" />
98
+ </SingleSelect>
99
+ )
100
+ WithCustomOptionsAndOnChange.storyName = 'With custom options and onChange'
101
+
102
+ export const WithInvalidOptions = (args) => (
103
+ <SingleSelect {...args}>
104
+ <div>invalid one</div>
105
+ <SingleSelectOption value="1" label="option one" />
106
+ <div>invalid two</div>
107
+ <SingleSelectOption value="2" label="option two" />
108
+ <div>invalid three</div>
109
+ <SingleSelectOption value="3" label="option three" />
110
+ {null}
111
+ {undefined}
112
+ {false}
113
+ </SingleSelect>
114
+ )
115
+
116
+ export const WithInvalidFilterableOptions = (args) => (
117
+ <SingleSelect {...args}>
118
+ <div>invalid one</div>
119
+ <SingleSelectOption value="1" label="option one" />
120
+ <div>invalid two</div>
121
+ <SingleSelectOption value="2" label="option two" />
122
+ <div>invalid three</div>
123
+ <SingleSelectOption value="3" label="option three" />
124
+ </SingleSelect>
125
+ )
126
+ WithInvalidFilterableOptions.args = {
127
+ filterable: true,
128
+ noMatchText: 'No match found',
129
+ }
130
+
131
+ export const WithInitialFocus = EmptyTemplate.bind({})
132
+ WithInitialFocus.args = { initialFocus: true }
133
+ WithInitialFocus.parameters = { docs: { disable: true } }
134
+
135
+ export const Dense = WithOptionsTemplate.bind({})
136
+ Dense.args = { dense: true, placeholder: 'Dense sized select' }
137
+ Dense.storyName = 'Dense'
138
+
139
+ export const Empty = EmptyTemplate.bind({})
140
+
141
+ export const EmptyWithEmptyText = EmptyTemplate.bind({})
142
+ EmptyWithEmptyText.args = { empty: 'Custom empty text' }
143
+
144
+ export const EmptyWithEmptyComponent = EmptyTemplate.bind({})
145
+ EmptyWithEmptyComponent.args = {
146
+ empty: <div className="custom-empty">Custom empty component</div>,
147
+ }
148
+
149
+ export const WithOptionsAndLoading = WithOptionsTemplate.bind({})
150
+ WithOptionsAndLoading.args = { loading: true }
151
+
152
+ export const WithOptionsLoadingAndLoadingText = WithOptionsTemplate.bind({})
153
+ WithOptionsLoadingAndLoadingText.args = {
154
+ ...WithOptionsAndLoading.args,
155
+ loadingText: 'Loading options',
156
+ }
157
+ WithOptionsLoadingAndLoadingText.storyName =
158
+ 'With options, loading and loading text'
159
+
160
+ export const WithMoreThanTenOptions = (args) => (
161
+ <SingleSelect {...args}>
162
+ <SingleSelectOption value="1" label="option one" />
163
+ <SingleSelectOption value="2" label="option two" />
164
+ <SingleSelectOption value="3" label="option three" />
165
+ <SingleSelectOption value="4" label="option four" />
166
+ <SingleSelectOption value="5" label="option five" />
167
+ <SingleSelectOption value="6" label="option six" />
168
+ <SingleSelectOption value="7" label="option seven" />
169
+ <SingleSelectOption value="8" label="option eight" />
170
+ <SingleSelectOption value="9" label="option nine" />
171
+ <SingleSelectOption value="10" label="option ten" />
172
+ <SingleSelectOption value="11" label="option eleven" />
173
+ <SingleSelectOption value="12" label="option twelve" />
174
+ </SingleSelect>
175
+ )
176
+
177
+ export const WithMoreThanThreeOptionsAndA100PxMaxHeight = (args) => (
178
+ <SingleSelect {...args}>
179
+ <SingleSelectOption value="1" label="option one" />
180
+ <SingleSelectOption value="2" label="option two" />
181
+ <SingleSelectOption value="3" label="option three" />
182
+ <SingleSelectOption value="4" label="option four" />
183
+ <SingleSelectOption value="5" label="option five" />
184
+ <SingleSelectOption value="6" label="option six" />
185
+ <SingleSelectOption value="7" label="option seven" />
186
+ <SingleSelectOption value="8" label="option eight" />
187
+ <SingleSelectOption value="9" label="option nine" />
188
+ <SingleSelectOption value="10" label="option ten" />
189
+ <SingleSelectOption value="11" label="option eleven" />
190
+ <SingleSelectOption value="12" label="option twelve" />
191
+ </SingleSelect>
192
+ )
193
+ WithMoreThanThreeOptionsAndA100PxMaxHeight.args = { maxHeight: '100px' }
194
+ WithMoreThanThreeOptionsAndA100PxMaxHeight.storyName =
195
+ 'With more than three options and a 100px max-height'
196
+
197
+ export const WithOptionsAndDisabled = WithOptionsTemplate.bind({})
198
+ WithOptionsAndDisabled.args = { disabled: true }
199
+ WithOptionsAndDisabled.storyName = 'With options and disabled'
200
+
201
+ export const WithOptionsASelectionAndDisabled = WithOptionsTemplate.bind({})
202
+ WithOptionsASelectionAndDisabled.args = {
203
+ ...WithOptionsAndDisabled.args,
204
+ ...WithOptionsAndASelection.args,
205
+ }
206
+ WithOptionsASelectionAndDisabled.storyName =
207
+ 'With options, a selection and disabled'
208
+
209
+ export const WithPrefix = WithOptionsTemplate.bind({})
210
+ WithPrefix.args = { prefix: 'Prefix text', selected: '1' }
211
+
212
+ export const WithPrefixAndSelection = WithOptionsTemplate.bind({})
213
+ WithPrefixAndSelection.args = {
214
+ ...WithPrefix.args,
215
+ ...WithOptionsAndASelection.args,
216
+ }
217
+
218
+ export const WithRTL = (args) => {
219
+ // as options are rendered in Portal, the body dir (of the iframe) needs to be set to 'rtl'
220
+ useEffect(() => {
221
+ document.body.dir = 'rtl'
222
+ return () => {
223
+ document.body.dir = 'ltr'
224
+ }
225
+ }, [])
226
+
227
+ return (
228
+ <div dir="rtl">
229
+ <SingleSelect {...args}>
230
+ <SingleSelectOption value="1" label="الخيار 1" />
231
+ <SingleSelectOption value="2" label="الخيار 2" />
232
+ <SingleSelectOption value="3" label="الخيار 3" />
233
+ </SingleSelect>
234
+ </div>
235
+ )
236
+ }
237
+ WithRTL.args = {
238
+ prefix: 'نص البادئة',
239
+ ...WithOptionsAndASelection.args,
240
+ }
241
+ WithRTL.storyName = 'RTL Text'
242
+
243
+ export const WithPlaceholder = WithOptionsTemplate.bind({})
244
+ WithPlaceholder.args = { placeholder: 'Placeholder text' }
245
+
246
+ export const WithPlaceholderAndSelection = WithOptionsTemplate.bind({})
247
+ WithPlaceholderAndSelection.args = {
248
+ ...WithPlaceholder.args,
249
+ ...WithOptionsAndASelection.args,
250
+ }
251
+
252
+ export const WithDisabledOptionAndOnChange = (args) => (
253
+ <SingleSelect {...args}>
254
+ <SingleSelectOption value="1" label="option one" />
255
+ <SingleSelectOption value="2" label="option two" />
256
+ <SingleSelectOption value="3" label="option three" />
257
+ <SingleSelectOption value="4" label="disabled option" disabled />
258
+ </SingleSelect>
259
+ )
260
+ WithDisabledOptionAndOnChange.storyName = 'With disabled option and onChange'
261
+
262
+ export const WithClearButtonSelectionAndOnChange = WithOptionsTemplate.bind({})
263
+ WithClearButtonSelectionAndOnChange.args = {
264
+ ...WithOptionsAndASelection.args,
265
+ clearable: true,
266
+ clearText: 'Clear',
267
+ }
268
+ WithClearButtonSelectionAndOnChange.storyName =
269
+ 'With clear button, selection and onChange'
270
+
271
+ export const WithFilterField = WithOptionsTemplate.bind({})
272
+ WithFilterField.args = { ...WithInvalidFilterableOptions.args }
273
+
274
+ export const DefaultPosition = (args) => (
275
+ <>
276
+ <SingleSelect {...args}>
277
+ <SingleSelectOption value="1" label="option one" />
278
+ <SingleSelectOption value="2" label="option two" />
279
+ <SingleSelectOption value="3" label="option three" />
280
+ <SingleSelectOption value="4" label="option four" />
281
+ <SingleSelectOption value="5" label="option five" />
282
+ <SingleSelectOption value="6" label="option six" />
283
+ <SingleSelectOption value="7" label="option seven" />
284
+ <SingleSelectOption value="8" label="option eight" />
285
+ <SingleSelectOption value="9" label="option nine" />
286
+ <SingleSelectOption value="10" label="option ten" />
287
+ <SingleSelectOption value="11" label="option eleven" />
288
+ <SingleSelectOption value="12" label="option twelve" />
289
+ </SingleSelect>
290
+ <style jsx>{`
291
+ :global(#root) {
292
+ margin-bottom: 2000px;
293
+ }
294
+ `}</style>
295
+ </>
296
+ )
297
+
298
+ export const FlippedPosition = (args) => (
299
+ <>
300
+ <SingleSelect {...args}>
301
+ <SingleSelectOption value="1" label="option one" />
302
+ <SingleSelectOption value="2" label="option two" />
303
+ <SingleSelectOption value="3" label="option three" />
304
+ <SingleSelectOption value="4" label="option four" />
305
+ <SingleSelectOption value="5" label="option five" />
306
+ <SingleSelectOption value="6" label="option six" />
307
+ <SingleSelectOption value="7" label="option seven" />
308
+ <SingleSelectOption value="8" label="option eight" />
309
+ <SingleSelectOption value="9" label="option nine" />
310
+ <SingleSelectOption value="10" label="option ten" />
311
+ <SingleSelectOption value="11" label="option eleven" />
312
+ <SingleSelectOption value="12" label="option twelve" />
313
+ </SingleSelect>
314
+ <style jsx>{`
315
+ :global(html),
316
+ :global(body),
317
+ :global(#root) {
318
+ position: relative;
319
+ height: 500px;
320
+ max-height: 500px;
321
+ }
322
+ :global(#root) {
323
+ padding-top: 400px !important;
324
+ }
325
+ `}</style>
326
+ </>
327
+ )
328
+
329
+ export const ShiftedIntoView = (args) => (
330
+ <>
331
+ <SingleSelect {...args}>
332
+ <SingleSelectOption value="1" label="option one" />
333
+ <SingleSelectOption value="2" label="option two" />
334
+ <SingleSelectOption value="3" label="option three" />
335
+ <SingleSelectOption value="4" label="option four" />
336
+ <SingleSelectOption value="5" label="option five" />
337
+ <SingleSelectOption value="6" label="option six" />
338
+ <SingleSelectOption value="7" label="option seven" />
339
+ <SingleSelectOption value="8" label="option eight" />
340
+ <SingleSelectOption value="9" label="option nine" />
341
+ <SingleSelectOption value="10" label="option ten" />
342
+ <SingleSelectOption value="11" label="option eleven" />
343
+ <SingleSelectOption value="12" label="option twelve" />
344
+ </SingleSelect>
345
+ <style jsx>{`
346
+ :global(html),
347
+ :global(body),
348
+ :global(#root) {
349
+ position: relative;
350
+ height: 300px !important;
351
+ max-height: 300px;
352
+ }
353
+ :global(#root) {
354
+ padding-top: 130px !important;
355
+ }
356
+ `}</style>
357
+ </>
358
+ )
@@ -0,0 +1,29 @@
1
+ import { render, fireEvent, screen } from '@testing-library/react'
2
+ import React from 'react'
3
+ import { SingleSelectField } from '../single-select-field.js'
4
+
5
+ describe('<SingleSelect />', () => {
6
+ it('should call the onKeyDown callback when provided', () => {
7
+ const onKeyDown = jest.fn()
8
+
9
+ render(
10
+ <SingleSelectField
11
+ label="label"
12
+ placeholder="placeholder"
13
+ onKeyDown={onKeyDown}
14
+ />
15
+ )
16
+
17
+ fireEvent.keyDown(
18
+ screen.getByTestId('dhis2-uicore-singleselect-placeholder'),
19
+ { key: 'Enter', code: 'Enter', charCode: 13 }
20
+ )
21
+
22
+ expect(onKeyDown).toHaveBeenCalledWith(
23
+ { selected: '' },
24
+ expect.objectContaining({})
25
+ )
26
+
27
+ expect(onKeyDown).toHaveBeenCalledTimes(1)
28
+ })
29
+ })
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a SingleSelectField with help text is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With help text')
5
+ })
6
+
7
+ Then('the help text is visible', () => {
8
+ cy.contains('The help text').should('be.visible')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Help text for the SingleSelectField
2
+
3
+ Scenario: Rendering a SingleSelectField with help text
4
+ Given a SingleSelectField with help text is rendered
5
+ Then the help text is visible
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a SingleSelectField with a label is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With label')
5
+ })
6
+
7
+ Then('the label is visible', () => {
8
+ cy.contains('The label').should('be.visible')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Label for the SingleSelectField
2
+
3
+ Scenario: Rendering a SingleSelectField with a label
4
+ Given a SingleSelectField with a label is rendered
5
+ Then the label is visible
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a SingleSelectField with validation text is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With validation text')
5
+ })
6
+
7
+ Then('the validation text is visible', () => {
8
+ cy.contains('The validation text').should('be.visible')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Validation text for the SingleSelectField
2
+
3
+ Scenario: Rendering a SingleSelectField with validation text
4
+ Given a SingleSelectField with validation text is rendered
5
+ Then the validation text is visible
@@ -0,0 +1,11 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a SingleSelectField with label and a required flag is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With label and required status')
5
+ })
6
+
7
+ Then('the required indicator is visible', () => {
8
+ cy.get(
9
+ '[data-test="dhis2-uiwidgets-singleselectfield-label-required"]'
10
+ ).should('be.visible')
11
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Required status for the SingleSelectField
2
+
3
+ Scenario: Rendering a SingleSelectField that is required
4
+ Given a SingleSelectField with label and a required flag is rendered
5
+ Then the required indicator is visible
@@ -0,0 +1,16 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a clearable SingleSelectField with selected option is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With clearable and selected option')
5
+ })
6
+
7
+ When('the clear button is hovered', () => {
8
+ cy.get('[data-test="dhis2-uicore-singleselect-clear"]').trigger(
9
+ 'mouseover',
10
+ 'top'
11
+ )
12
+ })
13
+
14
+ Then('the clear text is visible', () => {
15
+ cy.contains('Clear').should('be.visible')
16
+ })
@@ -0,0 +1,6 @@
1
+ Feature: Clear text for the SingleSelectField
2
+
3
+ Scenario: Rendering a clearable SingleSelectField
4
+ Given a clearable SingleSelectField with selected option is rendered
5
+ When the clear button is hovered
6
+ Then the clear text is visible
@@ -0,0 +1,13 @@
1
+ import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('an empty SingleSelectField is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'Without options')
5
+ })
6
+
7
+ When('the Select is opened', () => {
8
+ cy.get('[data-test="dhis2-uicore-select-input"]').click()
9
+ })
10
+
11
+ Then('the empty text is visible', () => {
12
+ cy.contains('No data found').should('be.visible')
13
+ })
@@ -0,0 +1,6 @@
1
+ Feature: Empty text for the SingleSelectField
2
+
3
+ Scenario: Rendering an empty SingleSelectField
4
+ Given an empty SingleSelectField is rendered
5
+ When the Select is opened
6
+ Then the empty text is visible
@@ -0,0 +1,17 @@
1
+ import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a filterable SingleSelectField is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With filterable')
5
+ })
6
+
7
+ When('the Select is opened', () => {
8
+ cy.get('[data-test="dhis2-uicore-select-input"]').click()
9
+ })
10
+
11
+ When('a filter that does not match any options is entered', () => {
12
+ cy.focused().type('Two')
13
+ })
14
+
15
+ Then('the no match text is visible', () => {
16
+ cy.contains('No options found').should('be.visible')
17
+ })
@@ -0,0 +1,7 @@
1
+ Feature: Nomatchtext for the SingleSelectField
2
+
3
+ Scenario: Rendering a filterable SingleSelectField
4
+ Given a filterable SingleSelectField is rendered
5
+ When the Select is opened
6
+ And a filter that does not match any options is entered
7
+ Then the no match text is visible
@@ -0,0 +1,15 @@
1
+ import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a filterable SingleSelectField is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With filterable')
5
+ })
6
+
7
+ When('the Select is opened', () => {
8
+ cy.get('[data-test="dhis2-uicore-select-input"]').click()
9
+ })
10
+
11
+ Then('the filter placeholder exists', () => {
12
+ cy.get(
13
+ '[data-test="dhis2-uicore-singleselect-filterinput"] [placeholder="Type to filter options"]'
14
+ ).should('exist')
15
+ })
@@ -0,0 +1,6 @@
1
+ Feature: Filter placeholder for the SingleSelectField
2
+
3
+ Scenario: Rendering a filterable SingleSelectField
4
+ Given a filterable SingleSelectField is rendered
5
+ When the Select is opened
6
+ Then the filter placeholder exists
@@ -0,0 +1,13 @@
1
+ import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a loading SingleSelectField is rendered', () => {
4
+ cy.visitStory('SingleSelectField', 'With loading')
5
+ })
6
+
7
+ When('the Select is opened', () => {
8
+ cy.get('[data-test="dhis2-uicore-select-input"]').click()
9
+ })
10
+
11
+ Then('the loading text is visible', () => {
12
+ cy.contains('Loading options').should('be.visible')
13
+ })
@@ -0,0 +1,6 @@
1
+ Feature: Filter placeholder for the SingleSelectField
2
+
3
+ Scenario: Rendering a filterable SingleSelectField
4
+ Given a loading SingleSelectField is rendered
5
+ When the Select is opened
6
+ Then the loading text is visible
@@ -0,0 +1 @@
1
+ export { SingleSelectField } from './single-select-field.js'
@@ -0,0 +1,45 @@
1
+ import React from 'react'
2
+ import { SingleSelectOption } from '../index.js'
3
+ import { SingleSelectField } from './index.js'
4
+
5
+ export default { title: 'SingleSelectField' }
6
+ export const WithLabel = () => (
7
+ <SingleSelectField label="The label">
8
+ <SingleSelectOption value="1" label="one" />
9
+ <SingleSelectOption value="2" label="two" />
10
+ <SingleSelectOption value="3" label="three" />
11
+ </SingleSelectField>
12
+ )
13
+ export const WithHelpText = () => (
14
+ <SingleSelectField helpText="The help text">
15
+ <SingleSelectOption value="1" label="one" />
16
+ <SingleSelectOption value="2" label="two" />
17
+ <SingleSelectOption value="3" label="three" />
18
+ </SingleSelectField>
19
+ )
20
+ export const WithValidationText = () => (
21
+ <SingleSelectField validationText="The validation text">
22
+ <SingleSelectOption value="1" label="one" />
23
+ <SingleSelectOption value="2" label="two" />
24
+ <SingleSelectOption value="3" label="three" />
25
+ </SingleSelectField>
26
+ )
27
+ export const WithLabelAndRequiredStatus = () => (
28
+ <SingleSelectField label="The label" required>
29
+ <SingleSelectOption value="1" label="one" />
30
+ <SingleSelectOption value="2" label="two" />
31
+ <SingleSelectOption value="3" label="three" />
32
+ </SingleSelectField>
33
+ )
34
+ export const WithClearableAndSelectedOption = () => (
35
+ <SingleSelectField selected="1" clearable>
36
+ <SingleSelectOption key="1" value="1" label="One" />
37
+ </SingleSelectField>
38
+ )
39
+ export const WithFilterable = () => (
40
+ <SingleSelectField filterable>
41
+ <SingleSelectOption key="1" value="1" label="One" />
42
+ </SingleSelectField>
43
+ )
44
+ export const WithLoading = () => <SingleSelectField loading />
45
+ export const WithoutOptions = () => <SingleSelectField />