@dhis2-ui/select 10.9.1 → 10.10.0-alpha.1

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 (148) hide show
  1. package/build/cjs/index.js +18 -4
  2. package/build/cjs/locales/en/translations.json +7 -5
  3. package/build/cjs/simple-single-select/__stories__/DefaultPosition.js +38 -0
  4. package/build/cjs/simple-single-select/__stories__/Dense.js +22 -0
  5. package/build/cjs/simple-single-select/__stories__/Empty.js +20 -0
  6. package/build/cjs/simple-single-select/__stories__/EmptyWithEmptyNode.js +28 -0
  7. package/build/cjs/simple-single-select/__stories__/EmptyWithEmptyText.js +21 -0
  8. package/build/cjs/simple-single-select/__stories__/FlippedPosition.js +37 -0
  9. package/build/cjs/simple-single-select/__stories__/InfiniteLoading.js +61 -0
  10. package/build/cjs/simple-single-select/__stories__/Loading.js +20 -0
  11. package/build/cjs/simple-single-select/__stories__/ShiftedIntoView.js +28 -0
  12. package/build/cjs/simple-single-select/__stories__/WithClearButton.js +25 -0
  13. package/build/cjs/simple-single-select/__stories__/WithCustomLowMaxHeight.js +22 -0
  14. package/build/cjs/simple-single-select/__stories__/WithCustomOptions.js +48 -0
  15. package/build/cjs/simple-single-select/__stories__/WithDisabledOption.js +28 -0
  16. package/build/cjs/simple-single-select/__stories__/WithFilterField.js +36 -0
  17. package/build/cjs/simple-single-select/__stories__/WithInitialFocus.js +38 -0
  18. package/build/cjs/simple-single-select/__stories__/WithManyOptions.js +24 -0
  19. package/build/cjs/simple-single-select/__stories__/WithNoMatchText.js +30 -0
  20. package/build/cjs/simple-single-select/__stories__/WithOnBlur.js +23 -0
  21. package/build/cjs/simple-single-select/__stories__/WithOnFocus.js +23 -0
  22. package/build/cjs/simple-single-select/__stories__/WithOptionsAndDisabled.js +22 -0
  23. package/build/cjs/simple-single-select/__stories__/WithOptionsAndLoading.js +34 -0
  24. package/build/cjs/simple-single-select/__stories__/WithOptionsAndLoadingText.js +35 -0
  25. package/build/cjs/simple-single-select/__stories__/WithPlaceholder.js +23 -0
  26. package/build/cjs/simple-single-select/__stories__/WithPlaceholderAndSelection.js +25 -0
  27. package/build/cjs/simple-single-select/__stories__/WithPrefix.js +22 -0
  28. package/build/cjs/simple-single-select/__stories__/WithPrefixAndSelection.js +25 -0
  29. package/build/cjs/simple-single-select/__stories__/WithRTL.js +34 -0
  30. package/build/cjs/simple-single-select/__stories__/WithSelection.js +24 -0
  31. package/build/cjs/simple-single-select/__stories__/WithSelectionAndDisabled.js +25 -0
  32. package/build/cjs/simple-single-select/__stories__/WithoutOptionsAndLoading.js +21 -0
  33. package/build/cjs/simple-single-select/__stories__/WithoutSelection.js +22 -0
  34. package/build/cjs/simple-single-select/__stories__/options.js +77 -0
  35. package/build/cjs/simple-single-select/features/keyboard-interactions.test.e2e.js +441 -0
  36. package/build/cjs/simple-single-select/features/menu-positioning.test.e2e.js +152 -0
  37. package/build/cjs/simple-single-select/index.js +19 -0
  38. package/build/cjs/simple-single-select/is-option-hidden.js +22 -0
  39. package/build/cjs/simple-single-select/menu/empty.js +26 -0
  40. package/build/cjs/simple-single-select/menu/filter.js +60 -0
  41. package/build/cjs/simple-single-select/menu/index.js +12 -0
  42. package/build/cjs/simple-single-select/menu/loading.js +30 -0
  43. package/build/cjs/simple-single-select/menu/menu.js +158 -0
  44. package/build/cjs/simple-single-select/menu/no-match.js +28 -0
  45. package/build/cjs/simple-single-select/menu/option.js +120 -0
  46. package/build/cjs/simple-single-select/menu/options-list.js +97 -0
  47. package/build/cjs/simple-single-select/selected-value/clear-button.js +74 -0
  48. package/build/cjs/simple-single-select/selected-value/container.js +100 -0
  49. package/build/cjs/simple-single-select/selected-value/index.js +12 -0
  50. package/build/cjs/simple-single-select/selected-value/placeholder.js +30 -0
  51. package/build/cjs/simple-single-select/selected-value/prefix.js +30 -0
  52. package/build/cjs/simple-single-select/selected-value/selected-value.js +119 -0
  53. package/build/cjs/simple-single-select/shared-prop-types.js +14 -0
  54. package/build/cjs/simple-single-select/simple-single-select.e2e.stories.js +156 -0
  55. package/build/cjs/simple-single-select/simple-single-select.js +319 -0
  56. package/build/cjs/simple-single-select/simple-single-select.prod.stories.js +228 -0
  57. package/build/cjs/simple-single-select/simple-single-select.test.js +1106 -0
  58. package/build/cjs/simple-single-select/use-handle-key-press/index.js +19 -0
  59. package/build/cjs/simple-single-select/use-handle-key-press/use-focus-option.js +24 -0
  60. package/build/cjs/simple-single-select/use-handle-key-press/use-handle-key-press-on-combobox.js +177 -0
  61. package/build/cjs/simple-single-select/use-handle-key-press/use-handle-key-press-on-filter-input.js +106 -0
  62. package/build/cjs/simple-single-select/use-handle-key-press/use-handle-typing.js +81 -0
  63. package/build/cjs/simple-single-select/use-handle-key-press/use-highlight-first-option-on-previous-page.js +50 -0
  64. package/build/cjs/simple-single-select/use-handle-key-press/use-highlight-first-visible-option.js +30 -0
  65. package/build/cjs/simple-single-select/use-handle-key-press/use-highlight-last-option-on-next-page.js +50 -0
  66. package/build/cjs/simple-single-select/use-handle-key-press/use-highlight-last-visible-option.js +42 -0
  67. package/build/cjs/simple-single-select/use-handle-key-press/use-page-down.js +45 -0
  68. package/build/cjs/simple-single-select/use-handle-key-press/use-page-up.js +44 -0
  69. package/build/cjs/simple-single-select/use-handle-key-press/utils.js +46 -0
  70. package/build/cjs/simple-single-select-field/index.js +12 -0
  71. package/build/cjs/simple-single-select-field/simple-single-select-field.js +138 -0
  72. package/build/cjs/simple-single-select-field/simple-single-select-field.prod.stories.js +188 -0
  73. package/build/cjs/simple-single-select-field/simple-single-select-field.test.js +133 -0
  74. package/build/es/index.js +2 -0
  75. package/build/es/locales/en/translations.json +7 -5
  76. package/build/es/simple-single-select/__stories__/DefaultPosition.js +29 -0
  77. package/build/es/simple-single-select/__stories__/Dense.js +13 -0
  78. package/build/es/simple-single-select/__stories__/Empty.js +11 -0
  79. package/build/es/simple-single-select/__stories__/EmptyWithEmptyNode.js +19 -0
  80. package/build/es/simple-single-select/__stories__/EmptyWithEmptyText.js +12 -0
  81. package/build/es/simple-single-select/__stories__/FlippedPosition.js +28 -0
  82. package/build/es/simple-single-select/__stories__/InfiniteLoading.js +53 -0
  83. package/build/es/simple-single-select/__stories__/Loading.js +12 -0
  84. package/build/es/simple-single-select/__stories__/ShiftedIntoView.js +18 -0
  85. package/build/es/simple-single-select/__stories__/WithClearButton.js +16 -0
  86. package/build/es/simple-single-select/__stories__/WithCustomLowMaxHeight.js +13 -0
  87. package/build/es/simple-single-select/__stories__/WithCustomOptions.js +38 -0
  88. package/build/es/simple-single-select/__stories__/WithDisabledOption.js +19 -0
  89. package/build/es/simple-single-select/__stories__/WithFilterField.js +27 -0
  90. package/build/es/simple-single-select/__stories__/WithInitialFocus.js +29 -0
  91. package/build/es/simple-single-select/__stories__/WithManyOptions.js +15 -0
  92. package/build/es/simple-single-select/__stories__/WithNoMatchText.js +21 -0
  93. package/build/es/simple-single-select/__stories__/WithOnBlur.js +14 -0
  94. package/build/es/simple-single-select/__stories__/WithOnFocus.js +14 -0
  95. package/build/es/simple-single-select/__stories__/WithOptionsAndDisabled.js +13 -0
  96. package/build/es/simple-single-select/__stories__/WithOptionsAndLoading.js +25 -0
  97. package/build/es/simple-single-select/__stories__/WithOptionsAndLoadingText.js +26 -0
  98. package/build/es/simple-single-select/__stories__/WithPlaceholder.js +14 -0
  99. package/build/es/simple-single-select/__stories__/WithPlaceholderAndSelection.js +16 -0
  100. package/build/es/simple-single-select/__stories__/WithPrefix.js +13 -0
  101. package/build/es/simple-single-select/__stories__/WithPrefixAndSelection.js +16 -0
  102. package/build/es/simple-single-select/__stories__/WithRTL.js +25 -0
  103. package/build/es/simple-single-select/__stories__/WithSelection.js +15 -0
  104. package/build/es/simple-single-select/__stories__/WithSelectionAndDisabled.js +16 -0
  105. package/build/es/simple-single-select/__stories__/WithoutOptionsAndLoading.js +12 -0
  106. package/build/es/simple-single-select/__stories__/WithoutSelection.js +13 -0
  107. package/build/es/simple-single-select/__stories__/options.js +71 -0
  108. package/build/es/simple-single-select/features/keyboard-interactions.test.e2e.js +439 -0
  109. package/build/es/simple-single-select/features/menu-positioning.test.e2e.js +150 -0
  110. package/build/es/simple-single-select/index.js +2 -0
  111. package/build/es/simple-single-select/is-option-hidden.js +16 -0
  112. package/build/es/simple-single-select/menu/empty.js +19 -0
  113. package/build/es/simple-single-select/menu/filter.js +53 -0
  114. package/build/es/simple-single-select/menu/index.js +1 -0
  115. package/build/es/simple-single-select/menu/loading.js +23 -0
  116. package/build/es/simple-single-select/menu/menu.js +149 -0
  117. package/build/es/simple-single-select/menu/no-match.js +21 -0
  118. package/build/es/simple-single-select/menu/option.js +111 -0
  119. package/build/es/simple-single-select/menu/options-list.js +88 -0
  120. package/build/es/simple-single-select/selected-value/clear-button.js +68 -0
  121. package/build/es/simple-single-select/selected-value/container.js +91 -0
  122. package/build/es/simple-single-select/selected-value/index.js +1 -0
  123. package/build/es/simple-single-select/selected-value/placeholder.js +23 -0
  124. package/build/es/simple-single-select/selected-value/prefix.js +23 -0
  125. package/build/es/simple-single-select/selected-value/selected-value.js +112 -0
  126. package/build/es/simple-single-select/shared-prop-types.js +7 -0
  127. package/build/es/simple-single-select/simple-single-select.e2e.stories.js +142 -0
  128. package/build/es/simple-single-select/simple-single-select.js +310 -0
  129. package/build/es/simple-single-select/simple-single-select.prod.stories.js +36 -0
  130. package/build/es/simple-single-select/simple-single-select.test.js +1103 -0
  131. package/build/es/simple-single-select/use-handle-key-press/index.js +2 -0
  132. package/build/es/simple-single-select/use-handle-key-press/use-focus-option.js +18 -0
  133. package/build/es/simple-single-select/use-handle-key-press/use-handle-key-press-on-combobox.js +171 -0
  134. package/build/es/simple-single-select/use-handle-key-press/use-handle-key-press-on-filter-input.js +100 -0
  135. package/build/es/simple-single-select/use-handle-key-press/use-handle-typing.js +75 -0
  136. package/build/es/simple-single-select/use-handle-key-press/use-highlight-first-option-on-previous-page.js +44 -0
  137. package/build/es/simple-single-select/use-handle-key-press/use-highlight-first-visible-option.js +24 -0
  138. package/build/es/simple-single-select/use-handle-key-press/use-highlight-last-option-on-next-page.js +44 -0
  139. package/build/es/simple-single-select/use-handle-key-press/use-highlight-last-visible-option.js +36 -0
  140. package/build/es/simple-single-select/use-handle-key-press/use-page-down.js +39 -0
  141. package/build/es/simple-single-select/use-handle-key-press/use-page-up.js +38 -0
  142. package/build/es/simple-single-select/use-handle-key-press/utils.js +36 -0
  143. package/build/es/simple-single-select-field/index.js +1 -0
  144. package/build/es/simple-single-select-field/simple-single-select-field.js +131 -0
  145. package/build/es/simple-single-select-field/simple-single-select-field.prod.stories.js +172 -0
  146. package/build/es/simple-single-select-field/simple-single-select-field.test.js +130 -0
  147. package/package.json +15 -15
  148. package/types/index.d.ts +184 -1
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "useHandleKeyPressOnCombobox", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useHandleKeyPressOnCombobox.useHandleKeyPressOnCombobox;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "useHandleKeyPressOnFilterInput", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _useHandleKeyPressOnFilterInput.useHandleKeyPressOnFilterInput;
16
+ }
17
+ });
18
+ var _useHandleKeyPressOnCombobox = require("./use-handle-key-press-on-combobox.js");
19
+ var _useHandleKeyPressOnFilterInput = require("./use-handle-key-press-on-filter-input.js");
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useFocusOption = useFocusOption;
7
+ var _react = require("react");
8
+ function useFocusOption(findIndexCallback, _ref) {
9
+ let {
10
+ options,
11
+ focussedOptionIndex,
12
+ setFocussedOptionIndex
13
+ } = _ref;
14
+ return (0, _react.useCallback)(() => {
15
+ const nextFocussedIndex = findIndexCallback({
16
+ options,
17
+ activeIndex: focussedOptionIndex
18
+ });
19
+ if (nextFocussedIndex === -1) {
20
+ return;
21
+ }
22
+ setFocussedOptionIndex(nextFocussedIndex);
23
+ }, [findIndexCallback, options, focussedOptionIndex, setFocussedOptionIndex]);
24
+ }
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHandleKeyPressOnCombobox = useHandleKeyPressOnCombobox;
7
+ var _react = require("react");
8
+ var _useFocusOption = require("./use-focus-option.js");
9
+ var _useHandleTyping = require("./use-handle-typing.js");
10
+ var _usePageDown = require("./use-page-down.js");
11
+ var _usePageUp = require("./use-page-up.js");
12
+ var _utils = require("./utils.js");
13
+ function useSelectOption(findIndexCallback, _ref) {
14
+ let {
15
+ options,
16
+ onChange,
17
+ value
18
+ } = _ref;
19
+ return (0, _react.useCallback)(() => {
20
+ const currentOptionIndex = options.findIndex(option => option.value === value);
21
+ const nextSelectedOptionIndex = findIndexCallback({
22
+ options,
23
+ activeIndex: currentOptionIndex
24
+ });
25
+ if (nextSelectedOptionIndex === -1) {
26
+ return;
27
+ }
28
+ const nextOption = options[nextSelectedOptionIndex];
29
+ onChange({
30
+ label: nextOption.label,
31
+ value: nextOption.value
32
+ });
33
+ }, [findIndexCallback, options, onChange, value]);
34
+ }
35
+ function useHandleKeyPressOnCombobox(_ref2) {
36
+ let {
37
+ value,
38
+ disabled,
39
+ expanded,
40
+ loading,
41
+ options,
42
+ openMenu,
43
+ closeMenu,
44
+ listBoxRef,
45
+ focussedOptionIndex,
46
+ setFocussedOptionIndex,
47
+ selectFocussedOption,
48
+ onChange
49
+ } = _ref2;
50
+ const {
51
+ onTyping,
52
+ typing
53
+ } = (0, _useHandleTyping.useHandleTyping)({
54
+ expanded,
55
+ options,
56
+ setFocussedOptionIndex,
57
+ onChange
58
+ });
59
+ const pageDown = (0, _usePageDown.usePageDown)({
60
+ options,
61
+ focussedOptionIndex,
62
+ setFocussedOptionIndex,
63
+ listBoxRef
64
+ });
65
+ const pageUp = (0, _usePageUp.usePageUp)({
66
+ options,
67
+ listBoxRef,
68
+ focussedOptionIndex,
69
+ setFocussedOptionIndex
70
+ });
71
+ const selectNextOption = useSelectOption(_utils.findNextOptionIndex, {
72
+ options,
73
+ onChange,
74
+ value
75
+ });
76
+ const selectPrevOption = useSelectOption(_utils.findPrevOptionIndex, {
77
+ options,
78
+ onChange,
79
+ value
80
+ });
81
+ const focusNextOption = (0, _useFocusOption.useFocusOption)(_utils.findNextOptionIndex, {
82
+ options,
83
+ focussedOptionIndex,
84
+ setFocussedOptionIndex
85
+ });
86
+ const focusPrevOption = (0, _useFocusOption.useFocusOption)(_utils.findPrevOptionIndex, {
87
+ options,
88
+ focussedOptionIndex,
89
+ setFocussedOptionIndex
90
+ });
91
+ const focusFirstOption = (0, _useFocusOption.useFocusOption)(_utils.findFirstOptionIndex, {
92
+ options,
93
+ focussedOptionIndex,
94
+ setFocussedOptionIndex
95
+ });
96
+ const focusLastOption = (0, _useFocusOption.useFocusOption)(_utils.findLastOptionIndex, {
97
+ options,
98
+ focussedOptionIndex,
99
+ setFocussedOptionIndex
100
+ });
101
+ const handleKeyPress = (0, _react.useCallback)(_ref3 => {
102
+ let {
103
+ key,
104
+ altKey,
105
+ ctrlKey,
106
+ metaKey
107
+ } = _ref3;
108
+ if (disabled || loading) {
109
+ return;
110
+ }
111
+
112
+ /*
113
+ * The menu won't be an ancestor / sibling of the combobox,
114
+ * so when pressing tab, it's highly unlikely that any element
115
+ * in the menu would receive focus (happens only in storybook,
116
+ * where there's no other focussable element).
117
+ *
118
+ * Assistive technology will know about the menu as the combobox
119
+ * has the appropriate aria attributes that will point to the
120
+ * correct HTML elements.
121
+ */
122
+ if (expanded && key === 'Tab') {
123
+ closeMenu();
124
+ return;
125
+ }
126
+ if (expanded && (key === 'Escape' || key === 'Enter' || key === ' ' && !typing || key === 'ArrowUp' && altKey || key === 'ArrowDown' && altKey)) {
127
+ if (value !== options[focussedOptionIndex].value) {
128
+ selectFocussedOption();
129
+ }
130
+ closeMenu();
131
+ return;
132
+ }
133
+ if (!expanded && (key === ' ' && !typing || key === 'Enter' || key === 'ArrowUp' && altKey || key === 'ArrowDown' && altKey)) {
134
+ openMenu();
135
+ return;
136
+ }
137
+ if (key === 'ArrowDown' && !expanded) {
138
+ selectNextOption();
139
+ return;
140
+ }
141
+ if (key === 'ArrowDown') {
142
+ focusNextOption();
143
+ return;
144
+ }
145
+ if (key === 'ArrowUp' && !expanded) {
146
+ selectPrevOption();
147
+ return;
148
+ }
149
+ if (key === 'ArrowUp') {
150
+ focusPrevOption();
151
+ return;
152
+ }
153
+ if (key === 'Home') {
154
+ focusFirstOption();
155
+ return;
156
+ }
157
+ if (key === 'End') {
158
+ focusLastOption();
159
+ return;
160
+ }
161
+ if (key === 'Backspace' || key === 'Clear' || key.length === 1 && key !== ' ' && !altKey && !ctrlKey && !metaKey || key === ' ' && typing) {
162
+ onTyping(key);
163
+ return;
164
+ }
165
+ if (expanded && key === 'PageUp') {
166
+ pageUp();
167
+ return;
168
+ }
169
+ if (expanded && key === 'PageDown') {
170
+ pageDown();
171
+ return;
172
+ }
173
+
174
+ // Do nothing
175
+ }, [closeMenu, disabled, expanded, loading, openMenu, options, value, typing, focussedOptionIndex, selectFocussedOption, selectNextOption, selectPrevOption, focusNextOption, focusPrevOption, focusFirstOption, focusLastOption, pageDown, pageUp, onTyping]);
176
+ return handleKeyPress;
177
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHandleKeyPressOnFilterInput = useHandleKeyPressOnFilterInput;
7
+ var _react = require("react");
8
+ var _useFocusOption = require("./use-focus-option.js");
9
+ var _usePageDown = require("./use-page-down.js");
10
+ var _usePageUp = require("./use-page-up.js");
11
+ var _utils = require("./utils.js");
12
+ function useHandleKeyPressOnFilterInput(_ref) {
13
+ let {
14
+ value,
15
+ options,
16
+ loading,
17
+ closeMenu,
18
+ listBoxRef,
19
+ focusComboBox,
20
+ focussedOptionIndex,
21
+ setFocussedOptionIndex,
22
+ selectFocussedOption
23
+ } = _ref;
24
+ const pageDown = (0, _usePageDown.usePageDown)({
25
+ options,
26
+ focussedOptionIndex,
27
+ setFocussedOptionIndex,
28
+ listBoxRef
29
+ });
30
+ const pageUp = (0, _usePageUp.usePageUp)({
31
+ options,
32
+ listBoxRef,
33
+ focussedOptionIndex,
34
+ setFocussedOptionIndex
35
+ });
36
+ const focusNextOption = (0, _useFocusOption.useFocusOption)(_utils.findNextOptionIndex, {
37
+ options,
38
+ focussedOptionIndex,
39
+ setFocussedOptionIndex
40
+ });
41
+ const focusPrevOption = (0, _useFocusOption.useFocusOption)(_utils.findPrevOptionIndex, {
42
+ options,
43
+ focussedOptionIndex,
44
+ setFocussedOptionIndex
45
+ });
46
+ const focusFirstOption = (0, _useFocusOption.useFocusOption)(_utils.findFirstOptionIndex, {
47
+ options,
48
+ focussedOptionIndex,
49
+ setFocussedOptionIndex
50
+ });
51
+ const focusLastOption = (0, _useFocusOption.useFocusOption)(_utils.findLastOptionIndex, {
52
+ options,
53
+ focussedOptionIndex,
54
+ setFocussedOptionIndex
55
+ });
56
+ const handleKeyPress = (0, _react.useCallback)(e => {
57
+ if (loading) {
58
+ return;
59
+ }
60
+ const {
61
+ key,
62
+ altKey
63
+ } = e;
64
+ if (key === 'Escape' || key === 'Enter' || key === 'ArrowUp' && altKey || key === 'ArrowDown' && altKey) {
65
+ if (value !== options[focussedOptionIndex].value) {
66
+ selectFocussedOption();
67
+ }
68
+ closeMenu();
69
+
70
+ // As the filter is being focused, we want to move focus back to the combobox
71
+ focusComboBox();
72
+ return;
73
+ }
74
+ if (key === 'ArrowDown') {
75
+ e.preventDefault(); // Disable moving cursor to end
76
+ focusNextOption();
77
+ return;
78
+ }
79
+ if (key === 'ArrowUp') {
80
+ e.preventDefault(); // Disable moving cursor to start
81
+ focusPrevOption();
82
+ return;
83
+ }
84
+ if (key === 'Home') {
85
+ e.preventDefault(); // Disable moving cursor to start
86
+ focusFirstOption();
87
+ return;
88
+ }
89
+ if (key === 'End') {
90
+ e.preventDefault(); // Disable moving cursor to end
91
+ focusLastOption();
92
+ return;
93
+ }
94
+ if (key === 'PageUp') {
95
+ pageUp();
96
+ return;
97
+ }
98
+ if (key === 'PageDown') {
99
+ pageDown();
100
+ return;
101
+ }
102
+
103
+ // Do nothing
104
+ }, [closeMenu, options, value, loading, focussedOptionIndex, selectFocussedOption, focusComboBox, focusNextOption, focusPrevOption, focusFirstOption, focusLastOption, pageDown, pageUp]);
105
+ return handleKeyPress;
106
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHandleTyping = useHandleTyping;
7
+ var _react = require("react");
8
+ const TYPING_DEBOUNCE_TIME = 300; // ms
9
+
10
+ function useHandleTyping(_ref) {
11
+ let {
12
+ expanded,
13
+ options,
14
+ setFocussedOptionIndex,
15
+ onChange
16
+ } = _ref;
17
+ const [value, setValue] = (0, _react.useState)('');
18
+ const [typing, setTyping] = (0, _react.useState)(false);
19
+
20
+ // This will reset the typed value after a given time
21
+ const timeoutRef = (0, _react.useRef)();
22
+ (0, _react.useEffect)(() => {
23
+ if (timeoutRef.current) {
24
+ clearTimeout(timeoutRef.current);
25
+ timeoutRef.current = null;
26
+ }
27
+ if (value) {
28
+ timeoutRef.current = setTimeout(() => {
29
+ setValue('');
30
+ setTyping(false);
31
+ }, TYPING_DEBOUNCE_TIME);
32
+ } else {
33
+ setTyping(false);
34
+ }
35
+ }, [
36
+ // adding value to the dependencies array so that the hooks runs every time the value changes
37
+ value]);
38
+
39
+ // This will focus the first option with a label starting with the typed sequence
40
+ const prevValueRef = (0, _react.useRef)();
41
+ (0, _react.useEffect)(() => {
42
+ if (value && value !== prevValueRef.current) {
43
+ // We only want to do this when the value changed
44
+ prevValueRef.current = value;
45
+ const optionIndex = options.findIndex(_ref2 => {
46
+ let {
47
+ disabled,
48
+ label
49
+ } = _ref2;
50
+ return !disabled && label.toLowerCase().startsWith(value.toLowerCase());
51
+ });
52
+ if (optionIndex !== -1) {
53
+ if (expanded) {
54
+ setFocussedOptionIndex(optionIndex);
55
+ } else {
56
+ const nextSelectedOption = options[optionIndex];
57
+ onChange({
58
+ label: nextSelectedOption.label,
59
+ value: nextSelectedOption.value
60
+ });
61
+ }
62
+ }
63
+ }
64
+ }, [value, options, setFocussedOptionIndex, expanded, onChange]);
65
+ const onTyping = (0, _react.useCallback)(key => {
66
+ setTyping(true);
67
+ if (key === 'Backspace') {
68
+ setValue(prevValue => prevValue.slice(0, -1));
69
+ return;
70
+ }
71
+ if (key === 'Clear') {
72
+ setValue('');
73
+ return;
74
+ }
75
+ setValue(prevValue => `${prevValue}${key}`);
76
+ }, []);
77
+ return {
78
+ onTyping,
79
+ typing
80
+ };
81
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHighlightFirstOptionOnPreviousPage = useHighlightFirstOptionOnPreviousPage;
7
+ var _react = require("react");
8
+ function useHighlightFirstOptionOnPreviousPage(_ref) {
9
+ let {
10
+ options,
11
+ focussedOptionIndex,
12
+ setFocussedOptionIndex,
13
+ listBoxRef
14
+ } = _ref;
15
+ return (0, _react.useCallback)(() => {
16
+ const listBoxParent = listBoxRef.current.parentNode;
17
+ const optionElements = Array.from(listBoxRef.current.childNodes);
18
+ const visibleOptionsAmount = Math.floor(listBoxParent.offsetHeight / optionElements[0].offsetHeight);
19
+ const nextTopOptionIndex = Math.max(0, focussedOptionIndex - visibleOptionsAmount);
20
+
21
+ // If there's no next option and we already have the last option in the list highlighted
22
+ if (!options[nextTopOptionIndex]) {
23
+ return;
24
+ }
25
+ if (!options[nextTopOptionIndex].disabled) {
26
+ const nextTopOption = optionElements[nextTopOptionIndex];
27
+ const scrollPosition = nextTopOption.offsetTop;
28
+ listBoxParent.scrollTop = scrollPosition;
29
+ setFocussedOptionIndex(nextTopOptionIndex);
30
+ return;
31
+ }
32
+ const lowerEnabledOptionIndex = options.slice(0, nextTopOptionIndex).findLastIndex(option => !option.disabled);
33
+ if (lowerEnabledOptionIndex !== -1) {
34
+ const lowerEnabledOption = optionElements[lowerEnabledOptionIndex];
35
+ const lowerScrollPosition = lowerEnabledOption.offsetTop;
36
+ listBoxParent.scrollTop = lowerScrollPosition;
37
+ setFocussedOptionIndex(lowerEnabledOptionIndex);
38
+ return;
39
+ }
40
+ const inbetweenEnabledOptionIndex = nextTopOptionIndex + options.slice(nextTopOptionIndex, focussedOptionIndex).findIndex(option => !option.disabled);
41
+ if (inbetweenEnabledOptionIndex === -1) {
42
+ // We're already on the first enabled option
43
+ return;
44
+ }
45
+ const inbetweenTopOption = optionElements[inbetweenEnabledOptionIndex];
46
+ const scrollPosition = inbetweenTopOption.offsetTop;
47
+ listBoxParent.scrollTop = scrollPosition;
48
+ setFocussedOptionIndex(inbetweenEnabledOptionIndex);
49
+ }, [options, focussedOptionIndex, setFocussedOptionIndex, listBoxRef]);
50
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHighlightFirstVisibleOption = useHighlightFirstVisibleOption;
7
+ var _react = require("react");
8
+ function useHighlightFirstVisibleOption(_ref) {
9
+ let {
10
+ options,
11
+ focussedOptionIndex,
12
+ setFocussedOptionIndex
13
+ } = _ref;
14
+ return (0, _react.useCallback)(lowestVisibleIndex => {
15
+ if (!options[lowestVisibleIndex].disabled) {
16
+ setFocussedOptionIndex(lowestVisibleIndex);
17
+ return;
18
+ }
19
+ const previousEnabledOptionIndex = options.slice(0, lowestVisibleIndex).findLastIndex(option => !option.disabled);
20
+ if (previousEnabledOptionIndex !== -1) {
21
+ setFocussedOptionIndex(previousEnabledOptionIndex);
22
+ return;
23
+ }
24
+ const nextEnabledOptionIndex = lowestVisibleIndex + options.slice(lowestVisibleIndex, focussedOptionIndex).findIndex(option => !option.disabled);
25
+ if (nextEnabledOptionIndex !== -1) {
26
+ return;
27
+ }
28
+ setFocussedOptionIndex(nextEnabledOptionIndex);
29
+ }, [options, focussedOptionIndex, setFocussedOptionIndex]);
30
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHighlightLastOptionOnNextPage = useHighlightLastOptionOnNextPage;
7
+ var _react = require("react");
8
+ function useHighlightLastOptionOnNextPage(_ref) {
9
+ let {
10
+ options,
11
+ focussedOptionIndex,
12
+ setFocussedOptionIndex,
13
+ listBoxRef
14
+ } = _ref;
15
+ return (0, _react.useCallback)(() => {
16
+ const listBoxParent = listBoxRef.current.parentNode;
17
+ const optionElements = Array.from(listBoxRef.current.childNodes);
18
+ const visibleOptionsAmount = Math.floor(listBoxParent.offsetHeight / optionElements[0].offsetHeight);
19
+ const nextHighlightedOptionIndex = Math.min(options.length - 1, focussedOptionIndex + visibleOptionsAmount);
20
+
21
+ // If there's no next option and we already have the last option in the list highlighted
22
+ if (!options[nextHighlightedOptionIndex]) {
23
+ return;
24
+ }
25
+ if (!options[nextHighlightedOptionIndex].disabled) {
26
+ // This will be the first option in the list
27
+ const {
28
+ offsetTop: scrollPosition
29
+ } = optionElements[nextHighlightedOptionIndex - visibleOptionsAmount + 1];
30
+ listBoxParent.scrollTop = scrollPosition;
31
+ setFocussedOptionIndex(nextHighlightedOptionIndex);
32
+ return;
33
+ }
34
+ const followingEnabledOptionIndex = nextHighlightedOptionIndex + options.slice(nextHighlightedOptionIndex).findIndex(option => !option.disabled);
35
+
36
+ // There is no enabled option after the disabled option that's at the end of the next page
37
+ // So we stay where we are
38
+ if (followingEnabledOptionIndex === -1) {
39
+ return;
40
+ }
41
+
42
+ // There is an enabled option after the disabled option that's at the end of the next page
43
+ // So that'll be the new highlighted option and the bottom of the next displayed page
44
+ const {
45
+ offsetTop: adjustedScrollPosition
46
+ } = optionElements[followingEnabledOptionIndex - visibleOptionsAmount + 1];
47
+ listBoxParent.scrollTop = adjustedScrollPosition;
48
+ setFocussedOptionIndex(followingEnabledOptionIndex);
49
+ }, [options, focussedOptionIndex, setFocussedOptionIndex, listBoxRef]);
50
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useHighlightLastVisibleOption = useHighlightLastVisibleOption;
7
+ var _react = require("react");
8
+ function useHighlightLastVisibleOption(_ref) {
9
+ let {
10
+ options,
11
+ focussedOptionIndex,
12
+ setFocussedOptionIndex
13
+ } = _ref;
14
+ return (0, _react.useCallback)(highestVisibleIndex => {
15
+ if (!options[highestVisibleIndex].disabled) {
16
+ setFocussedOptionIndex(highestVisibleIndex);
17
+ return;
18
+ }
19
+
20
+ // Last option on page is disabled, find next option that's not disabled
21
+ const followingEnabledOptionIndex = options.slice(highestVisibleIndex).findIndex(option => !option.disabled);
22
+ if (followingEnabledOptionIndex >= 0) {
23
+ // We need to add the highest visible index because the index is lower due to slicing the array
24
+ setFocussedOptionIndex(followingEnabledOptionIndex + highestVisibleIndex);
25
+ return;
26
+ }
27
+
28
+ // No following enabled option, trying to find the closest previous sibling of the last option on the current page
29
+ const closestToEndOfPageEnabledOptionIndex = options.slice(
30
+ // We don't include the currently highlighted option
31
+ focussedOptionIndex + 1, highestVisibleIndex).findLastIndex(option => !option.disabled);
32
+ if (closestToEndOfPageEnabledOptionIndex >= 0) {
33
+ setFocussedOptionIndex(closestToEndOfPageEnabledOptionIndex +
34
+ // We need to add the focused index and 1 because the index is lower due to slicing the array
35
+ focussedOptionIndex + 1);
36
+ return;
37
+ }
38
+
39
+ // The currently highlighted option is the last enabled option
40
+ return;
41
+ }, [options, focussedOptionIndex, setFocussedOptionIndex]);
42
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.usePageDown = usePageDown;
7
+ var _react = require("react");
8
+ var _isOptionHidden = require("../is-option-hidden.js");
9
+ var _useHighlightLastOptionOnNextPage = require("./use-highlight-last-option-on-next-page.js");
10
+ var _useHighlightLastVisibleOption = require("./use-highlight-last-visible-option.js");
11
+ function usePageDown(_ref) {
12
+ let {
13
+ options,
14
+ focussedOptionIndex,
15
+ setFocussedOptionIndex,
16
+ listBoxRef
17
+ } = _ref;
18
+ const highlightLastVisibleOption = (0, _useHighlightLastVisibleOption.useHighlightLastVisibleOption)({
19
+ options,
20
+ focussedOptionIndex,
21
+ setFocussedOptionIndex
22
+ });
23
+ const highlightLastOptionOnNextPage = (0, _useHighlightLastOptionOnNextPage.useHighlightLastOptionOnNextPage)({
24
+ options,
25
+ focussedOptionIndex,
26
+ setFocussedOptionIndex,
27
+ listBoxRef
28
+ });
29
+ return (0, _react.useCallback)(() => {
30
+ const listBoxParent = listBoxRef.current.parentNode;
31
+ const options = Array.from(listBoxRef.current.childNodes);
32
+ const highestVisibleIndex = options.findLastIndex(option => !(0, _isOptionHidden.isOptionHidden)(option, listBoxParent));
33
+ if (highestVisibleIndex > focussedOptionIndex) {
34
+ highlightLastVisibleOption(highestVisibleIndex);
35
+ return;
36
+ }
37
+ if (highestVisibleIndex > -1) {
38
+ highlightLastOptionOnNextPage();
39
+ return;
40
+ }
41
+
42
+ // No visible option (e.g. when menu is empty)
43
+ return;
44
+ }, [focussedOptionIndex, listBoxRef, highlightLastVisibleOption, highlightLastOptionOnNextPage]);
45
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.usePageUp = usePageUp;
7
+ var _react = require("react");
8
+ var _isOptionHidden = require("../is-option-hidden.js");
9
+ var _useHighlightFirstOptionOnPreviousPage = require("./use-highlight-first-option-on-previous-page.js");
10
+ var _useHighlightFirstVisibleOption = require("./use-highlight-first-visible-option.js");
11
+ function usePageUp(_ref) {
12
+ let {
13
+ options,
14
+ listBoxRef,
15
+ focussedOptionIndex,
16
+ setFocussedOptionIndex
17
+ } = _ref;
18
+ const highlightFirstVisibleOption = (0, _useHighlightFirstVisibleOption.useHighlightFirstVisibleOption)({
19
+ options,
20
+ focussedOptionIndex,
21
+ setFocussedOptionIndex
22
+ });
23
+ const highlightFirstOptionOnPreviousPage = (0, _useHighlightFirstOptionOnPreviousPage.useHighlightFirstOptionOnPreviousPage)({
24
+ options,
25
+ focussedOptionIndex,
26
+ setFocussedOptionIndex,
27
+ listBoxRef
28
+ });
29
+ return (0, _react.useCallback)(() => {
30
+ const listBoxParent = listBoxRef.current.parentNode;
31
+ const optionElements = Array.from(listBoxRef.current.childNodes);
32
+ const lowestVisibleIndex = optionElements.findIndex(optionElement => !(0, _isOptionHidden.isOptionHidden)(optionElement, listBoxParent));
33
+
34
+ // No visible option (e.g. when menu is empty)
35
+ if (lowestVisibleIndex === -1) {
36
+ return;
37
+ }
38
+ if (lowestVisibleIndex < focussedOptionIndex) {
39
+ highlightFirstVisibleOption(lowestVisibleIndex);
40
+ return;
41
+ }
42
+ highlightFirstOptionOnPreviousPage();
43
+ }, [focussedOptionIndex, listBoxRef, highlightFirstOptionOnPreviousPage, highlightFirstVisibleOption]);
44
+ }