@atlaskit/dropdown-menu 10.1.8 → 11.0.2

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 (211) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/__perf__/default.tsx +1 -1
  3. package/__perf__/dropdown-menu.tsx +216 -0
  4. package/codemods/11.0.0-lite-mode.tsx +39 -0
  5. package/codemods/__tests__/11.0.0-lite-mode.test.tsx +48 -0
  6. package/codemods/__tests__/convert-position.test.tsx +88 -0
  7. package/codemods/__tests__/convert-triggerType.test.tsx +100 -0
  8. package/codemods/__tests__/deprecate-items.test.tsx +108 -0
  9. package/codemods/__tests__/deprecate-onItemActivated.test.tsx +108 -0
  10. package/codemods/__tests__/deprecate-onPositioned.test.tsx +108 -0
  11. package/codemods/__tests__/deprecate-shouldFitContainer.tsx +108 -0
  12. package/codemods/__tests__/rename-imports.tsx +136 -0
  13. package/codemods/__tests__/replace-position-to-placement.test.tsx +84 -0
  14. package/codemods/__tests__/replace-shouldAllowMultipleLine.test.tsx +122 -0
  15. package/codemods/__tests__/update-component-callsites.tsx +66 -0
  16. package/codemods/migrates/convert-trigger-type.tsx +57 -0
  17. package/codemods/migrates/deprecate-items.tsx +9 -0
  18. package/codemods/migrates/deprecate-onItemActivated.tsx +9 -0
  19. package/codemods/migrates/deprecate-onPositioned.tsx +9 -0
  20. package/codemods/migrates/deprecate-shouldFitContainer.tsx +9 -0
  21. package/codemods/migrates/rename-imports.tsx +22 -0
  22. package/codemods/migrates/replace-position-to-placement.tsx +38 -0
  23. package/codemods/migrates/replace-shouldAllowMultiline.tsx +47 -0
  24. package/codemods/migrates/update-component-callsites.tsx +13 -0
  25. package/codemods/utils/convert-position.tsx +24 -0
  26. package/codemods/utils/create-rename-import.tsx +41 -0
  27. package/codemods/utils/create-update-callsite.tsx +32 -0
  28. package/dist/cjs/checkbox/dropdown-item-checkbox-group.js +31 -0
  29. package/dist/cjs/checkbox/dropdown-item-checkbox.js +108 -0
  30. package/dist/cjs/dropdown-menu-item-group.js +22 -0
  31. package/dist/cjs/dropdown-menu-item.js +67 -0
  32. package/dist/cjs/dropdown-menu.js +194 -0
  33. package/dist/cjs/index.js +21 -29
  34. package/dist/cjs/{components/item/DropdownItemRadio.js → internal/components/focus-manager.js} +40 -9
  35. package/dist/cjs/internal/components/menu-wrapper.js +68 -0
  36. package/dist/cjs/internal/context/checkbox-group-context.js +14 -0
  37. package/dist/cjs/internal/context/selection-store.js +76 -0
  38. package/dist/cjs/internal/hooks/use-checkbox-state.js +68 -0
  39. package/dist/cjs/internal/hooks/use-radio-state.js +84 -0
  40. package/dist/cjs/internal/hooks/use-register-item-with-focus-manager.js +29 -0
  41. package/dist/cjs/internal/utils/get-icon-colors.js +25 -0
  42. package/dist/cjs/internal/utils/handle-focus.js +58 -0
  43. package/dist/cjs/internal/utils/is-checkbox-item.js +11 -0
  44. package/dist/cjs/internal/utils/is-radio-item.js +11 -0
  45. package/dist/cjs/internal/utils/is-voice-over-supported.js +23 -0
  46. package/dist/cjs/internal/utils/reset-options-in-group.js +23 -0
  47. package/dist/cjs/radio/dropdown-item-radio-group.js +89 -0
  48. package/dist/cjs/radio/dropdown-item-radio.js +108 -0
  49. package/dist/cjs/version.json +1 -1
  50. package/dist/es2019/checkbox/dropdown-item-checkbox-group.js +21 -0
  51. package/dist/es2019/checkbox/dropdown-item-checkbox.js +67 -0
  52. package/dist/es2019/dropdown-menu-item-group.js +11 -0
  53. package/dist/es2019/dropdown-menu-item.js +49 -0
  54. package/dist/es2019/dropdown-menu.js +151 -0
  55. package/dist/es2019/index.js +7 -11
  56. package/dist/es2019/internal/components/focus-manager.js +40 -0
  57. package/dist/es2019/internal/components/menu-wrapper.js +44 -0
  58. package/dist/es2019/internal/context/checkbox-group-context.js +6 -0
  59. package/dist/es2019/internal/context/selection-store.js +54 -0
  60. package/dist/es2019/internal/hooks/use-checkbox-state.js +45 -0
  61. package/dist/es2019/internal/hooks/use-radio-state.js +56 -0
  62. package/dist/es2019/internal/hooks/use-register-item-with-focus-manager.js +19 -0
  63. package/dist/es2019/internal/utils/get-icon-colors.js +17 -0
  64. package/dist/es2019/internal/utils/handle-focus.js +48 -0
  65. package/dist/es2019/internal/utils/is-checkbox-item.js +4 -0
  66. package/dist/es2019/internal/utils/is-radio-item.js +4 -0
  67. package/dist/es2019/internal/utils/is-voice-over-supported.js +11 -0
  68. package/dist/es2019/internal/utils/reset-options-in-group.js +7 -0
  69. package/dist/es2019/radio/dropdown-item-radio-group.js +56 -0
  70. package/dist/es2019/radio/dropdown-item-radio.js +67 -0
  71. package/dist/es2019/version.json +1 -1
  72. package/dist/esm/checkbox/dropdown-item-checkbox-group.js +19 -0
  73. package/dist/esm/checkbox/dropdown-item-checkbox.js +81 -0
  74. package/dist/esm/dropdown-menu-item-group.js +11 -0
  75. package/dist/esm/dropdown-menu-item.js +52 -0
  76. package/dist/esm/dropdown-menu.js +168 -0
  77. package/dist/esm/index.js +7 -11
  78. package/dist/esm/internal/components/focus-manager.js +39 -0
  79. package/dist/esm/internal/components/menu-wrapper.js +45 -0
  80. package/dist/esm/internal/context/checkbox-group-context.js +6 -0
  81. package/dist/esm/internal/context/selection-store.js +58 -0
  82. package/dist/esm/internal/hooks/use-checkbox-state.js +55 -0
  83. package/dist/esm/internal/hooks/use-radio-state.js +70 -0
  84. package/dist/esm/internal/hooks/use-register-item-with-focus-manager.js +19 -0
  85. package/dist/esm/internal/utils/get-icon-colors.js +17 -0
  86. package/dist/esm/internal/utils/handle-focus.js +47 -0
  87. package/dist/esm/internal/utils/is-checkbox-item.js +4 -0
  88. package/dist/esm/internal/utils/is-radio-item.js +4 -0
  89. package/dist/esm/internal/utils/is-voice-over-supported.js +15 -0
  90. package/dist/esm/internal/utils/reset-options-in-group.js +13 -0
  91. package/dist/esm/radio/dropdown-item-radio-group.js +66 -0
  92. package/dist/esm/radio/dropdown-item-radio.js +81 -0
  93. package/dist/esm/version.json +1 -1
  94. package/dist/types/checkbox/dropdown-item-checkbox-group.d.ts +16 -0
  95. package/dist/types/checkbox/dropdown-item-checkbox.d.ts +13 -0
  96. package/dist/types/dropdown-menu-item-group.d.ts +11 -0
  97. package/dist/types/dropdown-menu-item.d.ts +13 -0
  98. package/dist/types/dropdown-menu.d.ts +13 -0
  99. package/dist/types/index.d.ts +8 -10
  100. package/dist/types/internal/components/focus-manager.d.ts +19 -0
  101. package/dist/types/internal/components/menu-wrapper.d.ts +11 -0
  102. package/dist/types/internal/context/checkbox-group-context.d.ts +5 -0
  103. package/dist/types/internal/context/selection-store.d.ts +27 -0
  104. package/dist/types/internal/hooks/use-checkbox-state.d.ts +14 -0
  105. package/dist/types/internal/hooks/use-radio-state.d.ts +9 -0
  106. package/dist/types/internal/hooks/use-register-item-with-focus-manager.d.ts +4 -0
  107. package/dist/types/internal/utils/get-icon-colors.d.ts +8 -0
  108. package/dist/types/internal/utils/handle-focus.d.ts +2 -0
  109. package/dist/types/internal/utils/is-checkbox-item.d.ts +1 -0
  110. package/dist/types/internal/utils/is-radio-item.d.ts +1 -0
  111. package/dist/types/internal/utils/is-voice-over-supported.d.ts +2 -0
  112. package/dist/types/internal/utils/reset-options-in-group.d.ts +4 -0
  113. package/dist/types/radio/dropdown-item-radio-group.d.ts +25 -0
  114. package/dist/types/radio/dropdown-item-radio.d.ts +13 -0
  115. package/dist/types/types.d.ts +254 -79
  116. package/package.json +39 -23
  117. package/dist/cjs/components/DropdownMenu.js +0 -230
  118. package/dist/cjs/components/DropdownMenuStateless.js +0 -523
  119. package/dist/cjs/components/context/DropdownItemClickManager.js +0 -72
  120. package/dist/cjs/components/context/DropdownItemFocusManager.js +0 -178
  121. package/dist/cjs/components/context/DropdownItemSelectionCache.js +0 -131
  122. package/dist/cjs/components/context/DropdownItemSelectionManager.js +0 -185
  123. package/dist/cjs/components/group/DropdownItemGroup.js +0 -61
  124. package/dist/cjs/components/group/DropdownItemGroupCheckbox.js +0 -16
  125. package/dist/cjs/components/group/DropdownItemGroupRadio.js +0 -16
  126. package/dist/cjs/components/group/ert-group-selection.js +0 -8
  127. package/dist/cjs/components/hoc/withItemSelectionManager.js +0 -66
  128. package/dist/cjs/components/hoc/withToggleInteraction.js +0 -175
  129. package/dist/cjs/components/item/DropdownItem.js +0 -19
  130. package/dist/cjs/components/item/DropdownItemCheckbox.js +0 -28
  131. package/dist/cjs/components/item/ert-item-checkbox.js +0 -8
  132. package/dist/cjs/components/item/ert-item-radio.js +0 -8
  133. package/dist/cjs/components/item/ert-item.js +0 -8
  134. package/dist/cjs/styled/WidthConstrainer.js +0 -21
  135. package/dist/cjs/util/contextNamespace.js +0 -19
  136. package/dist/cjs/util/getDisplayName.js +0 -14
  137. package/dist/cjs/util/keys.js +0 -18
  138. package/dist/cjs/util/safeContextCall.js +0 -27
  139. package/dist/cjs/util/supportsVoiceover.js +0 -17
  140. package/dist/es2019/components/DropdownMenu.js +0 -156
  141. package/dist/es2019/components/DropdownMenuStateless.js +0 -459
  142. package/dist/es2019/components/context/DropdownItemClickManager.js +0 -31
  143. package/dist/es2019/components/context/DropdownItemFocusManager.js +0 -134
  144. package/dist/es2019/components/context/DropdownItemSelectionCache.js +0 -68
  145. package/dist/es2019/components/context/DropdownItemSelectionManager.js +0 -140
  146. package/dist/es2019/components/group/DropdownItemGroup.js +0 -17
  147. package/dist/es2019/components/group/DropdownItemGroupCheckbox.js +0 -3
  148. package/dist/es2019/components/group/DropdownItemGroupRadio.js +0 -3
  149. package/dist/es2019/components/group/ert-group-selection.js +0 -1
  150. package/dist/es2019/components/hoc/withItemSelectionManager.js +0 -20
  151. package/dist/es2019/components/hoc/withToggleInteraction.js +0 -119
  152. package/dist/es2019/components/item/DropdownItem.js +0 -3
  153. package/dist/es2019/components/item/DropdownItemCheckbox.js +0 -5
  154. package/dist/es2019/components/item/DropdownItemRadio.js +0 -5
  155. package/dist/es2019/components/item/ert-item-checkbox.js +0 -1
  156. package/dist/es2019/components/item/ert-item-radio.js +0 -1
  157. package/dist/es2019/components/item/ert-item.js +0 -1
  158. package/dist/es2019/styled/WidthConstrainer.js +0 -6
  159. package/dist/es2019/util/contextNamespace.js +0 -6
  160. package/dist/es2019/util/getDisplayName.js +0 -4
  161. package/dist/es2019/util/keys.js +0 -6
  162. package/dist/es2019/util/safeContextCall.js +0 -10
  163. package/dist/es2019/util/supportsVoiceover.js +0 -5
  164. package/dist/esm/components/DropdownMenu.js +0 -215
  165. package/dist/esm/components/DropdownMenuStateless.js +0 -516
  166. package/dist/esm/components/context/DropdownItemClickManager.js +0 -59
  167. package/dist/esm/components/context/DropdownItemFocusManager.js +0 -164
  168. package/dist/esm/components/context/DropdownItemSelectionCache.js +0 -113
  169. package/dist/esm/components/context/DropdownItemSelectionManager.js +0 -174
  170. package/dist/esm/components/group/DropdownItemGroup.js +0 -43
  171. package/dist/esm/components/group/DropdownItemGroupCheckbox.js +0 -3
  172. package/dist/esm/components/group/DropdownItemGroupRadio.js +0 -3
  173. package/dist/esm/components/group/ert-group-selection.js +0 -1
  174. package/dist/esm/components/hoc/withItemSelectionManager.js +0 -47
  175. package/dist/esm/components/hoc/withToggleInteraction.js +0 -155
  176. package/dist/esm/components/item/DropdownItem.js +0 -3
  177. package/dist/esm/components/item/DropdownItemCheckbox.js +0 -7
  178. package/dist/esm/components/item/DropdownItemRadio.js +0 -7
  179. package/dist/esm/components/item/ert-item-checkbox.js +0 -1
  180. package/dist/esm/components/item/ert-item-radio.js +0 -1
  181. package/dist/esm/components/item/ert-item.js +0 -1
  182. package/dist/esm/styled/WidthConstrainer.js +0 -9
  183. package/dist/esm/util/contextNamespace.js +0 -8
  184. package/dist/esm/util/getDisplayName.js +0 -6
  185. package/dist/esm/util/keys.js +0 -6
  186. package/dist/esm/util/safeContextCall.js +0 -18
  187. package/dist/esm/util/supportsVoiceover.js +0 -9
  188. package/dist/types/components/DropdownMenu.d.ts +0 -36
  189. package/dist/types/components/DropdownMenuStateless.d.ts +0 -82
  190. package/dist/types/components/context/DropdownItemClickManager.d.ts +0 -19
  191. package/dist/types/components/context/DropdownItemFocusManager.d.ts +0 -35
  192. package/dist/types/components/context/DropdownItemSelectionCache.d.ts +0 -31
  193. package/dist/types/components/context/DropdownItemSelectionManager.d.ts +0 -34
  194. package/dist/types/components/group/DropdownItemGroup.d.ts +0 -12
  195. package/dist/types/components/group/DropdownItemGroupCheckbox.d.ts +0 -55
  196. package/dist/types/components/group/DropdownItemGroupRadio.d.ts +0 -55
  197. package/dist/types/components/group/ert-group-selection.d.ts +0 -6
  198. package/dist/types/components/hoc/withItemSelectionManager.d.ts +0 -63
  199. package/dist/types/components/hoc/withToggleInteraction.d.ts +0 -98
  200. package/dist/types/components/item/DropdownItem.d.ts +0 -65
  201. package/dist/types/components/item/DropdownItemCheckbox.d.ts +0 -80
  202. package/dist/types/components/item/DropdownItemRadio.d.ts +0 -80
  203. package/dist/types/components/item/ert-item-checkbox.d.ts +0 -2
  204. package/dist/types/components/item/ert-item-radio.d.ts +0 -2
  205. package/dist/types/components/item/ert-item.d.ts +0 -2
  206. package/dist/types/styled/WidthConstrainer.d.ts +0 -7
  207. package/dist/types/util/contextNamespace.d.ts +0 -4
  208. package/dist/types/util/getDisplayName.d.ts +0 -3
  209. package/dist/types/util/keys.d.ts +0 -6
  210. package/dist/types/util/safeContextCall.d.ts +0 -6
  211. package/dist/types/util/supportsVoiceover.d.ts +0 -2
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import Section from '@atlaskit/menu/section';
3
+ import { CheckboxGroupContext } from '../internal/context/checkbox-group-context';
4
+
5
+ /**
6
+ * __Dropdown item checkbox group__
7
+ *
8
+ * A wrapping element for dropdown menu checkbox items.
9
+ *
10
+ */
11
+ var DropdownItemCheckboxGroup = function DropdownItemCheckboxGroup(props) {
12
+ var children = props.children,
13
+ id = props.id;
14
+ return /*#__PURE__*/React.createElement(CheckboxGroupContext.Provider, {
15
+ value: id
16
+ }, /*#__PURE__*/React.createElement(Section, props, children));
17
+ };
18
+
19
+ export default DropdownItemCheckboxGroup;
@@ -0,0 +1,81 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
4
+ var _excluded = ["id", "isSelected", "defaultSelected", "onClick", "shouldTitleWrap", "shouldDescriptionWrap"];
5
+ import React, { useCallback, useEffect, useState } from 'react';
6
+ import noop from '@atlaskit/ds-lib/noop';
7
+ import CheckboxIcon from '@atlaskit/icon/glyph/checkbox';
8
+ import ButtonItem from '@atlaskit/menu/button-item';
9
+ import useCheckboxState from '../internal/hooks/use-checkbox-state';
10
+ import useRegisterItemWithFocusManager from '../internal/hooks/use-register-item-with-focus-manager';
11
+ import getIconColors from '../internal/utils/get-icon-colors';
12
+ import isVoiceOverSupported from '../internal/utils/is-voice-over-supported';
13
+
14
+ /**
15
+ * __Dropdown item checkbox__
16
+ *
17
+ * A dropdown item checkbox creates groups that have multiple selections.
18
+ *
19
+ * - [Examples](https://atlassian.design/components/dropdown-menu/dropdown-item-checkbox/examples)
20
+ * - [Code](https://atlassian.design/components/dropdown-menu/dropdown-item-checkbox/code)
21
+ * - [Usage](https://atlassian.design/components/dropdown-menu/dropdown-item-checkbox/usage)
22
+ */
23
+ var DropdownItemCheckbox = function DropdownItemCheckbox(props) {
24
+ var id = props.id,
25
+ isSelected = props.isSelected,
26
+ defaultSelected = props.defaultSelected,
27
+ _props$onClick = props.onClick,
28
+ providedOnClick = _props$onClick === void 0 ? noop : _props$onClick,
29
+ _props$shouldTitleWra = props.shouldTitleWrap,
30
+ shouldTitleWrap = _props$shouldTitleWra === void 0 ? true : _props$shouldTitleWra,
31
+ _props$shouldDescript = props.shouldDescriptionWrap,
32
+ shouldDescriptionWrap = _props$shouldDescript === void 0 ? true : _props$shouldDescript,
33
+ rest = _objectWithoutProperties(props, _excluded);
34
+
35
+ if (process.env.NODE_ENV !== 'production' && typeof isSelected !== 'undefined' && typeof defaultSelected !== 'undefined') {
36
+ // eslint-disable-next-line no-console
37
+ console.warn("[DropdownItemCheckbox] You've used both `defaultSelected` and `isSelected` props. This is dangerous and can lead to unexpected results. Use one or the other depending if you want to control the components state yourself.");
38
+ }
39
+
40
+ var _useCheckboxState = useCheckboxState({
41
+ id: id,
42
+ isSelected: isSelected,
43
+ defaultSelected: defaultSelected
44
+ }),
45
+ _useCheckboxState2 = _slicedToArray(_useCheckboxState, 2),
46
+ selected = _useCheckboxState2[0],
47
+ setSelected = _useCheckboxState2[1];
48
+
49
+ var _useState = useState(getIconColors(defaultSelected)),
50
+ _useState2 = _slicedToArray(_useState, 2),
51
+ iconColors = _useState2[0],
52
+ setIconColors = _useState2[1];
53
+
54
+ var onClickHandler = useCallback(function (event) {
55
+ setSelected(function (selected) {
56
+ return !selected;
57
+ });
58
+ providedOnClick(event);
59
+ }, [providedOnClick, setSelected]);
60
+ useEffect(function () {
61
+ setIconColors(getIconColors(selected));
62
+ }, [selected]);
63
+ var itemRef = useRegisterItemWithFocusManager();
64
+ return /*#__PURE__*/React.createElement(ButtonItem, _extends({
65
+ id: id,
66
+ onClick: onClickHandler,
67
+ role: isVoiceOverSupported() ? 'checkbox' : 'menuitemcheckbox',
68
+ "aria-checked": selected,
69
+ shouldTitleWrap: shouldTitleWrap,
70
+ shouldDescriptionWrap: shouldDescriptionWrap,
71
+ iconBefore: /*#__PURE__*/React.createElement(CheckboxIcon, {
72
+ label: "",
73
+ size: "medium",
74
+ primaryColor: iconColors.primary,
75
+ secondaryColor: iconColors.secondary
76
+ }),
77
+ ref: itemRef
78
+ }, rest));
79
+ };
80
+
81
+ export default DropdownItemCheckbox;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * __Section__
3
+ *
4
+ * A dropdown item group includes all the actions or items in a dropdown menu.
5
+ *
6
+ * - [Examples](https://atlassian.design/components/dropdown-menu/dropdown-item-group/examples)
7
+ * - [Code](https://atlassian.design/components/dropdown-menu/dropdown-item-group/code)
8
+ * - [Usage](https://atlassian.design/components/dropdown-menu/dropdown-item-group/usage)
9
+ */
10
+ import Section from '@atlaskit/menu/section';
11
+ export default Section;
@@ -0,0 +1,52 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ var _excluded = ["elemBefore", "elemAfter", "href", "shouldTitleWrap", "shouldDescriptionWrap"];
4
+ import React from 'react';
5
+ import ButtonItem from '@atlaskit/menu/button-item';
6
+ import LinkItem from '@atlaskit/menu/link-item';
7
+ import useRegisterItemWithFocusManager from './internal/hooks/use-register-item-with-focus-manager';
8
+
9
+ /**
10
+ * __Dropdown menu item__
11
+ *
12
+ * A dropdown item populates the dropdown menu with items. Every item should be inside a dropdown item group.
13
+ *
14
+ * - [Examples](https://atlassian.design/components/dropdown-item/examples)
15
+ * - [Code](https://atlassian.design/components/dropdown-item/code)
16
+ * - [Usage](https://atlassian.design/components/dropdown-item/usage)
17
+ */
18
+ var DropdownMenuItem = function DropdownMenuItem(props) {
19
+ var elemBefore = props.elemBefore,
20
+ elemAfter = props.elemAfter,
21
+ href = props.href,
22
+ _props$shouldTitleWra = props.shouldTitleWrap,
23
+ shouldTitleWrap = _props$shouldTitleWra === void 0 ? true : _props$shouldTitleWra,
24
+ _props$shouldDescript = props.shouldDescriptionWrap,
25
+ shouldDescriptionWrap = _props$shouldDescript === void 0 ? true : _props$shouldDescript,
26
+ rest = _objectWithoutProperties(props, _excluded);
27
+
28
+ var itemRef = useRegisterItemWithFocusManager();
29
+
30
+ if (href) {
31
+ return /*#__PURE__*/React.createElement(LinkItem, _extends({
32
+ href: href,
33
+ iconBefore: elemBefore,
34
+ iconAfter: elemAfter,
35
+ role: "menuitem",
36
+ ref: itemRef,
37
+ shouldTitleWrap: shouldTitleWrap,
38
+ shouldDescriptionWrap: shouldDescriptionWrap
39
+ }, rest));
40
+ } else {
41
+ return /*#__PURE__*/React.createElement(ButtonItem, _extends({
42
+ role: "menuitem",
43
+ iconBefore: elemBefore,
44
+ iconAfter: elemAfter,
45
+ ref: itemRef,
46
+ shouldTitleWrap: shouldTitleWrap,
47
+ shouldDescriptionWrap: shouldDescriptionWrap
48
+ }, rest));
49
+ }
50
+ };
51
+
52
+ export default DropdownMenuItem;
@@ -0,0 +1,168 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ var _excluded = ["ref"];
5
+
6
+ /** @jsx jsx */
7
+ import { useCallback, useState } from 'react';
8
+ import { css, jsx } from '@emotion/core';
9
+ import Button from '@atlaskit/button/standard-button';
10
+ import { KEY_DOWN } from '@atlaskit/ds-lib/keycodes';
11
+ import noop from '@atlaskit/ds-lib/noop';
12
+ import useControlledState from '@atlaskit/ds-lib/use-controlled';
13
+ import useFocus from '@atlaskit/ds-lib/use-focus-event';
14
+ import useKeydownEvent from '@atlaskit/ds-lib/use-keydown-event';
15
+ import ExpandIcon from '@atlaskit/icon/glyph/chevron-down';
16
+ import Popup from '@atlaskit/popup';
17
+ import Spinner from '@atlaskit/spinner';
18
+ import { gridSize as gridSizeFn, layers } from '@atlaskit/theme/constants';
19
+ import VisuallyHidden from '@atlaskit/visually-hidden';
20
+ import FocusManager from './internal/components/focus-manager';
21
+ import MenuWrapper from './internal/components/menu-wrapper';
22
+ import SelectionStore from './internal/context/selection-store';
23
+ var gridSize = gridSizeFn();
24
+ var spinnerContainerStyles = css({
25
+ display: 'flex',
26
+ minWidth: "".concat(gridSize * 20, "px"),
27
+ padding: "".concat(gridSize * 2.5, "px"),
28
+ justifyContent: 'center'
29
+ });
30
+ var MAX_HEIGHT = "calc(100vh - ".concat(gridSize * 2, "px)");
31
+ /**
32
+ * __Dropdown menu__
33
+ *
34
+ * A dropdown menu displays a list of actions or options to a user.
35
+ *
36
+ * - [Examples](https://atlassian.design/components/dropdown-menu/examples)
37
+ * - [Code](https://atlassian.design/components/dropdown-menu/code)
38
+ * - [Usage](https://atlassian.design/components/dropdown-menu/usage)
39
+ */
40
+
41
+ var DropdownMenu = function DropdownMenu(props) {
42
+ var _props$defaultOpen = props.defaultOpen,
43
+ defaultOpen = _props$defaultOpen === void 0 ? false : _props$defaultOpen,
44
+ isOpen = props.isOpen,
45
+ _props$onOpenChange = props.onOpenChange,
46
+ onOpenChange = _props$onOpenChange === void 0 ? noop : _props$onOpenChange,
47
+ children = props.children,
48
+ _props$placement = props.placement,
49
+ placement = _props$placement === void 0 ? 'bottom-start' : _props$placement,
50
+ Trigger = props.trigger,
51
+ _props$shouldFlip = props.shouldFlip,
52
+ shouldFlip = _props$shouldFlip === void 0 ? true : _props$shouldFlip,
53
+ _props$isLoading = props.isLoading,
54
+ isLoading = _props$isLoading === void 0 ? false : _props$isLoading,
55
+ _props$autoFocus = props.autoFocus,
56
+ autoFocus = _props$autoFocus === void 0 ? false : _props$autoFocus,
57
+ testId = props.testId,
58
+ _props$statusLabel = props.statusLabel,
59
+ statusLabel = _props$statusLabel === void 0 ? 'Loading' : _props$statusLabel;
60
+
61
+ var _useControlledState = useControlledState(isOpen, function () {
62
+ return defaultOpen;
63
+ }),
64
+ _useControlledState2 = _slicedToArray(_useControlledState, 2),
65
+ isLocalOpen = _useControlledState2[0],
66
+ setLocalIsOpen = _useControlledState2[1];
67
+
68
+ var _useState = useState(false),
69
+ _useState2 = _slicedToArray(_useState, 2),
70
+ isTriggeredUsingKeyboard = _useState2[0],
71
+ setTriggeredUsingKeyboard = _useState2[1];
72
+
73
+ var handleTriggerClicked = useCallback(function (event) {
74
+ var newValue = !isLocalOpen;
75
+ var clientX = event.clientX,
76
+ clientY = event.clientY,
77
+ type = event.type;
78
+
79
+ if (type === 'keydown') {
80
+ setTriggeredUsingKeyboard(true);
81
+ } else if (clientX === 0 || clientY === 0) {
82
+ // Hitting enter/space is registered as a click
83
+ // with both clientX and clientY === 0
84
+ setTriggeredUsingKeyboard(true);
85
+ }
86
+
87
+ setLocalIsOpen(newValue);
88
+ onOpenChange({
89
+ isOpen: newValue,
90
+ event: event
91
+ });
92
+ }, [onOpenChange, isLocalOpen, setLocalIsOpen]);
93
+ var handleOnClose = useCallback(function () {
94
+ var newValue = false;
95
+ setLocalIsOpen(newValue);
96
+ onOpenChange({
97
+ isOpen: newValue
98
+ });
99
+ }, [onOpenChange, setLocalIsOpen]);
100
+
101
+ var _useFocus = useFocus(),
102
+ isFocused = _useFocus.isFocused,
103
+ bindFocus = _useFocus.bindFocus;
104
+
105
+ var handleDownArrow = function handleDownArrow(e) {
106
+ if (e.key === KEY_DOWN) {
107
+ // prevent page scroll
108
+ e.preventDefault();
109
+ handleTriggerClicked(e);
110
+ }
111
+ };
112
+
113
+ useKeydownEvent(handleDownArrow, isFocused);
114
+
115
+ var renderTrigger = function renderTrigger(triggerProps) {
116
+ if (typeof Trigger === 'function') {
117
+ var ref = triggerProps.ref,
118
+ providedProps = _objectWithoutProperties(triggerProps, _excluded);
119
+
120
+ return jsx(Trigger, _extends({}, providedProps, bindFocus, {
121
+ triggerRef: ref,
122
+ isSelected: isLocalOpen,
123
+ onClick: handleTriggerClicked,
124
+ testId: testId && "".concat(testId, "--trigger")
125
+ }));
126
+ }
127
+
128
+ return jsx(Button, _extends({}, triggerProps, bindFocus, {
129
+ isSelected: isLocalOpen,
130
+ iconAfter: jsx(ExpandIcon, {
131
+ size: "medium",
132
+ label: "expand"
133
+ }),
134
+ onClick: handleTriggerClicked,
135
+ testId: testId && "".concat(testId, "--trigger")
136
+ }), Trigger);
137
+ };
138
+
139
+ var fallbackPlacements = ['bottom', 'bottom-end', 'right-start', 'left-start', 'auto'];
140
+ return jsx(SelectionStore, null, jsx(Popup, {
141
+ shouldFlip: shouldFlip,
142
+ isOpen: isLocalOpen,
143
+ onClose: handleOnClose,
144
+ zIndex: layers.modal(),
145
+ placement: placement,
146
+ fallbackPlacements: fallbackPlacements,
147
+ testId: testId && "".concat(testId, "--content"),
148
+ trigger: renderTrigger,
149
+ shouldUseCaptureOnOutsideClick: true,
150
+ content: function content(_ref) {
151
+ var setInitialFocusRef = _ref.setInitialFocusRef;
152
+ return jsx(FocusManager, null, jsx(MenuWrapper, {
153
+ maxHeight: MAX_HEIGHT,
154
+ maxWidth: 800,
155
+ onClose: handleOnClose,
156
+ setInitialFocusRef: isTriggeredUsingKeyboard || autoFocus ? setInitialFocusRef : undefined
157
+ }, isLoading ? jsx("div", {
158
+ css: spinnerContainerStyles
159
+ }, jsx(Spinner, {
160
+ size: "small"
161
+ }), jsx(VisuallyHidden, {
162
+ role: "status"
163
+ }, statusLabel)) : children));
164
+ }
165
+ }));
166
+ };
167
+
168
+ export default DropdownMenu;
package/dist/esm/index.js CHANGED
@@ -1,11 +1,7 @@
1
- // menu exports
2
- export { default } from './components/DropdownMenu';
3
- export { default as DropdownMenuStateless } from './components/DropdownMenuStateless'; // Item exports
4
-
5
- export { default as DropdownItem } from './components/item/DropdownItem';
6
- export { default as DropdownItemRadio } from './components/item/DropdownItemRadio';
7
- export { default as DropdownItemCheckbox } from './components/item/DropdownItemCheckbox'; // ItemGroup exports
8
-
9
- export { default as DropdownItemGroup } from './components/group/DropdownItemGroup';
10
- export { default as DropdownItemGroupRadio } from './components/group/DropdownItemGroupRadio';
11
- export { default as DropdownItemGroupCheckbox } from './components/group/DropdownItemGroupCheckbox'; // Types
1
+ export { default } from './dropdown-menu';
2
+ export { default as DropdownItemGroup } from './dropdown-menu-item-group';
3
+ export { default as DropdownItem } from './dropdown-menu-item';
4
+ export { default as DropdownItemCheckbox } from './checkbox/dropdown-item-checkbox';
5
+ export { default as DropdownItemCheckboxGroup } from './checkbox/dropdown-item-checkbox-group';
6
+ export { default as DropdownItemRadio } from './radio/dropdown-item-radio';
7
+ export { default as DropdownItemRadioGroup } from './radio/dropdown-item-radio-group';
@@ -0,0 +1,39 @@
1
+ import React, { createContext, useCallback, useRef } from 'react';
2
+ import useKeydownEvent from '@atlaskit/ds-lib/use-keydown-event';
3
+ import handleFocus from '../utils/handle-focus';
4
+ /**
5
+ *
6
+ *
7
+ * Context provider which maintains the list of focusable elements and a method to
8
+ * register new menu items.
9
+ * This list drives the keyboard navgation of the menu.
10
+ *
11
+ */
12
+
13
+ export var FocusManagerContext = /*#__PURE__*/createContext({
14
+ menuItemRefs: [],
15
+ registerRef: function registerRef(ref) {}
16
+ });
17
+ /**
18
+ * Focus manager logic
19
+ */
20
+
21
+ var FocusManager = function FocusManager(_ref) {
22
+ var children = _ref.children;
23
+ var menuItemRefs = useRef([]);
24
+ var registerRef = useCallback(function (ref) {
25
+ if (ref && !menuItemRefs.current.includes(ref)) {
26
+ menuItemRefs.current.push(ref);
27
+ }
28
+ }, []);
29
+ useKeydownEvent(handleFocus(menuItemRefs.current));
30
+ var contextValue = {
31
+ menuItemRefs: menuItemRefs.current,
32
+ registerRef: registerRef
33
+ };
34
+ return /*#__PURE__*/React.createElement(FocusManagerContext.Provider, {
35
+ value: contextValue
36
+ }, children);
37
+ };
38
+
39
+ export default FocusManager;
@@ -0,0 +1,45 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ var _excluded = ["onClose", "setInitialFocusRef"];
4
+ import React, { useContext } from 'react';
5
+ import MenuGroup from '@atlaskit/menu/menu-group';
6
+ import { FocusManagerContext } from '../components/focus-manager';
7
+ import isCheckboxItem from '../utils/is-checkbox-item';
8
+ import isRadioItem from '../utils/is-radio-item';
9
+ /**
10
+ *
11
+ * MenuWrapper wraps all the menu items.
12
+ * It handles the logic to close the menu when a MenuItem is clicked, but leaves it open
13
+ * if a CheckboxItem or RadioItem is clicked.
14
+ * It also sets focus to the first menu item when opened.
15
+ */
16
+
17
+ var MenuWrapper = function MenuWrapper(_ref) {
18
+ var onClose = _ref.onClose,
19
+ setInitialFocusRef = _ref.setInitialFocusRef,
20
+ props = _objectWithoutProperties(_ref, _excluded);
21
+
22
+ var _useContext = useContext(FocusManagerContext),
23
+ menuItemRefs = _useContext.menuItemRefs;
24
+
25
+ var closeOnMenuItemClick = function closeOnMenuItemClick(e) {
26
+ var isTargetMenuItemOrDecendant = menuItemRefs.some(function (menuItem) {
27
+ var isCheckboxOrRadio = isCheckboxItem(menuItem) || isRadioItem(menuItem);
28
+ return menuItem.contains(e.target) && !isCheckboxOrRadio;
29
+ }); // Close menu if the click is triggered from a MenuItem or
30
+ // its decendant. Don't close the menu if the click is triggered
31
+ // from a MenuItemRadio or MenuItemCheckbox so that the user can
32
+ // select multiple items.
33
+
34
+ if (isTargetMenuItemOrDecendant && onClose) {
35
+ onClose();
36
+ }
37
+ };
38
+
39
+ setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]);
40
+ return /*#__PURE__*/React.createElement(MenuGroup, _extends({
41
+ onClick: closeOnMenuItemClick
42
+ }, props));
43
+ };
44
+
45
+ export default MenuWrapper;
@@ -0,0 +1,6 @@
1
+ import { createContext } from 'react';
2
+ /**
3
+ * Holds the unique identifier for the checkbox group.
4
+ */
5
+
6
+ export var CheckboxGroupContext = /*#__PURE__*/createContext('');
@@ -0,0 +1,58 @@
1
+ import React, { createContext, useMemo, useRef } from 'react';
2
+ import noop from '@atlaskit/ds-lib/noop';
3
+
4
+ /**
5
+ *
6
+ * SelectionStoreContext maintains the state of the selected items
7
+ * and getter setters.
8
+ *
9
+ */
10
+ export var SelectionStoreContext = /*#__PURE__*/createContext({
11
+ setItemState: noop,
12
+ getItemState: function getItemState() {
13
+ return undefined;
14
+ },
15
+ setGroupState: noop,
16
+ getGroupState: function getGroupState() {
17
+ return {};
18
+ }
19
+ });
20
+
21
+ /**
22
+ * Selection store will persist data as long as it remains mounted.
23
+ * It handles the uncontrolled story for dropdown menu when the menu
24
+ * items can be mounted/unmounted depending if the menu is open or closed.
25
+ */
26
+ var SelectionStore = function SelectionStore(props) {
27
+ var children = props.children;
28
+ var store = useRef({});
29
+ var context = useMemo(function () {
30
+ return {
31
+ setItemState: function setItemState(group, id, value) {
32
+ if (!store.current[group]) {
33
+ store.current[group] = {};
34
+ }
35
+
36
+ store.current[group][id] = value;
37
+ },
38
+ getItemState: function getItemState(group, id) {
39
+ if (!store.current[group]) {
40
+ return undefined;
41
+ }
42
+
43
+ return store.current[group][id];
44
+ },
45
+ setGroupState: function setGroupState(group, value) {
46
+ store.current[group] = value;
47
+ },
48
+ getGroupState: function getGroupState(group) {
49
+ return store.current[group] || {};
50
+ }
51
+ };
52
+ }, []);
53
+ return /*#__PURE__*/React.createElement(SelectionStoreContext.Provider, {
54
+ value: context
55
+ }, children);
56
+ };
57
+
58
+ export default SelectionStore;
@@ -0,0 +1,55 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { useCallback, useContext, useState } from 'react';
3
+ import { CheckboxGroupContext } from '../context/checkbox-group-context';
4
+ import { SelectionStoreContext } from '../context/selection-store';
5
+
6
+ /**
7
+ * Custom hook to handle checkbox state for dropdown menu.
8
+ * It works in tandem with the selection store context when the
9
+ * component is uncontrolled.
10
+ */
11
+ var useCheckboxState = function useCheckboxState(_ref) {
12
+ var isSelected = _ref.isSelected,
13
+ id = _ref.id,
14
+ defaultSelected = _ref.defaultSelected;
15
+
16
+ var _useContext = useContext(SelectionStoreContext),
17
+ setItemState = _useContext.setItemState,
18
+ getItemState = _useContext.getItemState;
19
+
20
+ var groupId = useContext(CheckboxGroupContext);
21
+ var persistedIsSelected = getItemState(groupId, id);
22
+
23
+ var _useState = useState( // Initial state is set depending on value being defined or not.
24
+ // This state is only utilised if the checkbox is uncontrolled.
25
+ function () {
26
+ return persistedIsSelected !== undefined ? persistedIsSelected : defaultSelected || false;
27
+ }),
28
+ _useState2 = _slicedToArray(_useState, 2),
29
+ localIsSelected = _useState2[0],
30
+ setLocalIsSelected = _useState2[1];
31
+
32
+ var setLocalState = useCallback(function (newValue) {
33
+ var nextValue = newValue(persistedIsSelected);
34
+ setLocalIsSelected(nextValue);
35
+ setItemState(groupId, id, nextValue);
36
+ }, [setItemState, persistedIsSelected, groupId, id]); // Checkbox is controlled - do nothing!
37
+
38
+ if (typeof isSelected === 'boolean') {
39
+ return [isSelected, function () {
40
+ return false;
41
+ }];
42
+ } // Checkbox is going through its first render pass!
43
+
44
+
45
+ if (persistedIsSelected === undefined) {
46
+ // Set the item so we have this state to access next time the checkbox renders (either by mounting or re-rendering!)
47
+ setItemState(groupId, id, defaultSelected || false);
48
+ } // Return the value and setter!
49
+ // Remember this flow is only returned if the checkbox is uncontrolled.
50
+
51
+
52
+ return [localIsSelected, setLocalState];
53
+ };
54
+
55
+ export default useCheckboxState;
@@ -0,0 +1,70 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+
4
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
5
+
6
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
7
+
8
+ import { useCallback, useContext, useEffect, useState } from 'react';
9
+ import { RadioGroupContext } from '../../radio/dropdown-item-radio-group';
10
+ import { SelectionStoreContext } from '../context/selection-store';
11
+ import resetOptionsInGroup from '../utils/reset-options-in-group';
12
+
13
+ function useRadioState(_ref) {
14
+ var id = _ref.id,
15
+ isSelected = _ref.isSelected,
16
+ defaultSelected = _ref.defaultSelected;
17
+
18
+ var _useContext = useContext(SelectionStoreContext),
19
+ setGroupState = _useContext.setGroupState,
20
+ getGroupState = _useContext.getGroupState;
21
+
22
+ var _useContext2 = useContext(RadioGroupContext),
23
+ group = _useContext2.id,
24
+ radioGroupState = _useContext2.radioGroupState,
25
+ selectRadioItem = _useContext2.selectRadioItem;
26
+
27
+ var persistedIsSelected = radioGroupState[id];
28
+
29
+ var _useState = useState(function () {
30
+ return persistedIsSelected !== undefined ? persistedIsSelected : defaultSelected || false;
31
+ }),
32
+ _useState2 = _slicedToArray(_useState, 2),
33
+ localIsSelected = _useState2[0],
34
+ setLocalIsSelected = _useState2[1];
35
+
36
+ var setLocalState = useCallback(function (newValue) {
37
+ if (!persistedIsSelected) {
38
+ var nextValue = newValue(persistedIsSelected);
39
+ selectRadioItem(id, nextValue);
40
+ setLocalIsSelected(nextValue);
41
+ }
42
+ }, [persistedIsSelected, id, selectRadioItem]);
43
+ /**
44
+ * - radio state changes any time a radio child is changed
45
+ * - when it changes we want all radio buttons to update their local state
46
+ * - it takes the value from radio group state and applies it locally if it exists which it will only exist, if it is selected
47
+ */
48
+
49
+ useEffect(function () {
50
+ setLocalIsSelected(function () {
51
+ var existing = radioGroupState[id];
52
+ return existing !== undefined ? existing : defaultSelected || false;
53
+ });
54
+ }, [radioGroupState, group, id, defaultSelected]);
55
+
56
+ if (typeof isSelected === 'boolean') {
57
+ return [isSelected, function () {
58
+ return false;
59
+ }];
60
+ }
61
+
62
+ if (persistedIsSelected === undefined) {
63
+ var existing = getGroupState(group);
64
+ setGroupState(group, _objectSpread(_objectSpread({}, resetOptionsInGroup(existing || {})), {}, _defineProperty({}, id, defaultSelected || false)));
65
+ }
66
+
67
+ return [localIsSelected, setLocalState];
68
+ }
69
+
70
+ export default useRadioState;
@@ -0,0 +1,19 @@
1
+ import { useContext, useEffect, useRef } from 'react';
2
+ import { FocusManagerContext } from '../components/focus-manager'; // This function is called whenever a MenuItem mounts.
3
+ // The refs stored in the context are used to programatically
4
+ // control focus on a user navigates using the keyboard.
5
+
6
+ function useRegisterItemWithFocusManager() {
7
+ var _useContext = useContext(FocusManagerContext),
8
+ registerRef = _useContext.registerRef;
9
+
10
+ var itemRef = useRef(null);
11
+ useEffect(function () {
12
+ if (itemRef.current !== null) {
13
+ registerRef(itemRef.current);
14
+ }
15
+ }, [registerRef]);
16
+ return itemRef;
17
+ }
18
+
19
+ export default useRegisterItemWithFocusManager;
@@ -0,0 +1,17 @@
1
+ import { B400, N40 } from '@atlaskit/theme/colors';
2
+
3
+ var getIconColors = function getIconColors(isSelected) {
4
+ if (isSelected) {
5
+ return {
6
+ primary: "var(--ds-background-boldBrand-resting, ".concat(B400, ")"),
7
+ secondary: "var(--ds-background-default, ".concat(N40, ")")
8
+ };
9
+ }
10
+
11
+ return {
12
+ primary: "var(--ds-border-neutral, ".concat(N40, ")"),
13
+ secondary: "var(--ds-UNSAFE_util-transparent, ".concat(N40, ")")
14
+ };
15
+ };
16
+
17
+ export default getIconColors;