@elastic/eui 80.0.0 → 81.0.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 (78) hide show
  1. package/dist/eui_charts_theme.js.map +1 -1
  2. package/es/components/bottom_bar/bottom_bar.js +4 -1
  3. package/es/components/bottom_bar/bottom_bar.styles.js +2 -2
  4. package/es/components/button/button.js +4 -1
  5. package/es/components/button/button_empty/button_empty.js +4 -1
  6. package/es/components/button/button_icon/button_icon.js +4 -1
  7. package/es/components/filter_group/filter_group.a11y.js +2 -2
  8. package/es/components/overlay_mask/overlay_mask.js +25 -9
  9. package/es/components/portal/portal.js +17 -0
  10. package/es/components/selectable/selectable.a11y.js +39 -23
  11. package/es/components/selectable/selectable.js +4 -4
  12. package/es/components/selectable/selectable_list/selectable_list.js +5 -5
  13. package/es/components/selectable/selectable_list/selectable_list_item.js +119 -57
  14. package/es/components/selectable/selectable_templates/selectable_template_sitewide.js +4 -4
  15. package/es/services/theme/context.js +7 -1
  16. package/es/services/theme/index.js +1 -1
  17. package/es/services/theme/provider.js +47 -4
  18. package/eui.d.ts +44 -21
  19. package/i18ntokens.json +88 -52
  20. package/lib/components/bottom_bar/bottom_bar.js +4 -1
  21. package/lib/components/bottom_bar/bottom_bar.styles.js +2 -2
  22. package/lib/components/button/button.js +4 -1
  23. package/lib/components/button/button_empty/button_empty.js +4 -1
  24. package/lib/components/button/button_icon/button_icon.js +4 -1
  25. package/lib/components/filter_group/filter_group.a11y.js +2 -2
  26. package/lib/components/overlay_mask/overlay_mask.js +25 -4
  27. package/lib/components/portal/portal.js +17 -0
  28. package/lib/components/selectable/selectable.a11y.js +39 -23
  29. package/lib/components/selectable/selectable.js +4 -4
  30. package/lib/components/selectable/selectable_list/selectable_list.js +5 -5
  31. package/lib/components/selectable/selectable_list/selectable_list_item.js +119 -57
  32. package/lib/components/selectable/selectable_templates/selectable_template_sitewide.js +4 -4
  33. package/lib/services/theme/context.js +9 -2
  34. package/lib/services/theme/index.js +6 -0
  35. package/lib/services/theme/provider.js +45 -2
  36. package/optimize/es/components/bottom_bar/bottom_bar.js +4 -1
  37. package/optimize/es/components/bottom_bar/bottom_bar.styles.js +2 -2
  38. package/optimize/es/components/button/button.js +4 -1
  39. package/optimize/es/components/button/button_empty/button_empty.js +4 -1
  40. package/optimize/es/components/button/button_icon/button_icon.js +4 -1
  41. package/optimize/es/components/filter_group/filter_group.a11y.js +2 -2
  42. package/optimize/es/components/overlay_mask/overlay_mask.js +22 -9
  43. package/optimize/es/components/portal/portal.js +18 -1
  44. package/optimize/es/components/selectable/selectable.a11y.js +39 -23
  45. package/optimize/es/components/selectable/selectable_list/selectable_list_item.js +117 -54
  46. package/optimize/es/services/theme/context.js +7 -1
  47. package/optimize/es/services/theme/index.js +1 -1
  48. package/optimize/es/services/theme/provider.js +46 -4
  49. package/optimize/lib/components/bottom_bar/bottom_bar.js +4 -1
  50. package/optimize/lib/components/bottom_bar/bottom_bar.styles.js +2 -2
  51. package/optimize/lib/components/button/button.js +4 -1
  52. package/optimize/lib/components/button/button_empty/button_empty.js +4 -1
  53. package/optimize/lib/components/button/button_icon/button_icon.js +4 -1
  54. package/optimize/lib/components/filter_group/filter_group.a11y.js +2 -2
  55. package/optimize/lib/components/overlay_mask/overlay_mask.js +22 -4
  56. package/optimize/lib/components/portal/portal.js +18 -1
  57. package/optimize/lib/components/selectable/selectable.a11y.js +39 -23
  58. package/optimize/lib/components/selectable/selectable_list/selectable_list_item.js +117 -54
  59. package/optimize/lib/services/theme/context.js +9 -2
  60. package/optimize/lib/services/theme/index.js +6 -0
  61. package/optimize/lib/services/theme/provider.js +44 -2
  62. package/package.json +2 -5
  63. package/test-env/components/bottom_bar/bottom_bar.js +4 -1
  64. package/test-env/components/bottom_bar/bottom_bar.styles.js +2 -2
  65. package/test-env/components/button/button.js +4 -1
  66. package/test-env/components/button/button_empty/button_empty.js +4 -1
  67. package/test-env/components/button/button_icon/button_icon.js +4 -1
  68. package/test-env/components/filter_group/filter_group.a11y.js +2 -2
  69. package/test-env/components/overlay_mask/overlay_mask.js +22 -4
  70. package/test-env/components/portal/portal.js +17 -0
  71. package/test-env/components/selectable/selectable.a11y.js +39 -23
  72. package/test-env/components/selectable/selectable.js +4 -4
  73. package/test-env/components/selectable/selectable_list/selectable_list.js +5 -5
  74. package/test-env/components/selectable/selectable_list/selectable_list_item.js +120 -57
  75. package/test-env/components/selectable/selectable_templates/selectable_template_sitewide.js +4 -4
  76. package/test-env/services/theme/context.js +9 -2
  77. package/test-env/services/theme/index.js +6 -0
  78. package/test-env/services/theme/provider.js +44 -2
@@ -199,7 +199,10 @@ _EuiBottomBar.propTypes = {
199
199
  export var EuiBottomBar = /*#__PURE__*/forwardRef(function (props, ref) {
200
200
  var BottomBar = _EuiBottomBar;
201
201
  return ___EmotionJSX(EuiThemeProvider, {
202
- colorMode: 'dark'
202
+ colorMode: 'dark',
203
+ wrapperProps: {
204
+ cloneElement: true
205
+ }
203
206
  }, ___EmotionJSX(BottomBar, _extends({
204
207
  ref: ref
205
208
  }, props)));
@@ -17,8 +17,8 @@ export var euiBottomBarStyles = function euiBottomBarStyles(euiThemeContext) {
17
17
  var euiTheme = euiThemeContext.euiTheme;
18
18
  return {
19
19
  // Base
20
- // Text color needs to be reapplied to properly scope the forced `colorMode`
21
- euiBottomBar: /*#__PURE__*/css(euiShadowFlat(euiThemeContext), ";background:", shade(euiTheme.colors.lightestShade, 0.5), ";color:", euiTheme.colors.text, ";", euiCanAnimate, "{animation:", euiBottomBarAppear, " ", euiTheme.animation.slow, " ", euiTheme.animation.resistance, ";};label:euiBottomBar;"),
20
+ // `color` is inherited from the wrapping `EuiThemeProvider colorMode="dark"`
21
+ euiBottomBar: /*#__PURE__*/css(euiShadowFlat(euiThemeContext), ";background:", shade(euiTheme.colors.lightestShade, 0.5), ";", euiCanAnimate, "{animation:", euiBottomBarAppear, " ", euiTheme.animation.slow, " ", euiTheme.animation.resistance, ";};label:euiBottomBar;"),
22
22
  static: /*#__PURE__*/css(";label:static;"),
23
23
  fixed: /*#__PURE__*/css("z-index:", Number(euiTheme.levels.header) - 2, ";;label:fixed;"),
24
24
  sticky: /*#__PURE__*/css("z-index:", Number(euiTheme.levels.header) - 2, ";;label:sticky;"),
@@ -59,7 +59,10 @@ export var EuiButton = function EuiButton(props) {
59
59
  if (_color === 'ghost') {
60
60
  // INCEPTION: If `ghost`, re-implement with a wrapping dark mode theme provider
61
61
  return ___EmotionJSX(EuiThemeProvider, {
62
- colorMode: "dark"
62
+ colorMode: "dark",
63
+ wrapperProps: {
64
+ cloneElement: true
65
+ }
63
66
  }, ___EmotionJSX(EuiButton, _extends({}, props, {
64
67
  color: "text"
65
68
  })));
@@ -83,7 +83,10 @@ export var EuiButtonEmpty = function EuiButtonEmpty(props) {
83
83
  if (_color === 'ghost') {
84
84
  // INCEPTION: If `ghost`, re-implement with a wrapping dark mode theme provider
85
85
  return ___EmotionJSX(EuiThemeProvider, {
86
- colorMode: "dark"
86
+ colorMode: "dark",
87
+ wrapperProps: {
88
+ cloneElement: true
89
+ }
87
90
  }, ___EmotionJSX(EuiButtonEmpty, _extends({}, props, {
88
91
  color: "text"
89
92
  })));
@@ -82,7 +82,10 @@ export var EuiButtonIcon = function EuiButtonIcon(props) {
82
82
  if (_color === 'ghost') {
83
83
  // INCEPTION: If `ghost`, re-implement with a wrapping dark mode theme provider
84
84
  return ___EmotionJSX(EuiThemeProvider, {
85
- colorMode: "dark"
85
+ colorMode: "dark",
86
+ wrapperProps: {
87
+ cloneElement: true
88
+ }
86
89
  }, ___EmotionJSX(EuiButtonIcon, _extends({}, props, {
87
90
  color: "text"
88
91
  })));
@@ -238,10 +238,10 @@ describe('EuiFilterGroup multiselect example', function () {
238
238
  cy.realPress('Tab');
239
239
  cy.repeatRealPress('ArrowDown', 3);
240
240
  cy.realPress('Enter');
241
- cy.get('li[aria-selected="true"]').find('span.euiSelectableListItem__text').should('have.text', 'Dmitri Shostakovich - Selected option. To exclude this option, press enter.');
241
+ cy.get('li[aria-selected="true"]').find('span.euiSelectableListItem__text').should('have.text', 'Dmitri Shostakovich - Checked option. To exclude this option, press Enter.');
242
242
  cy.realPress('ArrowDown');
243
243
  cy.repeatRealPress('Enter');
244
- cy.get('li[aria-selected="true"]').find('span.euiSelectableListItem__text').should('have.text', 'Felix Mendelssohn-Bartholdy - Excluded option. To uncheck this option, press enter.');
244
+ cy.get('li[aria-selected="true"]').find('span.euiSelectableListItem__text').should('have.text', 'Felix Mendelssohn-Bartholdy - Excluded option. To uncheck this option, press Enter.');
245
245
  cy.checkAxe();
246
246
  });
247
247
  it('has zero violations when filtering by searchbox', function () {
@@ -1,4 +1,8 @@
1
1
  var _excluded = ["className", "children", "headerZindexLocation", "maskRef"];
2
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
3
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
2
6
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
3
7
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
8
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
@@ -15,11 +19,6 @@ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) r
15
19
  * Side Public License, v 1.
16
20
  */
17
21
 
18
- /**
19
- * NOTE: We can't test this component because Enzyme doesn't support rendering
20
- * into portals.
21
- */
22
-
23
22
  import React, { useEffect, useState } from 'react';
24
23
  import PropTypes from "prop-types";
25
24
  import { cx } from '@emotion/css';
@@ -57,11 +56,28 @@ export var EuiOverlayMask = function EuiOverlayMask(_ref) {
57
56
  });
58
57
  }, [overlayMaskNode]); // eslint-disable-line react-hooks/exhaustive-deps
59
58
 
59
+ // Note: Use `classList.add/remove` instead of setting the entire `className`
60
+ // so as not to override any existing classes set by `EuiPortal`
60
61
  useEffect(function () {
61
- if (!overlayMaskNode) return;
62
- overlayMaskNode.className = cx('euiOverlayMask', cssStyles, className);
63
- overlayMaskNode.dataset.relativeToHeader = headerZindexLocation;
64
- }, [overlayMaskNode, className, cssStyles, headerZindexLocation]);
62
+ if (overlayMaskNode) {
63
+ overlayMaskNode.classList.add('euiOverlayMask', cssStyles);
64
+ overlayMaskNode.dataset.relativeToHeader = headerZindexLocation;
65
+ return function () {
66
+ return overlayMaskNode.classList.remove(cssStyles);
67
+ };
68
+ }
69
+ }, [overlayMaskNode, cssStyles, headerZindexLocation]);
70
+ useEffect(function () {
71
+ if (className && overlayMaskNode) {
72
+ var _overlayMaskNode$clas;
73
+ var classNameArgs = className.split(' '); // The `classList` API doesn't support multiple classes in the same string
74
+ (_overlayMaskNode$clas = overlayMaskNode.classList).add.apply(_overlayMaskNode$clas, _toConsumableArray(classNameArgs));
75
+ return function () {
76
+ var _overlayMaskNode$clas2;
77
+ return (_overlayMaskNode$clas2 = overlayMaskNode.classList).remove.apply(_overlayMaskNode$clas2, _toConsumableArray(classNameArgs));
78
+ };
79
+ }
80
+ }, [overlayMaskNode, className]);
65
81
  return ___EmotionJSX(EuiPortal, {
66
82
  portalRef: combinedMaskRef
67
83
  }, ___EmotionJSX(Global, {
@@ -28,6 +28,7 @@ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input ==
28
28
  import { Component } from 'react';
29
29
  import PropTypes from "prop-types";
30
30
  import { createPortal } from 'react-dom';
31
+ import { EuiNestedThemeContext } from '../../services';
31
32
  import { keysOf } from '../common';
32
33
  export var insertPositions = {
33
34
  after: 'afterend',
@@ -61,6 +62,7 @@ export var EuiPortal = /*#__PURE__*/function (_Component) {
61
62
  _createClass(EuiPortal, [{
62
63
  key: "componentDidMount",
63
64
  value: function componentDidMount() {
65
+ this.setThemeColor();
64
66
  this.updatePortalRef(this.portalNode);
65
67
  }
66
68
  }, {
@@ -72,6 +74,20 @@ export var EuiPortal = /*#__PURE__*/function (_Component) {
72
74
  }
73
75
  this.updatePortalRef(null);
74
76
  }
77
+
78
+ // Set the inherited color of the portal based on the wrapping EuiThemeProvider
79
+ }, {
80
+ key: "setThemeColor",
81
+ value: function setThemeColor() {
82
+ if (this.portalNode && this.context) {
83
+ var _this$context = this.context,
84
+ hasDifferentColorFromGlobalTheme = _this$context.hasDifferentColorFromGlobalTheme,
85
+ colorClassName = _this$context.colorClassName;
86
+ if (hasDifferentColorFromGlobalTheme && this.props.insert == null) {
87
+ this.portalNode.classList.add(colorClassName);
88
+ }
89
+ }
90
+ }
75
91
  }, {
76
92
  key: "updatePortalRef",
77
93
  value: function updatePortalRef(ref) {
@@ -87,6 +103,7 @@ export var EuiPortal = /*#__PURE__*/function (_Component) {
87
103
  }]);
88
104
  return EuiPortal;
89
105
  }(Component);
106
+ _defineProperty(EuiPortal, "contextType", EuiNestedThemeContext);
90
107
  EuiPortal.propTypes = {
91
108
  /**
92
109
  * ReactNode to render as this component's content
@@ -4,7 +4,6 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
4
4
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
5
5
  function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
6
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
8
7
  /*
9
8
  * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
10
9
  * or more contributor license agreements. Licensed under the Elastic License
@@ -30,27 +29,27 @@ var options = [{
30
29
  }, {
31
30
  label: "Pandora is one of Saturn's moons, named for a Titaness of Greek mythology"
32
31
  }];
33
- var EuiSelectableListboxOnly = function EuiSelectableListboxOnly(args) {
34
- return ___EmotionJSX(EuiSelectable, _extends({
35
- options: options
36
- }, args), function (list) {
37
- return ___EmotionJSX(React.Fragment, null, list);
38
- });
39
- };
40
- var EuiSelectableWithSearchInput = function EuiSelectableWithSearchInput(args) {
41
- return ___EmotionJSX(EuiSelectable, _extends({
42
- searchable: true,
43
- options: options
44
- }, args), function (list, search) {
45
- return ___EmotionJSX(React.Fragment, null, search, list);
46
- });
47
- };
32
+ var excludedOptions = [{
33
+ label: 'Titan',
34
+ 'data-test-subj': 'titanOption',
35
+ checked: 'on'
36
+ }, {
37
+ label: 'Enceladus',
38
+ checked: 'off'
39
+ }, {
40
+ label: "Pandora is one of Saturn's moons, named for a Titaness of Greek mythology",
41
+ checked: 'mixed'
42
+ }];
48
43
  describe('EuiSelectable', function () {
49
44
  describe('with a `searchable` configuration', function () {
50
45
  it('has no accessibility errors', function () {
51
46
  var onChange = cy.stub();
52
- cy.realMount(___EmotionJSX(EuiSelectableWithSearchInput, {
53
- onChange: onChange
47
+ cy.realMount(___EmotionJSX(EuiSelectable, {
48
+ options: options,
49
+ onChange: onChange,
50
+ searchable: true
51
+ }, function (list, search) {
52
+ return ___EmotionJSX(React.Fragment, null, search, list);
54
53
  }));
55
54
  cy.checkAxe();
56
55
  });
@@ -58,9 +57,25 @@ describe('EuiSelectable', function () {
58
57
  describe('without a `searchable` configuration', function () {
59
58
  it('has no accessibility errors', function () {
60
59
  var onChange = cy.stub();
61
- cy.realMount(___EmotionJSX(EuiSelectableListboxOnly, {
60
+ cy.realMount(___EmotionJSX(EuiSelectable, {
62
61
  "aria-label": "No search box",
62
+ options: options,
63
63
  onChange: onChange
64
+ }, function (list) {
65
+ return ___EmotionJSX(React.Fragment, null, list);
66
+ }));
67
+ cy.checkAxe();
68
+ });
69
+ });
70
+ describe('with excluded and mixed options configuration', function () {
71
+ it('has no accessibility errors', function () {
72
+ var onChange = cy.stub();
73
+ cy.realMount(___EmotionJSX(EuiSelectable, {
74
+ "aria-label": "Excluded and mixed options",
75
+ options: excludedOptions,
76
+ onChange: onChange
77
+ }, function (list) {
78
+ return ___EmotionJSX(React.Fragment, null, list);
64
79
  }));
65
80
  cy.checkAxe();
66
81
  });
@@ -87,12 +102,13 @@ describe('EuiSelectable', function () {
87
102
  button: button,
88
103
  isOpen: isPopoverOpen,
89
104
  closePopover: onClosePopover
90
- }, ___EmotionJSX(EuiSelectableWithSearchInput, {
105
+ }, ___EmotionJSX(EuiSelectable, {
91
106
  "aria-label": "With popover",
92
107
  options: options,
93
- onChange: onChange
94
- }, function (list) {
95
- return ___EmotionJSX(React.Fragment, null, list);
108
+ onChange: onChange,
109
+ searchable: true
110
+ }, function (list, search) {
111
+ return ___EmotionJSX(React.Fragment, null, search, list);
96
112
  }));
97
113
  };
98
114
  it('has no accessibility errors', function () {
@@ -596,11 +596,11 @@ EuiSelectable.propTypes = {
596
596
  */
597
597
  key: PropTypes.string,
598
598
  /**
599
- * Leave `undefined` to indicate not selected,
600
- * 'on' to indicate inclusion and
601
- * 'off' to indicate exclusion
599
+ * Leave `undefined` to indicate not selected. Pass a string of
600
+ * 'on' to indicate inclusion, 'off' to indicate exclusion,
601
+ * or 'mixed' to indicate inclusion for some.
602
602
  */
603
- checked: PropTypes.oneOf(["on", "off", undefined]),
603
+ checked: PropTypes.oneOf(["on", "off", "mixed", undefined]),
604
604
  disabled: PropTypes.bool,
605
605
  /**
606
606
  * Node to add between the selection icon and the label
@@ -474,11 +474,11 @@ EuiSelectableList.propTypes = {
474
474
  */
475
475
  key: PropTypes.string,
476
476
  /**
477
- * Leave `undefined` to indicate not selected,
478
- * 'on' to indicate inclusion and
479
- * 'off' to indicate exclusion
477
+ * Leave `undefined` to indicate not selected. Pass a string of
478
+ * 'on' to indicate inclusion, 'off' to indicate exclusion,
479
+ * or 'mixed' to indicate inclusion for some.
480
480
  */
481
- checked: PropTypes.oneOf(["on", "off", undefined]),
481
+ checked: PropTypes.oneOf(["on", "off", "mixed", undefined]),
482
482
  disabled: PropTypes.bool,
483
483
  /**
484
484
  * Node to add between the selection icon and the label
@@ -507,7 +507,7 @@ EuiSelectableList.propTypes = {
507
507
  label: PropTypes.string,
508
508
  searchableLabel: PropTypes.string,
509
509
  key: PropTypes.string,
510
- checked: PropTypes.oneOf(["on", "off", undefined]),
510
+ checked: PropTypes.oneOf(["on", "off", "mixed", undefined]),
511
511
  disabled: PropTypes.bool,
512
512
  prepend: PropTypes.node,
513
513
  append: PropTypes.node,
@@ -35,18 +35,28 @@ import { EuiScreenReaderOnly } from '../../accessibility';
35
35
  import { EuiBadge } from '../../badge';
36
36
  import { jsx as ___EmotionJSX } from "@emotion/react";
37
37
  function resolveIconAndColor(checked) {
38
- if (!checked) {
39
- return {
40
- icon: 'empty'
41
- };
38
+ switch (checked) {
39
+ case 'on':
40
+ return {
41
+ icon: 'check',
42
+ color: 'text'
43
+ };
44
+ case 'off':
45
+ return {
46
+ icon: 'cross',
47
+ color: 'text'
48
+ };
49
+ case 'mixed':
50
+ return {
51
+ icon: 'minus',
52
+ color: 'text'
53
+ };
54
+ case undefined:
55
+ default:
56
+ return {
57
+ icon: 'empty'
58
+ };
42
59
  }
43
- return checked === 'on' ? {
44
- icon: 'check',
45
- color: 'text'
46
- } : {
47
- icon: 'cross',
48
- color: 'text'
49
- };
50
60
  }
51
61
  var paddingSizeToClassNameMap = {
52
62
  none: null,
@@ -58,8 +68,32 @@ export var EuiSelectableListItem = /*#__PURE__*/function (_Component) {
58
68
  _inherits(EuiSelectableListItem, _Component);
59
69
  var _super = _createSuper(EuiSelectableListItem);
60
70
  function EuiSelectableListItem(props) {
71
+ var _this;
61
72
  _classCallCheck(this, EuiSelectableListItem);
62
- return _super.call(this, props);
73
+ _this = _super.call(this, props);
74
+ // aria-checked is intended to be used with role="checkbox" but
75
+ // the MDN documentation lists it as a possibility for role="option".
76
+ // See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked
77
+ // and https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/option_role
78
+ _defineProperty(_assertThisInitialized(_this), "isChecked", function (role, checked) {
79
+ var rolesThatCanBeMixed = ['option', 'checkbox', 'menuitemcheckbox'];
80
+ var rolesThatCanBeChecked = [].concat(rolesThatCanBeMixed, ['radio', 'menuitemradio', 'switch']);
81
+ if (!rolesThatCanBeChecked.includes(role)) return undefined;
82
+ switch (checked) {
83
+ case 'on':
84
+ case 'off':
85
+ return true;
86
+ case 'mixed':
87
+ if (rolesThatCanBeMixed.includes(role)) {
88
+ return 'mixed';
89
+ } else {
90
+ return false;
91
+ }
92
+ default:
93
+ return false;
94
+ }
95
+ });
96
+ return _this;
63
97
  }
64
98
  _createClass(EuiSelectableListItem, [{
65
99
  key: "render",
@@ -98,41 +132,71 @@ export var EuiSelectableListItem = /*#__PURE__*/function (_Component) {
98
132
  });
99
133
  }
100
134
  var state;
101
- var instruction;
102
- if (allowExclusions && checked === 'on') {
103
- state = ___EmotionJSX(EuiI18n, {
104
- token: "euiSelectableListItem.includedOption",
105
- default: "Selected option."
106
- });
107
- instruction = ___EmotionJSX(EuiI18n, {
108
- token: "euiSelectableListItem.includedOptionInstructions",
109
- default: "To exclude this option, press enter."
110
- });
111
- } else if (allowExclusions && checked === 'off') {
112
- state = ___EmotionJSX(EuiI18n, {
113
- token: "euiSelectableListItem.excludedOption",
114
- default: "Excluded option."
115
- });
116
- instruction = ___EmotionJSX(EuiI18n, {
117
- token: "euiSelectableListItem.excludedOptionInstructions",
118
- default: "To uncheck this option, press enter."
119
- });
120
- } else if (allowExclusions && !checked) {
121
- instruction = ___EmotionJSX(EuiI18n, {
122
- token: "euiSelectableListItem.unckeckedOptionInstructions",
123
- default: "To select this option, press enter."
124
- });
125
- }
126
- var isChecked = !disabled && typeof checked === 'string';
127
- if (!allowExclusions && isChecked) {
128
- state = ___EmotionJSX(EuiI18n, {
129
- token: "euiSelectableListItem.checkedOption",
130
- default: "Checked option."
131
- });
132
- instruction = searchable ? ___EmotionJSX(EuiI18n, {
133
- token: "euiSelectableListItem.checkedOptionInstructions",
134
- default: "To uncheck this option, press enter."
135
- }) : undefined;
135
+ var instructions;
136
+ var screenReaderStrings = {
137
+ checked: {
138
+ state: ___EmotionJSX(EuiI18n, {
139
+ token: "euiSelectableListItem.checkedOption",
140
+ default: "Checked option."
141
+ }),
142
+ instructions: ___EmotionJSX(EuiI18n, {
143
+ token: "euiSelectableListItem.checkOptionInstructions",
144
+ default: "To check this option, press Enter."
145
+ })
146
+ },
147
+ unchecked: {
148
+ instructions: ___EmotionJSX(EuiI18n, {
149
+ token: "euiSelectableListItem.uncheckOptionInstructions",
150
+ default: "To uncheck this option, press Enter."
151
+ })
152
+ },
153
+ excluded: {
154
+ state: ___EmotionJSX(EuiI18n, {
155
+ token: "euiSelectableListItem.excludedOption",
156
+ default: "Excluded option."
157
+ }),
158
+ instructions: ___EmotionJSX(EuiI18n, {
159
+ token: "euiSelectableListItem.excludeOptionInstructions",
160
+ default: "To exclude this option, press Enter."
161
+ })
162
+ },
163
+ mixed: {
164
+ state: ___EmotionJSX(EuiI18n, {
165
+ token: "euiSelectableListItem.mixedOption",
166
+ default: "Mixed (indeterminate) option."
167
+ }),
168
+ instructions: ___EmotionJSX(EuiI18n, {
169
+ token: "euiSelectableListItem.mixedOptionInstructions",
170
+ default: "To check this option for all, press Enter once."
171
+ }),
172
+ uncheckInstructions: ___EmotionJSX(EuiI18n, {
173
+ token: "euiSelectableListItem.mixedOptionUncheckInstructions",
174
+ default: "To uncheck this option for all, press Enter twice."
175
+ }),
176
+ excludeInstructions: ___EmotionJSX(EuiI18n, {
177
+ token: "euiSelectableListItem.mixedOptionExcludeInstructions",
178
+ default: "To exclude this option for all, press Enter twice."
179
+ })
180
+ }
181
+ };
182
+ switch (checked) {
183
+ case 'on':
184
+ state = screenReaderStrings.checked.state;
185
+ // eslint-disable-next-line no-nested-ternary
186
+ instructions = allowExclusions ? screenReaderStrings.excluded.instructions : searchable ? screenReaderStrings.unchecked.instructions : undefined;
187
+ break;
188
+ case 'off':
189
+ state = screenReaderStrings.excluded.state;
190
+ instructions = screenReaderStrings.unchecked.instructions;
191
+ break;
192
+ case 'mixed':
193
+ state = screenReaderStrings.mixed.state;
194
+ instructions = ___EmotionJSX(React.Fragment, null, screenReaderStrings.mixed.instructions, ' ', allowExclusions ? screenReaderStrings.mixed.excludeInstructions : screenReaderStrings.mixed.uncheckInstructions);
195
+ break;
196
+ case undefined:
197
+ default:
198
+ instructions = allowExclusions || searchable ? screenReaderStrings.checked.instructions : undefined;
199
+ break;
136
200
  }
137
201
  var prependNode;
138
202
  if (prepend) {
@@ -169,22 +233,20 @@ export var EuiSelectableListItem = /*#__PURE__*/function (_Component) {
169
233
  }, append, " ", isFocused && !disabled ? onFocusBadgeNode : null);
170
234
  }
171
235
  }
172
- var instructions = (instruction || state) && ___EmotionJSX(EuiScreenReaderOnly, null, ___EmotionJSX("div", null, state || instruction ? ' - ' : null, state, state && instruction ? ' ' : null, instruction));
236
+ var screenReaderText = (state || instructions) && ___EmotionJSX(EuiScreenReaderOnly, null, ___EmotionJSX("div", null, state || instructions ? '. ' : null, state, state && instructions ? ' ' : null, instructions));
173
237
  return ___EmotionJSX("li", _extends({
174
238
  role: role,
175
- "data-test-selected": isChecked // Whether the item is checked/selected
176
- ,
177
- "aria-checked": role === 'option' ? isChecked : undefined // Whether the item is "checked"
239
+ "aria-disabled": disabled,
240
+ "aria-checked": this.isChecked(role, checked) // Whether the item is "checked"
178
241
  ,
179
242
  "aria-selected": !disabled && isFocused // Whether the item has keyboard focus per W3 spec
180
243
  ,
181
- className: classes,
182
- "aria-disabled": disabled
244
+ className: classes
183
245
  }, rest), ___EmotionJSX("span", {
184
246
  className: "euiSelectableListItem__content"
185
247
  }, optionIcon, prependNode, ___EmotionJSX("span", {
186
248
  className: textClasses
187
- }, children, instructions), appendNode));
249
+ }, children, screenReaderText), appendNode));
188
250
  }
189
251
  }]);
190
252
  return EuiSelectableListItem;
@@ -203,7 +265,7 @@ EuiSelectableListItem.propTypes = {
203
265
  /**
204
266
  * Applies an icon and visual styling to activated items
205
267
  */
206
- checked: PropTypes.oneOf(["on", "off", undefined]),
268
+ checked: PropTypes.oneOf(["on", "off", "mixed", undefined]),
207
269
  /**
208
270
  * Shows icons based on `checked` type
209
271
  */
@@ -278,8 +340,8 @@ EuiSelectableListItem.propTypes = {
278
340
  searchable: PropTypes.bool,
279
341
  /**
280
342
  * Attribute applied the option `<li>`.
281
- * If configured to something besides the default value of `option`,
282
- * other ARIA attributes such as `aria-checked` will not be automatically configured.
343
+ * If set to a role that allows [aria-checked](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked),
344
+ * `aria-checked` will be automatically configured.
283
345
  */
284
346
  role: PropTypes.any,
285
347
  /**
@@ -364,11 +364,11 @@ EuiSelectableTemplateSitewide.propTypes = {
364
364
  */
365
365
  key: PropTypes.string,
366
366
  /**
367
- * Leave `undefined` to indicate not selected,
368
- * 'on' to indicate inclusion and
369
- * 'off' to indicate exclusion
367
+ * Leave `undefined` to indicate not selected. Pass a string of
368
+ * 'on' to indicate inclusion, 'off' to indicate exclusion,
369
+ * or 'mixed' to indicate inclusion for some.
370
370
  */
371
- checked: PropTypes.oneOf(["on", "off", undefined]),
371
+ checked: PropTypes.oneOf(["on", "off", "mixed", undefined]),
372
372
  disabled: PropTypes.bool,
373
373
  /**
374
374
  * Node to add between the selection icon and the label
@@ -13,4 +13,10 @@ export var EuiSystemContext = /*#__PURE__*/createContext(EuiThemeAmsterdam);
13
13
  export var EuiModificationsContext = /*#__PURE__*/createContext({});
14
14
  export var EuiColorModeContext = /*#__PURE__*/createContext(DEFAULT_COLOR_MODE);
15
15
  export var defaultComputedTheme = getComputed(EuiThemeAmsterdam, {}, DEFAULT_COLOR_MODE);
16
- export var EuiThemeContext = /*#__PURE__*/createContext(defaultComputedTheme);
16
+ export var EuiThemeContext = /*#__PURE__*/createContext(defaultComputedTheme);
17
+ export var EuiNestedThemeContext = /*#__PURE__*/createContext({
18
+ isGlobalTheme: true,
19
+ hasDifferentColorFromGlobalTheme: false,
20
+ bodyColor: '',
21
+ colorClassName: ''
22
+ });
@@ -6,7 +6,7 @@
6
6
  * Side Public License, v 1.
7
7
  */
8
8
 
9
- export { EuiSystemContext, EuiThemeContext, EuiModificationsContext, EuiColorModeContext } from './context';
9
+ export { EuiSystemContext, EuiThemeContext, EuiNestedThemeContext, EuiModificationsContext, EuiColorModeContext } from './context';
10
10
  export { useEuiTheme, withEuiTheme, RenderWithEuiTheme } from './hooks';
11
11
  export { EuiThemeProvider, getEuiDevProviderWarning, setEuiDevProviderWarning } from './provider';
12
12
  export { buildTheme, computed, isInverseColorMode, getColorMode, getComputed, getOn, mergeDeep, setOn, Computed } from './utils';