@atlaskit/react-select 2.2.0 → 2.3.0

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 (268) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/cjs/compiled/components/containers.compiled.css +26 -0
  3. package/dist/cjs/compiled/components/containers.js +119 -0
  4. package/dist/cjs/compiled/components/control.compiled.css +51 -0
  5. package/dist/cjs/compiled/components/control.js +66 -0
  6. package/dist/cjs/compiled/components/group.compiled.css +12 -0
  7. package/dist/cjs/compiled/components/group.js +81 -0
  8. package/dist/cjs/compiled/components/indicators.compiled.css +24 -0
  9. package/dist/cjs/compiled/components/indicators.js +157 -0
  10. package/dist/cjs/compiled/components/input.compiled.css +49 -0
  11. package/dist/cjs/compiled/components/input.js +69 -0
  12. package/dist/cjs/compiled/components/internal/a11y-text.compiled.css +15 -0
  13. package/dist/cjs/compiled/components/internal/a11y-text.js +23 -0
  14. package/dist/cjs/compiled/components/internal/dummy-input.compiled.css +17 -0
  15. package/dist/cjs/compiled/components/internal/dummy-input.js +30 -0
  16. package/dist/cjs/compiled/components/internal/required-input.compiled.css +8 -0
  17. package/dist/cjs/compiled/components/internal/required-input.js +34 -0
  18. package/dist/cjs/compiled/components/live-region.js +177 -0
  19. package/dist/cjs/compiled/components/menu.compiled.css +19 -0
  20. package/dist/cjs/compiled/components/menu.js +491 -0
  21. package/dist/cjs/compiled/components/multi-value.compiled.css +56 -0
  22. package/dist/cjs/compiled/components/multi-value.js +199 -0
  23. package/dist/cjs/compiled/components/option.compiled.css +22 -0
  24. package/dist/cjs/compiled/components/option.js +57 -0
  25. package/dist/cjs/compiled/components/placeholder.compiled.css +7 -0
  26. package/dist/cjs/compiled/components/placeholder.js +45 -0
  27. package/dist/cjs/compiled/components/single-value.compiled.css +13 -0
  28. package/dist/cjs/compiled/components/single-value.js +46 -0
  29. package/dist/cjs/components/containers.js +12 -72
  30. package/dist/cjs/components/control.js +11 -96
  31. package/dist/cjs/components/group.js +15 -53
  32. package/dist/cjs/components/indicators.js +15 -107
  33. package/dist/cjs/components/input.js +12 -81
  34. package/dist/cjs/components/internal/a11y-text.js +6 -25
  35. package/dist/cjs/components/internal/dummy-input.js +8 -36
  36. package/dist/cjs/components/internal/notify-open-layer-observer.js +1 -0
  37. package/dist/cjs/components/internal/required-input.js +7 -31
  38. package/dist/cjs/components/internal/scroll-manager.js +19 -17
  39. package/dist/cjs/components/live-region.js +6 -164
  40. package/dist/cjs/components/menu.js +26 -181
  41. package/dist/cjs/components/multi-value.js +21 -197
  42. package/dist/cjs/components/option.js +11 -68
  43. package/dist/cjs/components/placeholder.js +11 -20
  44. package/dist/cjs/components/single-value.js +11 -26
  45. package/dist/cjs/emotion/components/containers.js +113 -0
  46. package/dist/cjs/emotion/components/control.js +112 -0
  47. package/dist/cjs/emotion/components/group.js +72 -0
  48. package/dist/cjs/emotion/components/indicators.js +138 -0
  49. package/dist/cjs/emotion/components/input.js +94 -0
  50. package/dist/cjs/emotion/components/internal/a11y-text.js +37 -0
  51. package/dist/cjs/emotion/components/internal/dummy-input.js +45 -0
  52. package/dist/cjs/emotion/components/internal/required-input.js +45 -0
  53. package/dist/cjs/emotion/components/live-region.js +182 -0
  54. package/dist/cjs/emotion/components/menu.js +456 -0
  55. package/dist/cjs/emotion/components/multi-value.js +224 -0
  56. package/dist/cjs/emotion/components/option.js +84 -0
  57. package/dist/cjs/emotion/components/placeholder.js +36 -0
  58. package/dist/cjs/emotion/components/single-value.js +42 -0
  59. package/dist/cjs/utils.js +2 -1
  60. package/dist/es2019/compiled/components/containers.compiled.css +26 -0
  61. package/dist/es2019/compiled/components/containers.js +115 -0
  62. package/dist/es2019/compiled/components/control.compiled.css +51 -0
  63. package/dist/es2019/compiled/components/control.js +58 -0
  64. package/dist/es2019/compiled/components/group.compiled.css +12 -0
  65. package/dist/es2019/compiled/components/group.js +72 -0
  66. package/dist/es2019/compiled/components/indicators.compiled.css +24 -0
  67. package/dist/es2019/compiled/components/indicators.js +144 -0
  68. package/dist/es2019/compiled/components/input.compiled.css +49 -0
  69. package/dist/es2019/compiled/components/input.js +59 -0
  70. package/dist/es2019/compiled/components/internal/a11y-text.compiled.css +15 -0
  71. package/dist/es2019/compiled/components/internal/a11y-text.js +11 -0
  72. package/dist/es2019/compiled/components/internal/dummy-input.compiled.css +17 -0
  73. package/dist/es2019/compiled/components/internal/dummy-input.js +19 -0
  74. package/dist/es2019/compiled/components/internal/required-input.compiled.css +8 -0
  75. package/dist/es2019/compiled/components/internal/required-input.js +23 -0
  76. package/dist/es2019/compiled/components/live-region.js +171 -0
  77. package/dist/es2019/compiled/components/menu.compiled.css +19 -0
  78. package/dist/es2019/compiled/components/menu.js +478 -0
  79. package/dist/es2019/compiled/components/multi-value.compiled.css +56 -0
  80. package/dist/es2019/compiled/components/multi-value.js +190 -0
  81. package/dist/es2019/compiled/components/option.compiled.css +22 -0
  82. package/dist/es2019/compiled/components/option.js +48 -0
  83. package/dist/es2019/compiled/components/placeholder.compiled.css +7 -0
  84. package/dist/es2019/compiled/components/placeholder.js +36 -0
  85. package/dist/es2019/compiled/components/single-value.compiled.css +13 -0
  86. package/dist/es2019/compiled/components/single-value.js +37 -0
  87. package/dist/es2019/components/containers.js +10 -87
  88. package/dist/es2019/components/control.js +8 -103
  89. package/dist/es2019/components/group.js +9 -54
  90. package/dist/es2019/components/indicators.js +11 -113
  91. package/dist/es2019/components/input.js +7 -83
  92. package/dist/es2019/components/internal/a11y-text.js +6 -26
  93. package/dist/es2019/components/internal/dummy-input.js +7 -36
  94. package/dist/es2019/components/internal/notify-open-layer-observer.js +1 -0
  95. package/dist/es2019/components/internal/required-input.js +6 -32
  96. package/dist/es2019/components/internal/scroll-manager.js +16 -16
  97. package/dist/es2019/components/live-region.js +5 -168
  98. package/dist/es2019/components/menu.js +14 -192
  99. package/dist/es2019/components/multi-value.js +12 -216
  100. package/dist/es2019/components/option.js +7 -75
  101. package/dist/es2019/components/placeholder.js +7 -25
  102. package/dist/es2019/components/single-value.js +7 -31
  103. package/dist/es2019/emotion/components/containers.js +110 -0
  104. package/dist/es2019/emotion/components/control.js +108 -0
  105. package/dist/es2019/emotion/components/group.js +60 -0
  106. package/dist/es2019/emotion/components/indicators.js +129 -0
  107. package/dist/es2019/emotion/components/input.js +87 -0
  108. package/dist/es2019/emotion/components/internal/a11y-text.js +28 -0
  109. package/dist/es2019/emotion/components/internal/dummy-input.js +38 -0
  110. package/dist/es2019/emotion/components/internal/required-input.js +36 -0
  111. package/dist/es2019/emotion/components/live-region.js +180 -0
  112. package/dist/es2019/emotion/components/menu.js +452 -0
  113. package/dist/es2019/emotion/components/multi-value.js +228 -0
  114. package/dist/es2019/emotion/components/option.js +79 -0
  115. package/dist/es2019/emotion/components/placeholder.js +29 -0
  116. package/dist/es2019/emotion/components/single-value.js +35 -0
  117. package/dist/es2019/utils.js +1 -0
  118. package/dist/esm/compiled/components/containers.compiled.css +26 -0
  119. package/dist/esm/compiled/components/containers.js +110 -0
  120. package/dist/esm/compiled/components/control.compiled.css +51 -0
  121. package/dist/esm/compiled/components/control.js +57 -0
  122. package/dist/esm/compiled/components/group.compiled.css +12 -0
  123. package/dist/esm/compiled/components/group.js +71 -0
  124. package/dist/esm/compiled/components/indicators.compiled.css +24 -0
  125. package/dist/esm/compiled/components/indicators.js +148 -0
  126. package/dist/esm/compiled/components/input.compiled.css +49 -0
  127. package/dist/esm/compiled/components/input.js +59 -0
  128. package/dist/esm/compiled/components/internal/a11y-text.compiled.css +15 -0
  129. package/dist/esm/compiled/components/internal/a11y-text.js +13 -0
  130. package/dist/esm/compiled/components/internal/dummy-input.compiled.css +17 -0
  131. package/dist/esm/compiled/components/internal/dummy-input.js +20 -0
  132. package/dist/esm/compiled/components/internal/required-input.compiled.css +8 -0
  133. package/dist/esm/compiled/components/internal/required-input.js +24 -0
  134. package/dist/esm/compiled/components/live-region.js +168 -0
  135. package/dist/esm/compiled/components/menu.compiled.css +19 -0
  136. package/dist/esm/compiled/components/menu.js +485 -0
  137. package/dist/esm/compiled/components/multi-value.compiled.css +56 -0
  138. package/dist/esm/compiled/components/multi-value.js +187 -0
  139. package/dist/esm/compiled/components/option.compiled.css +22 -0
  140. package/dist/esm/compiled/components/option.js +47 -0
  141. package/dist/esm/compiled/components/placeholder.compiled.css +7 -0
  142. package/dist/esm/compiled/components/placeholder.js +35 -0
  143. package/dist/esm/compiled/components/single-value.compiled.css +13 -0
  144. package/dist/esm/compiled/components/single-value.js +36 -0
  145. package/dist/esm/components/containers.js +12 -73
  146. package/dist/esm/components/control.js +8 -97
  147. package/dist/esm/components/group.js +11 -54
  148. package/dist/esm/components/indicators.js +15 -109
  149. package/dist/esm/components/input.js +8 -83
  150. package/dist/esm/components/internal/a11y-text.js +6 -26
  151. package/dist/esm/components/internal/dummy-input.js +7 -37
  152. package/dist/esm/components/internal/notify-open-layer-observer.js +1 -0
  153. package/dist/esm/components/internal/required-input.js +7 -32
  154. package/dist/esm/components/internal/scroll-manager.js +16 -16
  155. package/dist/esm/components/live-region.js +5 -163
  156. package/dist/esm/components/menu.js +24 -182
  157. package/dist/esm/components/multi-value.js +17 -199
  158. package/dist/esm/components/option.js +8 -69
  159. package/dist/esm/components/placeholder.js +8 -21
  160. package/dist/esm/components/single-value.js +8 -27
  161. package/dist/esm/emotion/components/containers.js +106 -0
  162. package/dist/esm/emotion/components/control.js +104 -0
  163. package/dist/esm/emotion/components/group.js +66 -0
  164. package/dist/esm/emotion/components/indicators.js +133 -0
  165. package/dist/esm/emotion/components/input.js +90 -0
  166. package/dist/esm/emotion/components/internal/a11y-text.js +30 -0
  167. package/dist/esm/emotion/components/internal/dummy-input.js +39 -0
  168. package/dist/esm/emotion/components/internal/required-input.js +37 -0
  169. package/dist/esm/emotion/components/live-region.js +177 -0
  170. package/dist/esm/emotion/components/menu.js +456 -0
  171. package/dist/esm/emotion/components/multi-value.js +218 -0
  172. package/dist/esm/emotion/components/option.js +76 -0
  173. package/dist/esm/emotion/components/placeholder.js +28 -0
  174. package/dist/esm/emotion/components/single-value.js +34 -0
  175. package/dist/esm/utils.js +2 -1
  176. package/dist/types/compiled/components/containers.d.ts +53 -0
  177. package/dist/types/compiled/components/control.d.ts +41 -0
  178. package/dist/types/compiled/components/group.d.ts +54 -0
  179. package/dist/types/compiled/components/indicators.d.ts +72 -0
  180. package/dist/types/compiled/components/input.d.ts +36 -0
  181. package/dist/types/compiled/components/internal/a11y-text.d.ts +3 -0
  182. package/dist/types/compiled/components/internal/dummy-input.d.ts +8 -0
  183. package/dist/types/compiled/components/internal/required-input.d.ts +10 -0
  184. package/dist/types/compiled/components/live-region.d.ts +19 -0
  185. package/dist/types/compiled/components/menu.d.ts +115 -0
  186. package/dist/types/compiled/components/multi-value.d.ts +57 -0
  187. package/dist/types/compiled/components/option.d.ts +48 -0
  188. package/dist/types/compiled/components/placeholder.d.ts +21 -0
  189. package/dist/types/compiled/components/single-value.d.ts +27 -0
  190. package/dist/types/components/containers.d.ts +6 -11
  191. package/dist/types/components/control.d.ts +4 -9
  192. package/dist/types/components/group.d.ts +8 -10
  193. package/dist/types/components/index.d.ts +21 -21
  194. package/dist/types/components/indicators.d.ts +7 -12
  195. package/dist/types/components/input.d.ts +3 -8
  196. package/dist/types/components/internal/a11y-text.d.ts +2 -7
  197. package/dist/types/components/internal/dummy-input.d.ts +3 -8
  198. package/dist/types/components/internal/required-input.d.ts +0 -4
  199. package/dist/types/components/internal/scroll-manager.d.ts +2 -7
  200. package/dist/types/components/live-region.d.ts +2 -8
  201. package/dist/types/components/menu.d.ts +10 -15
  202. package/dist/types/components/multi-value.d.ts +19 -13
  203. package/dist/types/components/option.d.ts +3 -8
  204. package/dist/types/components/placeholder.d.ts +3 -8
  205. package/dist/types/components/single-value.d.ts +3 -8
  206. package/dist/types/emotion/components/containers.d.ts +54 -0
  207. package/dist/types/emotion/components/control.d.ts +42 -0
  208. package/dist/types/emotion/components/group.d.ts +52 -0
  209. package/dist/types/emotion/components/indicators.d.ts +73 -0
  210. package/dist/types/emotion/components/input.d.ts +37 -0
  211. package/dist/types/emotion/components/internal/a11y-text.d.ts +8 -0
  212. package/dist/types/emotion/components/internal/dummy-input.d.ts +9 -0
  213. package/dist/types/emotion/components/internal/required-input.d.ts +10 -0
  214. package/dist/types/emotion/components/live-region.d.ts +25 -0
  215. package/dist/types/emotion/components/menu.d.ts +116 -0
  216. package/dist/types/emotion/components/multi-value.d.ts +47 -0
  217. package/dist/types/emotion/components/option.d.ts +49 -0
  218. package/dist/types/emotion/components/placeholder.d.ts +22 -0
  219. package/dist/types/emotion/components/single-value.d.ts +28 -0
  220. package/dist/types/select.d.ts +21 -21
  221. package/dist/types/types.d.ts +3 -0
  222. package/dist/types-ts4.5/compiled/components/containers.d.ts +53 -0
  223. package/dist/types-ts4.5/compiled/components/control.d.ts +41 -0
  224. package/dist/types-ts4.5/compiled/components/group.d.ts +54 -0
  225. package/dist/types-ts4.5/compiled/components/indicators.d.ts +72 -0
  226. package/dist/types-ts4.5/compiled/components/input.d.ts +36 -0
  227. package/dist/types-ts4.5/compiled/components/internal/a11y-text.d.ts +3 -0
  228. package/dist/types-ts4.5/compiled/components/internal/dummy-input.d.ts +8 -0
  229. package/dist/types-ts4.5/compiled/components/internal/required-input.d.ts +10 -0
  230. package/dist/types-ts4.5/compiled/components/live-region.d.ts +19 -0
  231. package/dist/types-ts4.5/compiled/components/menu.d.ts +115 -0
  232. package/dist/types-ts4.5/compiled/components/multi-value.d.ts +57 -0
  233. package/dist/types-ts4.5/compiled/components/option.d.ts +48 -0
  234. package/dist/types-ts4.5/compiled/components/placeholder.d.ts +21 -0
  235. package/dist/types-ts4.5/compiled/components/single-value.d.ts +27 -0
  236. package/dist/types-ts4.5/components/containers.d.ts +6 -11
  237. package/dist/types-ts4.5/components/control.d.ts +4 -9
  238. package/dist/types-ts4.5/components/group.d.ts +8 -10
  239. package/dist/types-ts4.5/components/index.d.ts +21 -21
  240. package/dist/types-ts4.5/components/indicators.d.ts +7 -12
  241. package/dist/types-ts4.5/components/input.d.ts +3 -8
  242. package/dist/types-ts4.5/components/internal/a11y-text.d.ts +2 -7
  243. package/dist/types-ts4.5/components/internal/dummy-input.d.ts +3 -8
  244. package/dist/types-ts4.5/components/internal/required-input.d.ts +0 -4
  245. package/dist/types-ts4.5/components/internal/scroll-manager.d.ts +2 -7
  246. package/dist/types-ts4.5/components/live-region.d.ts +2 -8
  247. package/dist/types-ts4.5/components/menu.d.ts +10 -15
  248. package/dist/types-ts4.5/components/multi-value.d.ts +19 -13
  249. package/dist/types-ts4.5/components/option.d.ts +3 -8
  250. package/dist/types-ts4.5/components/placeholder.d.ts +3 -8
  251. package/dist/types-ts4.5/components/single-value.d.ts +3 -8
  252. package/dist/types-ts4.5/emotion/components/containers.d.ts +54 -0
  253. package/dist/types-ts4.5/emotion/components/control.d.ts +42 -0
  254. package/dist/types-ts4.5/emotion/components/group.d.ts +52 -0
  255. package/dist/types-ts4.5/emotion/components/indicators.d.ts +73 -0
  256. package/dist/types-ts4.5/emotion/components/input.d.ts +37 -0
  257. package/dist/types-ts4.5/emotion/components/internal/a11y-text.d.ts +8 -0
  258. package/dist/types-ts4.5/emotion/components/internal/dummy-input.d.ts +9 -0
  259. package/dist/types-ts4.5/emotion/components/internal/required-input.d.ts +10 -0
  260. package/dist/types-ts4.5/emotion/components/live-region.d.ts +25 -0
  261. package/dist/types-ts4.5/emotion/components/menu.d.ts +116 -0
  262. package/dist/types-ts4.5/emotion/components/multi-value.d.ts +47 -0
  263. package/dist/types-ts4.5/emotion/components/option.d.ts +49 -0
  264. package/dist/types-ts4.5/emotion/components/placeholder.d.ts +22 -0
  265. package/dist/types-ts4.5/emotion/components/single-value.d.ts +28 -0
  266. package/dist/types-ts4.5/select.d.ts +21 -21
  267. package/dist/types-ts4.5/types.d.ts +3 -0
  268. package/package.json +10 -2
@@ -0,0 +1,180 @@
1
+ /* eslint-disable @atlaskit/platform/ensure-feature-flag-prefix */
2
+ /**
3
+ * @jsxRuntime classic
4
+ * @jsx jsx
5
+ * @jsxFrag React.Fragment
6
+ */
7
+ import React, { Fragment, useMemo, useRef } from 'react';
8
+
9
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled
10
+ import { jsx } from '@emotion/react';
11
+ import { fg } from '@atlaskit/platform-feature-flags';
12
+ import { defaultAriaLiveMessages } from '../../accessibility';
13
+ import A11yText from './internal/a11y-text';
14
+
15
+ // ==============================
16
+ // Root Container
17
+ // ==============================
18
+
19
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
20
+ const LiveRegion = props => {
21
+ const {
22
+ ariaSelection,
23
+ focusedOption,
24
+ focusedValue,
25
+ focusableOptions,
26
+ isFocused,
27
+ selectValue,
28
+ selectProps,
29
+ id,
30
+ isAppleDevice
31
+ } = props;
32
+ const {
33
+ ariaLiveMessages,
34
+ getOptionLabel,
35
+ inputValue,
36
+ isMulti,
37
+ isOptionDisabled,
38
+ isSearchable,
39
+ label,
40
+ menuIsOpen,
41
+ options,
42
+ screenReaderStatus,
43
+ tabSelectsValue,
44
+ isLoading
45
+ } = selectProps;
46
+ const ariaLabel = selectProps['aria-label'] || label;
47
+ const ariaLive = selectProps['aria-live'];
48
+
49
+ // for safari, we will use minimum support from aria-live region
50
+ const isA11yImprovementEnabled = fg('design_system_select-a11y-improvement') && !isAppleDevice;
51
+
52
+ // Update aria live message configuration when prop changes
53
+ const messages = useMemo(() => ({
54
+ ...defaultAriaLiveMessages,
55
+ ...(ariaLiveMessages || {})
56
+ }), [ariaLiveMessages]);
57
+
58
+ // Update aria live selected option when prop changes
59
+ const ariaSelected = useMemo(() => {
60
+ let message = '';
61
+ if (isA11yImprovementEnabled && menuIsOpen) {
62
+ // we don't need to have selected message when the menu is open
63
+ return '';
64
+ }
65
+ if (ariaSelection && messages.onChange) {
66
+ const {
67
+ option,
68
+ options: selectedOptions,
69
+ removedValue,
70
+ removedValues,
71
+ value
72
+ } = ariaSelection;
73
+ // select-option when !isMulti does not return option so we assume selected option is value
74
+ const asOption = val => !Array.isArray(val) ? val : null;
75
+
76
+ // If there is just one item from the action then get its label
77
+ const selected = removedValue || option || asOption(value);
78
+ const label = selected ? getOptionLabel(selected) : '';
79
+
80
+ // If there are multiple items from the action then return an array of labels
81
+ const multiSelected = selectedOptions || removedValues || undefined;
82
+ const labels = multiSelected ? multiSelected.map(getOptionLabel) : [];
83
+ if (isA11yImprovementEnabled && !label && !labels.length) {
84
+ // return empty string if no labels provided
85
+ return '';
86
+ }
87
+ const onChangeProps = {
88
+ // multiSelected items are usually items that have already been selected
89
+ // or set by the user as a default value so we assume they are not disabled
90
+ isDisabled: selected && isOptionDisabled(selected, selectValue),
91
+ label,
92
+ labels,
93
+ ...ariaSelection
94
+ };
95
+ message = messages.onChange(onChangeProps);
96
+ }
97
+ return message;
98
+ }, [ariaSelection, messages, isOptionDisabled, selectValue, getOptionLabel, isA11yImprovementEnabled, menuIsOpen]);
99
+ const prevInputValue = useRef('');
100
+ const ariaFocused = useMemo(() => {
101
+ let focusMsg = '';
102
+ const focused = focusedOption || focusedValue;
103
+ const isSelected = !!(focusedOption && selectValue && selectValue.includes(focusedOption));
104
+ if (inputValue === prevInputValue.current && isA11yImprovementEnabled) {
105
+ // only announce focus option when searching when ff is on and the input value changed
106
+ // for safari, we will announce for all
107
+ return '';
108
+ }
109
+ if (focused && messages.onFocus) {
110
+ const onFocusProps = {
111
+ focused,
112
+ label: getOptionLabel(focused),
113
+ isDisabled: isOptionDisabled(focused, selectValue),
114
+ isSelected,
115
+ options: focusableOptions,
116
+ context: focused === focusedOption ? 'menu' : 'value',
117
+ selectValue,
118
+ isMulti
119
+ };
120
+ focusMsg = messages.onFocus(onFocusProps);
121
+ }
122
+ prevInputValue.current = inputValue;
123
+ return focusMsg;
124
+ }, [inputValue, focusedOption, focusedValue, getOptionLabel, isOptionDisabled, messages, focusableOptions, selectValue, isA11yImprovementEnabled, isMulti]);
125
+ const ariaResults = useMemo(() => {
126
+ let resultsMsg = '';
127
+ if (menuIsOpen && options.length && !isLoading && messages.onFilter) {
128
+ const resultsMessage = screenReaderStatus({
129
+ count: focusableOptions.length
130
+ });
131
+ resultsMsg = messages.onFilter({
132
+ inputValue,
133
+ resultsMessage
134
+ });
135
+ }
136
+ return resultsMsg;
137
+ }, [focusableOptions, inputValue, menuIsOpen, messages, options, screenReaderStatus, isLoading]);
138
+ const isInitialFocus = (ariaSelection === null || ariaSelection === void 0 ? void 0 : ariaSelection.action) === 'initial-input-focus';
139
+ const ariaGuidance = useMemo(() => {
140
+ if (fg('design_system_select-a11y-improvement')) {
141
+ // don't announce guidance at all when ff is on
142
+ return '';
143
+ }
144
+ let guidanceMsg = '';
145
+ if (messages.guidance) {
146
+ const context = focusedValue ? 'value' : menuIsOpen ? 'menu' : 'input';
147
+ guidanceMsg = messages.guidance({
148
+ 'aria-label': ariaLabel,
149
+ context,
150
+ isDisabled: focusedOption && isOptionDisabled(focusedOption, selectValue),
151
+ isMulti,
152
+ isSearchable,
153
+ tabSelectsValue,
154
+ isInitialFocus
155
+ });
156
+ }
157
+ return guidanceMsg;
158
+ }, [ariaLabel, focusedOption, focusedValue, isMulti, isOptionDisabled, isSearchable, menuIsOpen, messages, selectValue, tabSelectsValue, isInitialFocus]);
159
+ const ScreenReaderText = jsx(Fragment, null, jsx("span", {
160
+ id: "aria-selection"
161
+ }, ariaSelected), jsx("span", {
162
+ id: "aria-results"
163
+ }, ariaResults), !fg('design_system_select-a11y-improvement') && jsx(React.Fragment, null, jsx("span", {
164
+ id: "aria-focused"
165
+ }, ariaFocused), jsx("span", {
166
+ id: "aria-guidance"
167
+ }, ariaGuidance)));
168
+ return jsx(Fragment, null, jsx(A11yText, {
169
+ id: id
170
+ }, isInitialFocus && ScreenReaderText), jsx(A11yText, {
171
+ "aria-live": ariaLive // Should be undefined by default unless a specific use case requires it
172
+ ,
173
+ "aria-atomic": fg('design_system_select-a11y-improvement') ? undefined : 'false',
174
+ "aria-relevant": fg('design_system_select-a11y-improvement') ? undefined : 'additions text',
175
+ role: fg('design_system_select-a11y-improvement') ? 'status' : 'log'
176
+ }, isFocused && !isInitialFocus && ScreenReaderText));
177
+ };
178
+
179
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
180
+ export default LiveRegion;
@@ -0,0 +1,452 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ /**
3
+ * @jsxRuntime classic
4
+ * @jsx jsx
5
+ */
6
+ import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';
7
+
8
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled
9
+ import { jsx } from '@emotion/react';
10
+ import { autoUpdate } from '@floating-ui/dom';
11
+ import { createPortal } from 'react-dom';
12
+ import useLayoutEffect from 'use-isomorphic-layout-effect';
13
+ import { fg } from '@atlaskit/platform-feature-flags';
14
+ import { Text } from '@atlaskit/primitives';
15
+ import { animatedScrollTo, getBoundingClientObj, getScrollParent, getScrollTop, getStyleProps, normalizedHeight, scrollTo } from '../../utils';
16
+
17
+ // ==============================
18
+ // Menu
19
+ // ==============================
20
+
21
+ // Get Menu Placement
22
+ // ------------------------------
23
+
24
+ function getMenuPlacement({
25
+ maxHeight: preferredMaxHeight,
26
+ menuEl,
27
+ minHeight,
28
+ placement: preferredPlacement,
29
+ shouldScroll,
30
+ isFixedPosition,
31
+ controlHeight
32
+ }) {
33
+ const scrollParent = getScrollParent(menuEl);
34
+ const defaultState = {
35
+ placement: 'bottom',
36
+ maxHeight: preferredMaxHeight
37
+ };
38
+
39
+ // something went wrong, return default state
40
+ if (!menuEl || !menuEl.offsetParent) {
41
+ return defaultState;
42
+ }
43
+
44
+ // we can't trust `scrollParent.scrollHeight` --> it may increase when
45
+ // the menu is rendered
46
+ const {
47
+ height: scrollHeight,
48
+ top: scrollParentTop
49
+ } = scrollParent.getBoundingClientRect();
50
+ const {
51
+ bottom: menuBottom,
52
+ height: menuHeight,
53
+ top: menuTop
54
+ } = menuEl.getBoundingClientRect();
55
+ const {
56
+ top: containerTop
57
+ } = menuEl.offsetParent.getBoundingClientRect();
58
+ const viewHeight = isFixedPosition ? window.innerHeight : normalizedHeight(scrollParent);
59
+ const scrollTop = getScrollTop(scrollParent);
60
+ // use menuTop - scrollParentTop for the actual top space of menu in the scroll container
61
+ const menuTopFromParent = fg('design-system-select-fix-placement') ? menuTop - scrollParentTop : menuTop;
62
+ const marginBottom = parseInt(getComputedStyle(menuEl).marginBottom, 10);
63
+ const marginTop = parseInt(getComputedStyle(menuEl).marginTop, 10);
64
+ const viewSpaceAbove = containerTop - marginTop;
65
+ const viewSpaceBelow = viewHeight - menuTopFromParent;
66
+ const scrollSpaceAbove = viewSpaceAbove + scrollTop;
67
+ const scrollSpaceBelow = scrollHeight - scrollTop - menuTopFromParent;
68
+ const scrollDown = menuBottom - viewHeight + scrollTop + marginBottom;
69
+ const scrollUp = scrollTop + menuTop - marginTop;
70
+ const scrollDuration = 160;
71
+ switch (preferredPlacement) {
72
+ case 'auto':
73
+ case 'bottom':
74
+ // 1: the menu will fit, do nothing
75
+ if (viewSpaceBelow >= menuHeight) {
76
+ return {
77
+ placement: 'bottom',
78
+ maxHeight: preferredMaxHeight
79
+ };
80
+ }
81
+
82
+ // 2: the menu will fit, if scrolled
83
+ if (scrollSpaceBelow >= menuHeight && !isFixedPosition) {
84
+ if (shouldScroll) {
85
+ animatedScrollTo(scrollParent, scrollDown, scrollDuration);
86
+ }
87
+ return {
88
+ placement: 'bottom',
89
+ maxHeight: preferredMaxHeight
90
+ };
91
+ }
92
+
93
+ // 3: the menu will fit, if constrained
94
+ if (!isFixedPosition && scrollSpaceBelow >= minHeight || isFixedPosition && viewSpaceBelow >= minHeight) {
95
+ if (shouldScroll) {
96
+ animatedScrollTo(scrollParent, scrollDown, scrollDuration);
97
+ }
98
+
99
+ // we want to provide as much of the menu as possible to the user,
100
+ // so give them whatever is available below rather than the minHeight.
101
+ const constrainedHeight = isFixedPosition ? viewSpaceBelow - marginBottom : scrollSpaceBelow - marginBottom;
102
+ return {
103
+ placement: 'bottom',
104
+ maxHeight: constrainedHeight
105
+ };
106
+ }
107
+
108
+ // 4. Forked beviour when there isn't enough space below
109
+
110
+ // AUTO: flip the menu, render above
111
+ if (preferredPlacement === 'auto' || isFixedPosition) {
112
+ // may need to be constrained after flipping
113
+ let constrainedHeight = preferredMaxHeight;
114
+ const spaceAbove = isFixedPosition ? viewSpaceAbove : scrollSpaceAbove;
115
+ if (spaceAbove >= minHeight) {
116
+ constrainedHeight = Math.min(spaceAbove - marginBottom - controlHeight, preferredMaxHeight);
117
+ }
118
+ return {
119
+ placement: 'top',
120
+ maxHeight: constrainedHeight
121
+ };
122
+ }
123
+
124
+ // BOTTOM: allow browser to increase scrollable area and immediately set scroll
125
+ if (preferredPlacement === 'bottom') {
126
+ if (shouldScroll) {
127
+ scrollTo(scrollParent, scrollDown);
128
+ }
129
+ return {
130
+ placement: 'bottom',
131
+ maxHeight: preferredMaxHeight
132
+ };
133
+ }
134
+ break;
135
+ case 'top':
136
+ // 1: the menu will fit, do nothing
137
+ if (viewSpaceAbove >= menuHeight) {
138
+ return {
139
+ placement: 'top',
140
+ maxHeight: preferredMaxHeight
141
+ };
142
+ }
143
+
144
+ // 2: the menu will fit, if scrolled
145
+ if (scrollSpaceAbove >= menuHeight && !isFixedPosition) {
146
+ if (shouldScroll) {
147
+ animatedScrollTo(scrollParent, scrollUp, scrollDuration);
148
+ }
149
+ return {
150
+ placement: 'top',
151
+ maxHeight: preferredMaxHeight
152
+ };
153
+ }
154
+
155
+ // 3: the menu will fit, if constrained
156
+ if (!isFixedPosition && scrollSpaceAbove >= minHeight || isFixedPosition && viewSpaceAbove >= minHeight) {
157
+ let constrainedHeight = preferredMaxHeight;
158
+
159
+ // we want to provide as much of the menu as possible to the user,
160
+ // so give them whatever is available below rather than the minHeight.
161
+ if (!isFixedPosition && scrollSpaceAbove >= minHeight || isFixedPosition && viewSpaceAbove >= minHeight) {
162
+ constrainedHeight = isFixedPosition ? viewSpaceAbove - marginTop : scrollSpaceAbove - marginTop;
163
+ }
164
+ if (shouldScroll) {
165
+ animatedScrollTo(scrollParent, scrollUp, scrollDuration);
166
+ }
167
+ return {
168
+ placement: 'top',
169
+ maxHeight: constrainedHeight
170
+ };
171
+ }
172
+
173
+ // 4. not enough space, the browser WILL NOT increase scrollable area when
174
+ // absolutely positioned element rendered above the viewport (only below).
175
+ // Flip the menu, render below
176
+ return {
177
+ placement: 'bottom',
178
+ maxHeight: preferredMaxHeight
179
+ };
180
+ default:
181
+ throw new Error(`Invalid placement provided "${preferredPlacement}".`);
182
+ }
183
+ return defaultState;
184
+ }
185
+
186
+ // Menu Component
187
+ // ------------------------------
188
+
189
+ function alignToControl(placement) {
190
+ const placementToCSSProp = {
191
+ bottom: 'top',
192
+ top: 'bottom'
193
+ };
194
+ return placement ? placementToCSSProp[placement] : 'bottom';
195
+ }
196
+ const coercePlacement = p => p === 'auto' ? 'bottom' : p;
197
+ export const menuCSS = ({
198
+ placement
199
+ }) => ({
200
+ label: 'menu',
201
+ [alignToControl(placement)]: '100%',
202
+ position: 'absolute',
203
+ width: '100%',
204
+ zIndex: 1,
205
+ borderRadius: "var(--ds-border-radius, 4px)",
206
+ marginBottom: "var(--ds-space-100, 8px)",
207
+ marginTop: "var(--ds-space-100, 8px)",
208
+ backgroundColor: "var(--ds-surface-overlay, white)",
209
+ boxShadow: "var(--ds-shadow-overlay, 0 0 0 1px hsl(0deg 0% 0% / 10%), 0 4px 11px hsl(0deg 0% 0% / 10%))"
210
+ });
211
+ const PortalPlacementContext = /*#__PURE__*/createContext(null);
212
+
213
+ // NOTE: internal only
214
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
215
+ export const MenuPlacer = props => {
216
+ const {
217
+ children,
218
+ minMenuHeight,
219
+ maxMenuHeight,
220
+ menuPlacement,
221
+ menuPosition,
222
+ menuShouldScrollIntoView
223
+ } = props;
224
+ const {
225
+ setPortalPlacement
226
+ } = useContext(PortalPlacementContext) || {};
227
+ const ref = useRef(null);
228
+ const [maxHeight, setMaxHeight] = useState(maxMenuHeight);
229
+ const [placement, setPlacement] = useState(null);
230
+ // The minimum height of the control
231
+ const controlHeight = 38;
232
+ useLayoutEffect(() => {
233
+ const menuEl = ref.current;
234
+ if (!menuEl) {
235
+ return;
236
+ }
237
+
238
+ // DO NOT scroll if position is fixed
239
+ const isFixedPosition = menuPosition === 'fixed';
240
+ const shouldScroll = menuShouldScrollIntoView && !isFixedPosition;
241
+ const state = getMenuPlacement({
242
+ maxHeight: maxMenuHeight,
243
+ menuEl,
244
+ minHeight: minMenuHeight,
245
+ placement: menuPlacement,
246
+ shouldScroll,
247
+ isFixedPosition,
248
+ controlHeight
249
+ });
250
+ setMaxHeight(state.maxHeight);
251
+ setPlacement(state.placement);
252
+ setPortalPlacement === null || setPortalPlacement === void 0 ? void 0 : setPortalPlacement(state.placement);
253
+ }, [maxMenuHeight, menuPlacement, menuPosition, menuShouldScrollIntoView, minMenuHeight, setPortalPlacement, controlHeight]);
254
+ return children({
255
+ ref,
256
+ placerProps: {
257
+ ...props,
258
+ placement: placement || coercePlacement(menuPlacement),
259
+ maxHeight
260
+ }
261
+ });
262
+ };
263
+ const Menu = props => {
264
+ const {
265
+ children,
266
+ innerRef,
267
+ innerProps
268
+ } = props;
269
+ return jsx("div", _extends({}, getStyleProps(props, 'menu', {
270
+ menu: true
271
+ }), {
272
+ ref: innerRef
273
+ }, innerProps), children);
274
+ };
275
+
276
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
277
+ export default Menu;
278
+
279
+ // ==============================
280
+ // Menu List
281
+ // ==============================
282
+
283
+ export const menuListCSS = ({
284
+ maxHeight
285
+ }) => ({
286
+ maxHeight,
287
+ overflowY: 'auto',
288
+ position: 'relative',
289
+ // required for offset[Height, Top] > keyboard scroll
290
+ WebkitOverflowScrolling: 'touch',
291
+ paddingTop: "var(--ds-space-100, 8px)",
292
+ paddingBottom: "var(--ds-space-100, 8px)"
293
+ });
294
+
295
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
296
+ export const MenuList = props => {
297
+ const {
298
+ children,
299
+ innerProps,
300
+ innerRef,
301
+ isMulti
302
+ } = props;
303
+ return jsx("div", _extends({}, getStyleProps(props, 'menuList', {
304
+ 'menu-list': true,
305
+ 'menu-list--is-multi': isMulti
306
+ }), {
307
+ ref: innerRef
308
+ }, innerProps, {
309
+ tabIndex: -1
310
+ }), children);
311
+ };
312
+
313
+ // ==============================
314
+ // Menu Notices
315
+ // ==============================
316
+
317
+ const noticeCSS = ({}) => ({
318
+ textAlign: 'center',
319
+ padding: `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-150, 12px)"}`
320
+ });
321
+ export const noOptionsMessageCSS = noticeCSS;
322
+ export const loadingMessageCSS = noticeCSS;
323
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
324
+ export const NoOptionsMessage = ({
325
+ children = 'No options',
326
+ innerProps,
327
+ ...restProps
328
+ }) => {
329
+ return jsx("div", _extends({}, getStyleProps({
330
+ ...restProps,
331
+ children,
332
+ innerProps
333
+ }, 'noOptionsMessage', {
334
+ 'menu-notice': true,
335
+ 'menu-notice--no-options': true
336
+ }), {
337
+ // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
338
+ role: "option"
339
+ }, innerProps), jsx(Text, {
340
+ color: "color.text.subtle"
341
+ }, children));
342
+ };
343
+
344
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
345
+ export const LoadingMessage = ({
346
+ children = 'Loading...',
347
+ innerProps,
348
+ ...restProps
349
+ }) => {
350
+ return jsx("div", _extends({}, getStyleProps({
351
+ ...restProps,
352
+ children,
353
+ innerProps
354
+ }, 'loadingMessage', {
355
+ 'menu-notice': true,
356
+ 'menu-notice--loading': true
357
+ }), innerProps, {
358
+ // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
359
+ role: "option"
360
+ }), jsx(Text, {
361
+ color: "color.text.subtle"
362
+ }, children));
363
+ };
364
+
365
+ // ==============================
366
+ // Menu Portal
367
+ // ==============================
368
+
369
+ export const menuPortalCSS = ({
370
+ rect,
371
+ offset,
372
+ position
373
+ }) => ({
374
+ left: rect.left,
375
+ position: position,
376
+ top: offset,
377
+ width: rect.width,
378
+ zIndex: 1
379
+ });
380
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
381
+ export const MenuPortal = props => {
382
+ const {
383
+ appendTo,
384
+ children,
385
+ controlElement,
386
+ innerProps,
387
+ menuPlacement,
388
+ menuPosition
389
+ } = props;
390
+ const menuPortalRef = useRef(null);
391
+ const cleanupRef = useRef(null);
392
+ const [placement, setPortalPlacement] = useState(coercePlacement(menuPlacement));
393
+ const portalPlacementContext = useMemo(() => ({
394
+ setPortalPlacement
395
+ }), []);
396
+ const [computedPosition, setComputedPosition] = useState(null);
397
+ const updateComputedPosition = useCallback(() => {
398
+ if (!controlElement) {
399
+ return;
400
+ }
401
+ const rect = getBoundingClientObj(controlElement);
402
+ const scrollDistance = menuPosition === 'fixed' ? 0 : window.pageYOffset;
403
+ const offset = rect[placement] + scrollDistance;
404
+ if (offset !== (computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.offset) || rect.left !== (computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.left) || rect.width !== (computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.width)) {
405
+ setComputedPosition({
406
+ offset,
407
+ rect
408
+ });
409
+ }
410
+ }, [controlElement, menuPosition, placement, computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.offset, computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.left, computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.width]);
411
+ useLayoutEffect(() => {
412
+ updateComputedPosition();
413
+ }, [updateComputedPosition]);
414
+ const runAutoUpdate = useCallback(() => {
415
+ if (typeof cleanupRef.current === 'function') {
416
+ cleanupRef.current();
417
+ cleanupRef.current = null;
418
+ }
419
+ if (controlElement && menuPortalRef.current) {
420
+ cleanupRef.current = autoUpdate(controlElement, menuPortalRef.current, updateComputedPosition, {
421
+ elementResize: 'ResizeObserver' in window
422
+ });
423
+ }
424
+ }, [controlElement, updateComputedPosition]);
425
+ useLayoutEffect(() => {
426
+ runAutoUpdate();
427
+ }, [runAutoUpdate]);
428
+ const setMenuPortalElement = useCallback(menuPortalElement => {
429
+ menuPortalRef.current = menuPortalElement;
430
+ runAutoUpdate();
431
+ }, [runAutoUpdate]);
432
+
433
+ // bail early if required elements aren't present
434
+ if (!appendTo && menuPosition !== 'fixed' || !computedPosition) {
435
+ return null;
436
+ }
437
+
438
+ // same wrapper element whether fixed or portalled
439
+ const menuWrapper = jsx("div", _extends({
440
+ ref: setMenuPortalElement
441
+ }, getStyleProps({
442
+ ...props,
443
+ offset: computedPosition.offset,
444
+ position: menuPosition,
445
+ rect: computedPosition.rect
446
+ }, 'menuPortal', {
447
+ 'menu-portal': true
448
+ }), innerProps), children);
449
+ return jsx(PortalPlacementContext.Provider, {
450
+ value: portalPlacementContext
451
+ }, appendTo ? /*#__PURE__*/createPortal(menuWrapper, appendTo) : menuWrapper);
452
+ };