@atlaskit/select 17.11.8 → 17.11.9

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/select
2
2
 
3
+ ## 17.11.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#124328](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/124328)
8
+ [`69cea8c513faa`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/69cea8c513faa) -
9
+ Add announcement of focused option for the first open of Popup select
10
+
3
11
  ## 17.11.8
4
12
 
5
13
  ### Patch Changes
@@ -28,6 +28,7 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
28
28
  var _colors = require("@atlaskit/theme/colors");
29
29
  var _Select = _interopRequireDefault(require("../Select"));
30
30
  var _styles = _interopRequireDefault(require("../styles"));
31
+ var _groupedOptionsAnnouncement = require("../utils/grouped-options-announcement");
31
32
  var _components = require("./components");
32
33
  var _excluded = ["footer", "label", "maxMenuWidth", "minMenuWidth", "placeholder", "target", "testId"];
33
34
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
@@ -333,6 +334,51 @@ var PopupSelect = exports.default = /*#__PURE__*/function (_PureComponent) {
333
334
  }
334
335
  };
335
336
  var InternalSelect = (0, _platformFeatureFlags.fg)('platform.design-system-team.use-default-select-in-popup-select_46rmj') ? _Select.default : _reactSelect.default;
337
+ var providedAriaLabel = getLabel();
338
+ var updateInputAriaLabel = function updateInputAriaLabel(ariaLabelText) {
339
+ var _this$selectRef, _this$selectRef2;
340
+ // Update aria-label to get first announcement when popup opened.
341
+ if ((_this$selectRef = _this.selectRef) !== null && _this$selectRef !== void 0 && (_this$selectRef = _this$selectRef.select) !== null && _this$selectRef !== void 0 && _this$selectRef.inputRef || (_this$selectRef2 = _this.selectRef) !== null && _this$selectRef2 !== void 0 && _this$selectRef2.inputRef) {
342
+ var _this$selectRef3, _this$selectRef4;
343
+ if (providedAriaLabel) {
344
+ ariaLabelText = "".concat(providedAriaLabel, ". ").concat(ariaLabelText);
345
+ }
346
+ (0, _platformFeatureFlags.fg)('platform.design-system-team.use-default-select-in-popup-select_46rmj') ? (_this$selectRef3 = _this.selectRef) === null || _this$selectRef3 === void 0 || (_this$selectRef3 = _this$selectRef3.select.inputRef) === null || _this$selectRef3 === void 0 ? void 0 : _this$selectRef3.setAttribute('aria-label', ariaLabelText) : (_this$selectRef4 = _this.selectRef) === null || _this$selectRef4 === void 0 || (_this$selectRef4 = _this$selectRef4.inputRef) === null || _this$selectRef4 === void 0 ? void 0 : _this$selectRef4.setAttribute('aria-label', ariaLabelText);
347
+ }
348
+ };
349
+ var generateNoGroupsAriaText = function generateNoGroupsAriaText(onFocusProps, ariaLabelSuffix) {
350
+ var _options$findIndex;
351
+ var focused = onFocusProps.focused;
352
+ var options = (props === null || props === void 0 ? void 0 : props.options) || [];
353
+ var totalLength = (options === null || options === void 0 ? void 0 : options.length) + 1;
354
+ var optionIndex = (_options$findIndex = options === null || options === void 0 ? void 0 : options.findIndex(function (option) {
355
+ return option === focused;
356
+ })) !== null && _options$findIndex !== void 0 ? _options$findIndex : 0;
357
+ var optionName = typeof (props === null || props === void 0 ? void 0 : props.getOptionLabel) === 'function' ? props.getOptionLabel(focused) : focused.label;
358
+ var ariaLabelText = "Option ".concat(optionName, " focused, ").concat(optionIndex, " of ").concat(totalLength, ".\n\t\t\t").concat(totalLength, " results available.\n\t\t\t").concat(ariaLabelSuffix, "\n\t\t\t");
359
+ // Option LABEL focused, 1 of 8. 8 results available.
360
+ // Use Up and Down to choose options, press Enter to select the currently focused option,
361
+ // press Escape to exit the menu.
362
+ return ariaLabelText;
363
+ };
364
+ var onReactSelectFocus = function onReactSelectFocus(onFocusProps) {
365
+ var _props$options;
366
+ var ariaLabelSuffix = ' Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu.';
367
+ var ariaLabelText = '';
368
+ var ariaLiveMessage = '';
369
+ if ((_props$options = props.options) !== null && _props$options !== void 0 && _props$options.length) {
370
+ if ((0, _groupedOptionsAnnouncement.isOptionsGrouped)(props.options)) {
371
+ var totalLength = (0, _groupedOptionsAnnouncement.countAllOptions)(props.options);
372
+ ariaLiveMessage = (0, _groupedOptionsAnnouncement.onFocus)(onFocusProps);
373
+ ariaLabelText = "".concat(ariaLiveMessage, " ").concat(totalLength, " results available. ").concat(ariaLabelSuffix);
374
+ } else {
375
+ ariaLabelText = generateNoGroupsAriaText(onFocusProps, ariaLabelSuffix);
376
+ ariaLiveMessage = ariaLabelText;
377
+ }
378
+ updateInputAriaLabel(ariaLabelText);
379
+ return ariaLiveMessage;
380
+ }
381
+ };
336
382
  var popper = /*#__PURE__*/_react.default.createElement(_reactPopper.Popper, (0, _extends2.default)({}, mergedPopperProps, {
337
383
  onFirstUpdate: function onFirstUpdate(state) {
338
384
  var _mergedPopperProps$on;
@@ -358,7 +404,7 @@ var PopupSelect = exports.default = /*#__PURE__*/function (_PureComponent) {
358
404
  disabled: !focusLockEnabled,
359
405
  returnFocus: true
360
406
  }, /*#__PURE__*/_react.default.createElement(InternalSelect, (0, _extends2.default)({
361
- "aria-label": getLabel(),
407
+ "aria-label": providedAriaLabel,
362
408
  backspaceRemovesValue: false,
363
409
  controlShouldRenderValue: false,
364
410
  isClearable: false,
@@ -373,7 +419,11 @@ var PopupSelect = exports.default = /*#__PURE__*/function (_PureComponent) {
373
419
  styles: (0, _reactSelect.mergeStyles)(_this.defaultStyles, props.styles || {}),
374
420
  maxMenuHeight: _this.getMaxHeight(),
375
421
  components: selectComponents,
376
- onChange: _this.handleSelectChange
422
+ onChange: _this.handleSelectChange,
423
+ ariaLiveMessages: !showSearchControl ? _objectSpread({
424
+ // Overwriting ariaLiveMessages builtin onFocus method to announce selected option when popup has been opened
425
+ onFocus: onReactSelectFocus
426
+ }, props.ariaLiveMessages) : props.ariaLiveMessages
377
427
  })), footer)));
378
428
  });
379
429
  return mergedPopperProps.strategy === 'fixed' ? popper : /*#__PURE__*/(0, _reactDom.createPortal)(popper, portalDestination);
@@ -9,7 +9,7 @@ var _reactSelect = _interopRequireDefault(require("react-select"));
9
9
  var _analyticsNext = require("@atlaskit/analytics-next");
10
10
  var _createSelect = _interopRequireDefault(require("./createSelect"));
11
11
  var packageName = "@atlaskit/select";
12
- var packageVersion = "17.11.8";
12
+ var packageVersion = "17.11.9";
13
13
  var SelectWithoutAnalytics = exports.SelectWithoutAnalytics = (0, _createSelect.default)(_reactSelect.default);
14
14
  var createAndFireEventOnAtlaskit = (0, _analyticsNext.createAndFireEvent)('atlaskit');
15
15
  var Select = (0, _analyticsNext.withAnalyticsContext)({
@@ -11,9 +11,9 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
11
11
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
12
12
  var _react = _interopRequireWildcard(require("react"));
13
13
  var _reactSelect = require("react-select");
14
+ var _components = require("./components");
14
15
  var _inputAriaDescribedby = require("./components/input-aria-describedby");
15
16
  var _noOptions = require("./components/no-options");
16
- var _components = require("./components");
17
17
  var _styles = _interopRequireDefault(require("./styles"));
18
18
  var _groupedOptionsAnnouncement = require("./utils/grouped-options-announcement");
19
19
  var _excluded = ["appearance", "ariaLiveMessages", "components", "isInvalid", "onClickPreventDefault", "spacing", "styles", "tabSelectsValue", "validationState"];
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isOptionsGrouped = void 0;
6
+ exports.isOptionsGrouped = exports.countAllOptions = void 0;
7
7
  exports.onFocus = onFocus;
8
8
  // Used for overwriting ariaLiveMessages builtin onFocus method.
9
9
  // Returns custom built string while focusing each group option. This string is used for screen reader announcement.
@@ -27,4 +27,15 @@ var isOptionsGrouped = exports.isOptionsGrouped = function isOptionsGrouped(arr)
27
27
  return arr === null || arr === void 0 ? void 0 : arr.every(function (obj) {
28
28
  return obj.hasOwnProperty('options');
29
29
  });
30
+ };
31
+
32
+ // Helper function which calculates how many options are in total in all groups.
33
+ var countAllOptions = exports.countAllOptions = function countAllOptions(groupsArray) {
34
+ var totalLength = groupsArray === null || groupsArray === void 0 ? void 0 : groupsArray.reduce(function (acc, currentGroup) {
35
+ var _group$options;
36
+ var group = currentGroup;
37
+ acc += group === null || group === void 0 || (_group$options = group.options) === null || _group$options === void 0 ? void 0 : _group$options.length;
38
+ return acc;
39
+ }, 0);
40
+ return totalLength;
30
41
  };
@@ -13,6 +13,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
13
13
  import { N80 } from '@atlaskit/theme/colors';
14
14
  import DefaultSelect from '../Select';
15
15
  import baseStyles from '../styles';
16
+ import { countAllOptions, isOptionsGrouped, onFocus } from '../utils/grouped-options-announcement';
16
17
  import { defaultComponents, DummyControl, MenuDialog } from './components';
17
18
  /**
18
19
  * Are we rendering on the client or server?
@@ -309,6 +310,54 @@ export default class PopupSelect extends PureComponent {
309
310
  }
310
311
  };
311
312
  const InternalSelect = fg('platform.design-system-team.use-default-select-in-popup-select_46rmj') ? DefaultSelect : Select;
313
+ const providedAriaLabel = getLabel();
314
+ const updateInputAriaLabel = ariaLabelText => {
315
+ var _this$selectRef, _this$selectRef$selec3, _this$selectRef2;
316
+ // Update aria-label to get first announcement when popup opened.
317
+ if ((_this$selectRef = this.selectRef) !== null && _this$selectRef !== void 0 && (_this$selectRef$selec3 = _this$selectRef.select) !== null && _this$selectRef$selec3 !== void 0 && _this$selectRef$selec3.inputRef || (_this$selectRef2 = this.selectRef) !== null && _this$selectRef2 !== void 0 && _this$selectRef2.inputRef) {
318
+ var _this$selectRef3, _this$selectRef3$sele, _this$selectRef4, _this$selectRef4$inpu;
319
+ if (providedAriaLabel) {
320
+ ariaLabelText = `${providedAriaLabel}. ${ariaLabelText}`;
321
+ }
322
+ fg('platform.design-system-team.use-default-select-in-popup-select_46rmj') ? (_this$selectRef3 = this.selectRef) === null || _this$selectRef3 === void 0 ? void 0 : (_this$selectRef3$sele = _this$selectRef3.select.inputRef) === null || _this$selectRef3$sele === void 0 ? void 0 : _this$selectRef3$sele.setAttribute('aria-label', ariaLabelText) : (_this$selectRef4 = this.selectRef) === null || _this$selectRef4 === void 0 ? void 0 : (_this$selectRef4$inpu = _this$selectRef4.inputRef) === null || _this$selectRef4$inpu === void 0 ? void 0 : _this$selectRef4$inpu.setAttribute('aria-label', ariaLabelText);
323
+ }
324
+ };
325
+ const generateNoGroupsAriaText = (onFocusProps, ariaLabelSuffix) => {
326
+ var _options$findIndex;
327
+ const {
328
+ focused
329
+ } = onFocusProps;
330
+ const options = (props === null || props === void 0 ? void 0 : props.options) || [];
331
+ const totalLength = (options === null || options === void 0 ? void 0 : options.length) + 1;
332
+ const optionIndex = (_options$findIndex = options === null || options === void 0 ? void 0 : options.findIndex(option => option === focused)) !== null && _options$findIndex !== void 0 ? _options$findIndex : 0;
333
+ const optionName = typeof (props === null || props === void 0 ? void 0 : props.getOptionLabel) === 'function' ? props.getOptionLabel(focused) : focused.label;
334
+ const ariaLabelText = `Option ${optionName} focused, ${optionIndex} of ${totalLength}.
335
+ ${totalLength} results available.
336
+ ${ariaLabelSuffix}
337
+ `;
338
+ // Option LABEL focused, 1 of 8. 8 results available.
339
+ // Use Up and Down to choose options, press Enter to select the currently focused option,
340
+ // press Escape to exit the menu.
341
+ return ariaLabelText;
342
+ };
343
+ const onReactSelectFocus = onFocusProps => {
344
+ var _props$options;
345
+ const ariaLabelSuffix = ' Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu.';
346
+ let ariaLabelText = '';
347
+ let ariaLiveMessage = '';
348
+ if ((_props$options = props.options) !== null && _props$options !== void 0 && _props$options.length) {
349
+ if (isOptionsGrouped(props.options)) {
350
+ const totalLength = countAllOptions(props.options);
351
+ ariaLiveMessage = onFocus(onFocusProps);
352
+ ariaLabelText = `${ariaLiveMessage} ${totalLength} results available. ${ariaLabelSuffix}`;
353
+ } else {
354
+ ariaLabelText = generateNoGroupsAriaText(onFocusProps, ariaLabelSuffix);
355
+ ariaLiveMessage = ariaLabelText;
356
+ }
357
+ updateInputAriaLabel(ariaLabelText);
358
+ return ariaLiveMessage;
359
+ }
360
+ };
312
361
  const popper = /*#__PURE__*/React.createElement(Popper, _extends({}, mergedPopperProps, {
313
362
  onFirstUpdate: state => {
314
363
  var _mergedPopperProps$on;
@@ -334,7 +383,7 @@ export default class PopupSelect extends PureComponent {
334
383
  disabled: !focusLockEnabled,
335
384
  returnFocus: true
336
385
  }, /*#__PURE__*/React.createElement(InternalSelect, _extends({
337
- "aria-label": getLabel(),
386
+ "aria-label": providedAriaLabel,
338
387
  backspaceRemovesValue: false,
339
388
  controlShouldRenderValue: false,
340
389
  isClearable: false,
@@ -349,7 +398,12 @@ export default class PopupSelect extends PureComponent {
349
398
  styles: mergeStyles(this.defaultStyles, props.styles || {}),
350
399
  maxMenuHeight: this.getMaxHeight(),
351
400
  components: selectComponents,
352
- onChange: this.handleSelectChange
401
+ onChange: this.handleSelectChange,
402
+ ariaLiveMessages: !showSearchControl ? {
403
+ // Overwriting ariaLiveMessages builtin onFocus method to announce selected option when popup has been opened
404
+ onFocus: onReactSelectFocus,
405
+ ...props.ariaLiveMessages // priority to use user handlers if provided
406
+ } : props.ariaLiveMessages
353
407
  })), footer))));
354
408
  return mergedPopperProps.strategy === 'fixed' ? popper : /*#__PURE__*/createPortal(popper, portalDestination);
355
409
  });
@@ -2,7 +2,7 @@ import ReactSelect from 'react-select';
2
2
  import { withAnalyticsEvents, withAnalyticsContext, createAndFireEvent } from '@atlaskit/analytics-next';
3
3
  import createSelect from './createSelect';
4
4
  const packageName = "@atlaskit/select";
5
- const packageVersion = "17.11.8";
5
+ const packageVersion = "17.11.9";
6
6
  export const SelectWithoutAnalytics = createSelect(ReactSelect);
7
7
  const createAndFireEventOnAtlaskit = createAndFireEvent('atlaskit');
8
8
  const Select = withAnalyticsContext({
@@ -1,11 +1,11 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React, { useRef, useEffect, useMemo, forwardRef, useImperativeHandle } from 'react';
2
+ import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
3
3
  import { mergeStyles } from 'react-select';
4
+ import { ClearIndicator, DropdownIndicator, IndicatorSeparator, LoadingIndicator, MultiValueRemove } from './components';
4
5
  import { Input } from './components/input-aria-describedby';
5
6
  import { NoOptionsMessage } from './components/no-options';
6
- import { ClearIndicator, DropdownIndicator, LoadingIndicator, MultiValueRemove, IndicatorSeparator } from './components';
7
7
  import baseStyles from './styles';
8
- import { onFocus, isOptionsGrouped } from './utils/grouped-options-announcement';
8
+ import { isOptionsGrouped, onFocus } from './utils/grouped-options-announcement';
9
9
  export default function createSelect(WrappedComponent) {
10
10
  const AtlaskitSelect = /*#__PURE__*/forwardRef(function AtlaskitSelect(props, forwardedRef) {
11
11
  const {
@@ -20,4 +20,15 @@ export function onFocus(props) {
20
20
  // Helper function which identifies if options are grouped.
21
21
  export const isOptionsGrouped = arr => {
22
22
  return arr === null || arr === void 0 ? void 0 : arr.every(obj => obj.hasOwnProperty('options'));
23
+ };
24
+
25
+ // Helper function which calculates how many options are in total in all groups.
26
+ export const countAllOptions = groupsArray => {
27
+ const totalLength = groupsArray === null || groupsArray === void 0 ? void 0 : groupsArray.reduce((acc, currentGroup) => {
28
+ var _group$options;
29
+ const group = currentGroup;
30
+ acc += group === null || group === void 0 ? void 0 : (_group$options = group.options) === null || _group$options === void 0 ? void 0 : _group$options.length;
31
+ return acc;
32
+ }, 0);
33
+ return totalLength;
23
34
  };
@@ -25,6 +25,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
25
25
  import { N80 } from '@atlaskit/theme/colors';
26
26
  import DefaultSelect from '../Select';
27
27
  import baseStyles from '../styles';
28
+ import { countAllOptions, isOptionsGrouped, onFocus } from '../utils/grouped-options-announcement';
28
29
  import { defaultComponents, DummyControl, MenuDialog } from './components';
29
30
  /**
30
31
  * Are we rendering on the client or server?
@@ -323,6 +324,51 @@ var PopupSelect = /*#__PURE__*/function (_PureComponent) {
323
324
  }
324
325
  };
325
326
  var InternalSelect = fg('platform.design-system-team.use-default-select-in-popup-select_46rmj') ? DefaultSelect : Select;
327
+ var providedAriaLabel = getLabel();
328
+ var updateInputAriaLabel = function updateInputAriaLabel(ariaLabelText) {
329
+ var _this$selectRef, _this$selectRef2;
330
+ // Update aria-label to get first announcement when popup opened.
331
+ if ((_this$selectRef = _this.selectRef) !== null && _this$selectRef !== void 0 && (_this$selectRef = _this$selectRef.select) !== null && _this$selectRef !== void 0 && _this$selectRef.inputRef || (_this$selectRef2 = _this.selectRef) !== null && _this$selectRef2 !== void 0 && _this$selectRef2.inputRef) {
332
+ var _this$selectRef3, _this$selectRef4;
333
+ if (providedAriaLabel) {
334
+ ariaLabelText = "".concat(providedAriaLabel, ". ").concat(ariaLabelText);
335
+ }
336
+ fg('platform.design-system-team.use-default-select-in-popup-select_46rmj') ? (_this$selectRef3 = _this.selectRef) === null || _this$selectRef3 === void 0 || (_this$selectRef3 = _this$selectRef3.select.inputRef) === null || _this$selectRef3 === void 0 ? void 0 : _this$selectRef3.setAttribute('aria-label', ariaLabelText) : (_this$selectRef4 = _this.selectRef) === null || _this$selectRef4 === void 0 || (_this$selectRef4 = _this$selectRef4.inputRef) === null || _this$selectRef4 === void 0 ? void 0 : _this$selectRef4.setAttribute('aria-label', ariaLabelText);
337
+ }
338
+ };
339
+ var generateNoGroupsAriaText = function generateNoGroupsAriaText(onFocusProps, ariaLabelSuffix) {
340
+ var _options$findIndex;
341
+ var focused = onFocusProps.focused;
342
+ var options = (props === null || props === void 0 ? void 0 : props.options) || [];
343
+ var totalLength = (options === null || options === void 0 ? void 0 : options.length) + 1;
344
+ var optionIndex = (_options$findIndex = options === null || options === void 0 ? void 0 : options.findIndex(function (option) {
345
+ return option === focused;
346
+ })) !== null && _options$findIndex !== void 0 ? _options$findIndex : 0;
347
+ var optionName = typeof (props === null || props === void 0 ? void 0 : props.getOptionLabel) === 'function' ? props.getOptionLabel(focused) : focused.label;
348
+ var ariaLabelText = "Option ".concat(optionName, " focused, ").concat(optionIndex, " of ").concat(totalLength, ".\n\t\t\t").concat(totalLength, " results available.\n\t\t\t").concat(ariaLabelSuffix, "\n\t\t\t");
349
+ // Option LABEL focused, 1 of 8. 8 results available.
350
+ // Use Up and Down to choose options, press Enter to select the currently focused option,
351
+ // press Escape to exit the menu.
352
+ return ariaLabelText;
353
+ };
354
+ var onReactSelectFocus = function onReactSelectFocus(onFocusProps) {
355
+ var _props$options;
356
+ var ariaLabelSuffix = ' Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu.';
357
+ var ariaLabelText = '';
358
+ var ariaLiveMessage = '';
359
+ if ((_props$options = props.options) !== null && _props$options !== void 0 && _props$options.length) {
360
+ if (isOptionsGrouped(props.options)) {
361
+ var totalLength = countAllOptions(props.options);
362
+ ariaLiveMessage = onFocus(onFocusProps);
363
+ ariaLabelText = "".concat(ariaLiveMessage, " ").concat(totalLength, " results available. ").concat(ariaLabelSuffix);
364
+ } else {
365
+ ariaLabelText = generateNoGroupsAriaText(onFocusProps, ariaLabelSuffix);
366
+ ariaLiveMessage = ariaLabelText;
367
+ }
368
+ updateInputAriaLabel(ariaLabelText);
369
+ return ariaLiveMessage;
370
+ }
371
+ };
326
372
  var popper = /*#__PURE__*/React.createElement(Popper, _extends({}, mergedPopperProps, {
327
373
  onFirstUpdate: function onFirstUpdate(state) {
328
374
  var _mergedPopperProps$on;
@@ -348,7 +394,7 @@ var PopupSelect = /*#__PURE__*/function (_PureComponent) {
348
394
  disabled: !focusLockEnabled,
349
395
  returnFocus: true
350
396
  }, /*#__PURE__*/React.createElement(InternalSelect, _extends({
351
- "aria-label": getLabel(),
397
+ "aria-label": providedAriaLabel,
352
398
  backspaceRemovesValue: false,
353
399
  controlShouldRenderValue: false,
354
400
  isClearable: false,
@@ -363,7 +409,11 @@ var PopupSelect = /*#__PURE__*/function (_PureComponent) {
363
409
  styles: mergeStyles(_this.defaultStyles, props.styles || {}),
364
410
  maxMenuHeight: _this.getMaxHeight(),
365
411
  components: selectComponents,
366
- onChange: _this.handleSelectChange
412
+ onChange: _this.handleSelectChange,
413
+ ariaLiveMessages: !showSearchControl ? _objectSpread({
414
+ // Overwriting ariaLiveMessages builtin onFocus method to announce selected option when popup has been opened
415
+ onFocus: onReactSelectFocus
416
+ }, props.ariaLiveMessages) : props.ariaLiveMessages
367
417
  })), footer)));
368
418
  });
369
419
  return mergedPopperProps.strategy === 'fixed' ? popper : /*#__PURE__*/createPortal(popper, portalDestination);
@@ -2,7 +2,7 @@ import ReactSelect from 'react-select';
2
2
  import { withAnalyticsEvents, withAnalyticsContext, createAndFireEvent } from '@atlaskit/analytics-next';
3
3
  import createSelect from './createSelect';
4
4
  var packageName = "@atlaskit/select";
5
- var packageVersion = "17.11.8";
5
+ var packageVersion = "17.11.9";
6
6
  export var SelectWithoutAnalytics = createSelect(ReactSelect);
7
7
  var createAndFireEventOnAtlaskit = createAndFireEvent('atlaskit');
8
8
  var Select = withAnalyticsContext({
@@ -4,13 +4,13 @@ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProper
4
4
  var _excluded = ["appearance", "ariaLiveMessages", "components", "isInvalid", "onClickPreventDefault", "spacing", "styles", "tabSelectsValue", "validationState"];
5
5
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
6
6
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
7
- import React, { useRef, useEffect, useMemo, forwardRef, useImperativeHandle } from 'react';
7
+ import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
8
8
  import { mergeStyles } from 'react-select';
9
+ import { ClearIndicator, DropdownIndicator, IndicatorSeparator, LoadingIndicator, MultiValueRemove } from './components';
9
10
  import { Input } from './components/input-aria-describedby';
10
11
  import { NoOptionsMessage } from './components/no-options';
11
- import { ClearIndicator, DropdownIndicator, LoadingIndicator, MultiValueRemove, IndicatorSeparator } from './components';
12
12
  import baseStyles from './styles';
13
- import { onFocus, isOptionsGrouped } from './utils/grouped-options-announcement';
13
+ import { isOptionsGrouped, onFocus } from './utils/grouped-options-announcement';
14
14
  export default function createSelect(WrappedComponent) {
15
15
  var AtlaskitSelect = /*#__PURE__*/forwardRef(function AtlaskitSelect(props, forwardedRef) {
16
16
  var appearance = props.appearance,
@@ -20,4 +20,15 @@ export var isOptionsGrouped = function isOptionsGrouped(arr) {
20
20
  return arr === null || arr === void 0 ? void 0 : arr.every(function (obj) {
21
21
  return obj.hasOwnProperty('options');
22
22
  });
23
+ };
24
+
25
+ // Helper function which calculates how many options are in total in all groups.
26
+ export var countAllOptions = function countAllOptions(groupsArray) {
27
+ var totalLength = groupsArray === null || groupsArray === void 0 ? void 0 : groupsArray.reduce(function (acc, currentGroup) {
28
+ var _group$options;
29
+ var group = currentGroup;
30
+ acc += group === null || group === void 0 || (_group$options = group.options) === null || _group$options === void 0 ? void 0 : _group$options.length;
31
+ return acc;
32
+ }, 0);
33
+ return totalLength;
23
34
  };
@@ -22,12 +22,11 @@ export interface PopupSelectProps<Option = OptionType, IsMulti extends boolean =
22
22
  */
23
23
  footer?: ReactNode;
24
24
  /**
25
- The props passed down to React Popper.
26
-
27
- Use these to override the default positioning strategy, behaviour and placement used by this library.
28
- For more information, see the Popper Props section below, or [React Popper documentation](https://popper.js.org/react-popper/v2/render-props).
29
-
30
- */
25
+ * The props passed down to React Popper.
26
+ *
27
+ * Use these to override the default positioning strategy, behaviour and placement used by this library.
28
+ * For more information, see the Popper Props section below, or [React Popper documentation](https://popper.js.org/react-popper/v2/render-props).
29
+ */
31
30
  popperProps?: PopperPropsNoChildren<Modifiers>;
32
31
  /**
33
32
  * The maximum number of options the select can contain without rendering the search field. The default is `5`.
@@ -49,32 +48,42 @@ export interface PopupSelectProps<Option = OptionType, IsMulti extends boolean =
49
48
  */
50
49
  minMenuWidth?: number | string;
51
50
  /**
52
- Render props used to anchor the popup to your content.
53
-
54
- Make this an interactive element, such as an @atlaskit/button component.
55
-
56
- The provided render props in `options` are detailed below:
57
- - `isOpen`: The current state of the popup.
58
- Use this to change the appearance of your target based on the state of your component
59
- - `ref`: Pass this ref to the element the Popup should be attached to
60
- - `onKeyDown`: Pass this keydown handler to the element to allow keyboard users to access the element.
61
- - `aria-haspopup`, `aria-expanded`, `aria-controls`: Spread these onto a target element to
62
- ensure your experience is accessible
63
- */
51
+ * Render props used to anchor the popup to your content.
52
+ *
53
+ * Make this an interactive element, such as an @atlaskit/button component.
54
+ *
55
+ * The provided render props in `options` are detailed below:
56
+ * - `isOpen`: The current state of the popup.
57
+ * Use this to change the appearance of your target based on the state of your component
58
+ * - `ref`: Pass this ref to the element the Popup should be attached to
59
+ * - `onKeyDown`: Pass this keydown handler to the element to allow keyboard users to access the element.
60
+ * - `aria-haspopup`, `aria-expanded`, `aria-controls`: Spread these onto a target element to
61
+ * ensure your experience is accessible
62
+ */
64
63
  target?: (options: PopupSelectTriggerProps & {
65
64
  isOpen: boolean;
66
65
  }) => ReactNode;
67
66
  isOpen?: boolean;
68
67
  defaultIsOpen?: boolean;
69
- /** Use this to set whether the component uses compact or standard spacing. */
68
+ /**
69
+ * Use this to set whether the component uses compact or standard spacing.
70
+ */
70
71
  spacing?: 'default' | 'compact';
71
- /** @deprecated Use isInvalid instead. The state of validation if used in a form */
72
+ /**
73
+ * @deprecated Use isInvalid instead. The state of validation if used in a form
74
+ */
72
75
  validationState?: ValidationState;
73
- /** This prop indicates if the component is in an error state. */
76
+ /**
77
+ * This prop indicates if the component is in an error state.
78
+ */
74
79
  isInvalid?: boolean;
75
- /** This gives an accessible name to the input for people who use assistive technology. */
80
+ /**
81
+ * This gives an accessible name to the input for people who use assistive technology.
82
+ */
76
83
  label?: string;
77
- /** The `testId` prop appears as a data attribute `data-testid` in the rendered code, serving as a hook for automated tests. It will be set on the menu element when defined: `{testId}--menu` */
84
+ /**
85
+ * The `testId` prop appears as a data attribute `data-testid` in the rendered code, serving as a hook for automated tests. It will be set on the menu element when defined: `{testId}--menu`
86
+ */
78
87
  testId?: string;
79
88
  }
80
89
  interface State<Modifiers = string> {
@@ -1,5 +1,5 @@
1
1
  import { type ComponentType, type Ref } from 'react';
2
- import { type SelectProps, type OptionType, type AsyncSelectProps, type CreatableSelectProps, type AtlaskitSelectRefType } from './types';
2
+ import { type AsyncSelectProps, type AtlaskitSelectRefType, type CreatableSelectProps, type OptionType, type SelectProps } from './types';
3
3
  type AtlaskitSelectProps<Option extends unknown, IsMulti extends boolean> = SelectProps<Option, IsMulti> | AsyncSelectProps<Option, IsMulti> | CreatableSelectProps<Option, IsMulti>;
4
4
  export default function createSelect(WrappedComponent: ComponentType<any>): <Option extends unknown = OptionType, IsMulti extends boolean = false>(props: AtlaskitSelectProps<Option, IsMulti> & {
5
5
  ref?: Ref<AtlaskitSelectRefType>;
@@ -2,3 +2,4 @@ import { type AriaOnFocusProps, type GroupBase, type OptionsOrGroups } from 'rea
2
2
  import { type GroupType, type OptionType } from '../types';
3
3
  export declare function onFocus(props: AriaOnFocusProps<OptionType, GroupBase<OptionType>>): string;
4
4
  export declare const isOptionsGrouped: (arr: OptionsOrGroups<OptionType, GroupType<OptionType>> | undefined) => boolean | undefined;
5
+ export declare const countAllOptions: (groupsArray: readonly GroupType<OptionType>[]) => number;
@@ -22,12 +22,11 @@ export interface PopupSelectProps<Option = OptionType, IsMulti extends boolean =
22
22
  */
23
23
  footer?: ReactNode;
24
24
  /**
25
- The props passed down to React Popper.
26
-
27
- Use these to override the default positioning strategy, behaviour and placement used by this library.
28
- For more information, see the Popper Props section below, or [React Popper documentation](https://popper.js.org/react-popper/v2/render-props).
29
-
30
- */
25
+ * The props passed down to React Popper.
26
+ *
27
+ * Use these to override the default positioning strategy, behaviour and placement used by this library.
28
+ * For more information, see the Popper Props section below, or [React Popper documentation](https://popper.js.org/react-popper/v2/render-props).
29
+ */
31
30
  popperProps?: PopperPropsNoChildren<Modifiers>;
32
31
  /**
33
32
  * The maximum number of options the select can contain without rendering the search field. The default is `5`.
@@ -49,32 +48,42 @@ export interface PopupSelectProps<Option = OptionType, IsMulti extends boolean =
49
48
  */
50
49
  minMenuWidth?: number | string;
51
50
  /**
52
- Render props used to anchor the popup to your content.
53
-
54
- Make this an interactive element, such as an @atlaskit/button component.
55
-
56
- The provided render props in `options` are detailed below:
57
- - `isOpen`: The current state of the popup.
58
- Use this to change the appearance of your target based on the state of your component
59
- - `ref`: Pass this ref to the element the Popup should be attached to
60
- - `onKeyDown`: Pass this keydown handler to the element to allow keyboard users to access the element.
61
- - `aria-haspopup`, `aria-expanded`, `aria-controls`: Spread these onto a target element to
62
- ensure your experience is accessible
63
- */
51
+ * Render props used to anchor the popup to your content.
52
+ *
53
+ * Make this an interactive element, such as an @atlaskit/button component.
54
+ *
55
+ * The provided render props in `options` are detailed below:
56
+ * - `isOpen`: The current state of the popup.
57
+ * Use this to change the appearance of your target based on the state of your component
58
+ * - `ref`: Pass this ref to the element the Popup should be attached to
59
+ * - `onKeyDown`: Pass this keydown handler to the element to allow keyboard users to access the element.
60
+ * - `aria-haspopup`, `aria-expanded`, `aria-controls`: Spread these onto a target element to
61
+ * ensure your experience is accessible
62
+ */
64
63
  target?: (options: PopupSelectTriggerProps & {
65
64
  isOpen: boolean;
66
65
  }) => ReactNode;
67
66
  isOpen?: boolean;
68
67
  defaultIsOpen?: boolean;
69
- /** Use this to set whether the component uses compact or standard spacing. */
68
+ /**
69
+ * Use this to set whether the component uses compact or standard spacing.
70
+ */
70
71
  spacing?: 'default' | 'compact';
71
- /** @deprecated Use isInvalid instead. The state of validation if used in a form */
72
+ /**
73
+ * @deprecated Use isInvalid instead. The state of validation if used in a form
74
+ */
72
75
  validationState?: ValidationState;
73
- /** This prop indicates if the component is in an error state. */
76
+ /**
77
+ * This prop indicates if the component is in an error state.
78
+ */
74
79
  isInvalid?: boolean;
75
- /** This gives an accessible name to the input for people who use assistive technology. */
80
+ /**
81
+ * This gives an accessible name to the input for people who use assistive technology.
82
+ */
76
83
  label?: string;
77
- /** The `testId` prop appears as a data attribute `data-testid` in the rendered code, serving as a hook for automated tests. It will be set on the menu element when defined: `{testId}--menu` */
84
+ /**
85
+ * The `testId` prop appears as a data attribute `data-testid` in the rendered code, serving as a hook for automated tests. It will be set on the menu element when defined: `{testId}--menu`
86
+ */
78
87
  testId?: string;
79
88
  }
80
89
  interface State<Modifiers = string> {
@@ -1,5 +1,5 @@
1
1
  import { type ComponentType, type Ref } from 'react';
2
- import { type SelectProps, type OptionType, type AsyncSelectProps, type CreatableSelectProps, type AtlaskitSelectRefType } from './types';
2
+ import { type AsyncSelectProps, type AtlaskitSelectRefType, type CreatableSelectProps, type OptionType, type SelectProps } from './types';
3
3
  type AtlaskitSelectProps<Option extends unknown, IsMulti extends boolean> = SelectProps<Option, IsMulti> | AsyncSelectProps<Option, IsMulti> | CreatableSelectProps<Option, IsMulti>;
4
4
  export default function createSelect(WrappedComponent: ComponentType<any>): <Option extends unknown = OptionType, IsMulti extends boolean = false>(props: AtlaskitSelectProps<Option, IsMulti> & {
5
5
  ref?: Ref<AtlaskitSelectRefType>;
@@ -2,3 +2,4 @@ import { type AriaOnFocusProps, type GroupBase, type OptionsOrGroups } from 'rea
2
2
  import { type GroupType, type OptionType } from '../types';
3
3
  export declare function onFocus(props: AriaOnFocusProps<OptionType, GroupBase<OptionType>>): string;
4
4
  export declare const isOptionsGrouped: (arr: OptionsOrGroups<OptionType, GroupType<OptionType>> | undefined) => boolean | undefined;
5
+ export declare const countAllOptions: (groupsArray: readonly GroupType<OptionType>[]) => number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/select",
3
- "version": "17.11.8",
3
+ "version": "17.11.9",
4
4
  "description": "Select allows users to make a single selection or multiple selections from a list of options.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -45,7 +45,7 @@
45
45
  "@atlaskit/analytics-next": "^9.3.0",
46
46
  "@atlaskit/icon": "^22.7.0",
47
47
  "@atlaskit/platform-feature-flags": "^0.3.0",
48
- "@atlaskit/primitives": "^11.0.0",
48
+ "@atlaskit/primitives": "^11.1.0",
49
49
  "@atlaskit/spinner": "^16.2.0",
50
50
  "@atlaskit/theme": "^12.11.0",
51
51
  "@atlaskit/tokens": "^1.56.0",