@carbon/react 1.47.0 → 1.48.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 (76) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +914 -839
  2. package/es/components/Button/Button.d.ts +1 -3
  3. package/es/components/Button/Button.js +9 -3
  4. package/es/components/ComboButton/index.js +1 -0
  5. package/es/components/ComposedModal/ModalHeader.js +10 -4
  6. package/es/components/DangerButton/DangerButton.js +2 -2
  7. package/es/components/DataTable/TableExpandHeader.d.ts +1 -1
  8. package/es/components/DataTable/TableExpandRow.d.ts +1 -1
  9. package/es/components/DataTable/TableExpandRow.js +0 -1
  10. package/es/components/DataTable/TableHeader.d.ts +10 -1
  11. package/es/components/DataTable/index.d.ts +3 -2
  12. package/es/components/DatePicker/DatePicker.js +3 -2
  13. package/es/components/Dropdown/Dropdown.d.ts +3 -2
  14. package/es/components/Dropdown/index.d.ts +2 -2
  15. package/es/components/ExpandableSearch/ExpandableSearch.js +6 -3
  16. package/es/components/IconButton/index.d.ts +70 -0
  17. package/es/components/IconButton/index.js +6 -5
  18. package/es/components/ListBox/ListBoxMenuIcon.d.ts +3 -6
  19. package/es/components/ListBox/ListBoxMenuIcon.js +4 -8
  20. package/es/components/ListBox/index.d.ts +1 -0
  21. package/es/components/Menu/Menu.d.ts +59 -0
  22. package/es/components/Menu/Menu.js +33 -10
  23. package/es/components/Menu/MenuContext.d.ts +32 -0
  24. package/es/components/Menu/MenuItem.d.ts +119 -0
  25. package/es/components/Menu/MenuItem.js +17 -12
  26. package/es/components/Menu/index.d.ts +9 -0
  27. package/es/components/MenuButton/index.js +1 -0
  28. package/es/components/Modal/Modal.d.ts +1 -1
  29. package/es/components/Modal/Modal.js +10 -6
  30. package/es/components/OverflowMenu/next/index.js +1 -0
  31. package/es/components/Slug/index.js +5 -1
  32. package/es/components/Tooltip/Tooltip.js +1 -9
  33. package/es/components/TreeView/TreeNode.js +11 -3
  34. package/es/components/TreeView/TreeView.js +1 -1
  35. package/es/components/UIShell/HeaderMenu.js +1 -1
  36. package/es/components/UIShell/SwitcherItem.d.ts +4 -0
  37. package/es/components/UIShell/SwitcherItem.js +4 -0
  38. package/es/index.js +3 -3
  39. package/lib/components/Button/Button.d.ts +1 -3
  40. package/lib/components/Button/Button.js +9 -3
  41. package/lib/components/ComboButton/index.js +1 -0
  42. package/lib/components/ComposedModal/ModalHeader.js +10 -4
  43. package/lib/components/DangerButton/DangerButton.js +2 -2
  44. package/lib/components/DataTable/TableExpandHeader.d.ts +1 -1
  45. package/lib/components/DataTable/TableExpandRow.d.ts +1 -1
  46. package/lib/components/DataTable/TableExpandRow.js +0 -1
  47. package/lib/components/DataTable/TableHeader.d.ts +10 -1
  48. package/lib/components/DataTable/index.d.ts +3 -2
  49. package/lib/components/DatePicker/DatePicker.js +3 -2
  50. package/lib/components/Dropdown/Dropdown.d.ts +3 -2
  51. package/lib/components/Dropdown/index.d.ts +2 -2
  52. package/lib/components/ExpandableSearch/ExpandableSearch.js +5 -2
  53. package/lib/components/IconButton/index.d.ts +70 -0
  54. package/lib/components/IconButton/index.js +6 -4
  55. package/lib/components/ListBox/ListBoxMenuIcon.d.ts +3 -6
  56. package/lib/components/ListBox/ListBoxMenuIcon.js +3 -8
  57. package/lib/components/ListBox/index.d.ts +1 -0
  58. package/lib/components/Menu/Menu.d.ts +59 -0
  59. package/lib/components/Menu/Menu.js +33 -10
  60. package/lib/components/Menu/MenuContext.d.ts +32 -0
  61. package/lib/components/Menu/MenuItem.d.ts +119 -0
  62. package/lib/components/Menu/MenuItem.js +17 -12
  63. package/lib/components/Menu/index.d.ts +9 -0
  64. package/lib/components/MenuButton/index.js +1 -0
  65. package/lib/components/Modal/Modal.d.ts +1 -1
  66. package/lib/components/Modal/Modal.js +10 -6
  67. package/lib/components/OverflowMenu/next/index.js +1 -0
  68. package/lib/components/Slug/index.js +5 -1
  69. package/lib/components/Tooltip/Tooltip.js +0 -8
  70. package/lib/components/TreeView/TreeNode.js +11 -3
  71. package/lib/components/TreeView/TreeView.js +1 -1
  72. package/lib/components/UIShell/HeaderMenu.js +1 -1
  73. package/lib/components/UIShell/SwitcherItem.d.ts +4 -0
  74. package/lib/components/UIShell/SwitcherItem.js +4 -0
  75. package/lib/index.js +9 -8
  76. package/package.json +7 -7
@@ -65,8 +65,6 @@ interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement>
65
65
  tooltipPosition?: ButtonTooltipPosition;
66
66
  }
67
67
  export type ButtonProps<T extends React.ElementType> = PolymorphicProps<T, ButtonBaseProps>;
68
- export interface ButtonComponent {
69
- <T extends React.ElementType>(props: ButtonProps<T>, context?: any): React.ReactElement<any, any> | null;
70
- }
68
+ export type ButtonComponent = <T extends React.ElementType>(props: ButtonProps<T>, context?: any) => React.ReactElement<any, any> | null;
71
69
  declare const _default: ButtonComponent;
72
70
  export default _default;
@@ -18,6 +18,12 @@ const ButtonKinds = ['primary', 'secondary', 'danger', 'ghost', 'danger--primary
18
18
  const ButtonSizes = ['sm', 'md', 'lg', 'xl', '2xl'];
19
19
  const ButtonTooltipAlignments = ['start', 'center', 'end'];
20
20
  const ButtonTooltipPositions = ['top', 'right', 'bottom', 'left'];
21
+ function isIconOnlyButton(hasIconOnly, _kind) {
22
+ if (hasIconOnly === true) {
23
+ return true;
24
+ }
25
+ return false;
26
+ }
21
27
  const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref) {
22
28
  let {
23
29
  as,
@@ -50,7 +56,6 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
50
56
  // Prevent clicks on the tooltip from triggering the button click event
51
57
  if (evt.target === tooltipRef.current) {
52
58
  evt.preventDefault();
53
- return;
54
59
  }
55
60
  };
56
61
  const buttonClasses = cx(className, {
@@ -113,7 +118,7 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
113
118
  component = 'a';
114
119
  otherProps = anchorProps;
115
120
  }
116
- if (!hasIconOnly) {
121
+ if (!isIconOnlyButton(hasIconOnly)) {
117
122
  return /*#__PURE__*/React__default.createElement(component, {
118
123
  onMouseEnter,
119
124
  onMouseLeave,
@@ -151,7 +156,7 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
151
156
  onFocus: onFocus,
152
157
  onBlur: onBlur,
153
158
  onClick: composeEventHandlers([onClick, handleClick])
154
- }, rest, commonProps, otherProps), iconOnlyImage ? iconOnlyImage : children);
159
+ }, rest, commonProps, otherProps), iconOnlyImage ?? children);
155
160
  }
156
161
  });
157
162
  Button.displayName = 'Button';
@@ -206,6 +211,7 @@ Button.propTypes = {
206
211
  /**
207
212
  * Specify the kind of Button you want to create
208
213
  */
214
+ // TODO: this should be either ButtonKinds or IconButtonKinds based on the value of "hasIconOnly"
209
215
  kind: PropTypes.oneOf(ButtonKinds),
210
216
  /**
211
217
  * Provide an optional function to be called when the button element
@@ -14,6 +14,7 @@ import { IconButton } from '../IconButton/index.js';
14
14
  import Button from '../Button/Button.js';
15
15
  import '../Button/Button.Skeleton.js';
16
16
  import { Menu } from '../Menu/Menu.js';
17
+ import '../Menu/MenuItem.js';
17
18
  import { useAttachedMenu } from '../../internal/useAttachedMenu.js';
18
19
  import { useId } from '../../internal/useId.js';
19
20
  import { useMergedRefs } from '../../internal/useMergedRefs.js';
@@ -11,6 +11,7 @@ import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { Close } from '@carbon/icons-react';
13
13
  import { usePrefix } from '../../internal/usePrefix.js';
14
+ import { IconButton } from '../IconButton/index.js';
14
15
 
15
16
  const ModalHeader = /*#__PURE__*/React__default.forwardRef(function ModalHeader(_ref, ref) {
16
17
  let {
@@ -45,16 +46,21 @@ const ModalHeader = /*#__PURE__*/React__default.forwardRef(function ModalHeader(
45
46
  className: labelClass
46
47
  }, label), title && /*#__PURE__*/React__default.createElement("h3", {
47
48
  className: titleClass
48
- }, title), children, /*#__PURE__*/React__default.createElement("button", {
49
- onClick: handleCloseButtonClick,
49
+ }, title), children, /*#__PURE__*/React__default.createElement("div", {
50
+ className: `${prefix}--modal-close-button`
51
+ }, /*#__PURE__*/React__default.createElement(IconButton, {
50
52
  className: closeClass,
53
+ label: iconDescription,
54
+ onClick: handleCloseButtonClick,
51
55
  title: iconDescription,
52
56
  "aria-label": iconDescription,
53
- type: "button"
57
+ align: "left"
54
58
  }, /*#__PURE__*/React__default.createElement(Close, {
55
59
  size: 20,
60
+ "aria-hidden": "true",
61
+ tabIndex: "-1",
56
62
  className: closeIconClass
57
- })));
63
+ }))));
58
64
  });
59
65
  ModalHeader.propTypes = {
60
66
  /**
@@ -10,8 +10,8 @@ import React__default from 'react';
10
10
  import Button from '../Button/Button.js';
11
11
  import '../Button/Button.Skeleton.js';
12
12
 
13
- const DangerButton = props => /*#__PURE__*/React__default.createElement(Button, _extends({
13
+ const DangerButton = props => /*#__PURE__*/React__default.createElement(Button, _extends({}, props, {
14
14
  kind: "danger"
15
- }, props));
15
+ }));
16
16
 
17
17
  export { DangerButton as default };
@@ -11,7 +11,7 @@ type TableExpandHeaderPropsBase = {
11
11
  /**
12
12
  * Space separated list of one or more ID values referencing the TableExpandedRow(s) being controlled by the TableExpandHeader
13
13
  */
14
- ['aria-controls']: string;
14
+ ['aria-controls']?: string;
15
15
  /**
16
16
  * @deprecated This prop has been deprecated and will be
17
17
  * removed in the next major release of Carbon. Use the
@@ -10,7 +10,7 @@ interface TableExpandRowProps extends PropsWithChildren<TableRowProps> {
10
10
  /**
11
11
  * Space separated list of one or more ID values referencing the TableExpandedRow(s) being controlled by the TableExpandRow
12
12
  */
13
- ['aria-controls']: string;
13
+ ['aria-controls']?: string;
14
14
  /**
15
15
  * @deprecated This prop has been deprecated and will be
16
16
  * removed in the next major release of Carbon. Use the
@@ -77,7 +77,6 @@ TableExpandRow.propTypes = {
77
77
  * Space separated list of one or more ID values referencing the TableExpandedRow(s) being controlled by the TableExpandRow
78
78
  * TODO: make this required in v12
79
79
  */
80
- /**@ts-ignore*/
81
80
  ['aria-controls']: PropTypes.string,
82
81
  /**
83
82
  * Specify the string read by a voice reader when the expand trigger is
@@ -6,7 +6,16 @@
6
6
  */
7
7
  import { ReactNodeLike } from 'prop-types';
8
8
  import React, { type MouseEventHandler } from 'react';
9
+ import { sortStates } from './state/sorting';
9
10
  import { ReactAttr } from '../../types/common';
11
+ import { DataTableSortState } from './state/sortStates';
12
+ export type TableHeaderTranslationKey = 'carbon.table.header.icon.description';
13
+ export interface TableHeaderTranslationArgs {
14
+ header: React.ReactNode;
15
+ isSortHeader?: boolean;
16
+ sortDirection?: DataTableSortState;
17
+ sortStates: typeof sortStates;
18
+ }
10
19
  interface TableHeaderProps extends ReactAttr<HTMLTableCellElement & HTMLButtonElement> {
11
20
  /**
12
21
  * Pass in children that will be embedded in the table header label
@@ -58,7 +67,7 @@ interface TableHeaderProps extends ReactAttr<HTMLTableCellElement & HTMLButtonEl
58
67
  * choice. Translation keys are available on the `translationKeys` field for
59
68
  * this component.
60
69
  */
61
- translateWithId?: (key: string, { header, sortDirection, isSortHeader, sortStates }: {
70
+ translateWithId?: (key: TableHeaderTranslationKey, { header, sortDirection, isSortHeader, sortStates }: {
62
71
  header: any;
63
72
  sortDirection: any;
64
73
  isSortHeader: any;
@@ -16,7 +16,7 @@ import TableExpandHeader from './TableExpandHeader';
16
16
  import TableExpandRow from './TableExpandRow';
17
17
  import TableExpandedRow from './TableExpandedRow';
18
18
  import TableHead from './TableHead';
19
- import TableHeader from './TableHeader';
19
+ import TableHeader, { TableHeaderTranslationKey, TableHeaderTranslationArgs } from './TableHeader';
20
20
  import TableRow from './TableRow';
21
21
  import TableSelectAll from './TableSelectAll';
22
22
  import TableSelectRow from './TableSelectRow';
@@ -26,5 +26,6 @@ import TableToolbarAction from './TableToolbarAction';
26
26
  import TableToolbarContent from './TableToolbarContent';
27
27
  import TableToolbarSearch from './TableToolbarSearch';
28
28
  import TableToolbarMenu from './TableToolbarMenu';
29
- export { DataTable, type DataTableCell, type DataTableHeader, type DataTableProps, type DataTableRenderProps, type DataTableRow, type DataTableSize, Table, TableActionList, TableBatchAction, TableBatchActions, TableBody, TableCell, TableContainer, TableExpandHeader, TableExpandRow, TableExpandedRow, TableHead, TableHeader, TableRow, TableSelectAll, TableSelectRow, TableSlugRow, TableToolbar, TableToolbarAction, TableToolbarContent, TableToolbarSearch, TableToolbarMenu, };
29
+ import type { DataTableSortState } from './state/sortStates';
30
+ export { DataTable, type DataTableCell, type DataTableHeader, type DataTableProps, type DataTableRenderProps, type DataTableSortState, type DataTableRow, type DataTableSize, Table, TableActionList, TableBatchAction, TableBatchActions, TableBody, TableCell, TableContainer, TableExpandHeader, TableExpandRow, TableExpandedRow, TableHead, TableHeader, type TableHeaderTranslationKey, type TableHeaderTranslationArgs, TableRow, TableSelectAll, TableSelectRow, TableSlugRow, TableToolbar, TableToolbarAction, TableToolbarContent, TableToolbarSearch, TableToolbarMenu, };
30
31
  export default DataTable;
@@ -336,7 +336,7 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
336
336
  }
337
337
  }
338
338
  function handleOnChange(event) {
339
- if (datePickerType == 'single') {
339
+ if (datePickerType == 'single' && closeOnSelect) {
340
340
  calendar.calendarContainer.classList.remove('open');
341
341
  }
342
342
  const {
@@ -401,7 +401,8 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
401
401
  end.removeEventListener('change', handleOnChange);
402
402
  }
403
403
  };
404
- }, [savedOnChange, savedOnClose, savedOnOpen, readOnly, hasInput]); //eslint-disable-line react-hooks/exhaustive-deps
404
+ // eslint-disable-next-line react-hooks/exhaustive-deps
405
+ }, [savedOnChange, savedOnClose, savedOnOpen, readOnly, closeOnSelect, hasInput]);
405
406
 
406
407
  // this hook allows consumers to access the flatpickr calendar
407
408
  // instance for cases where functions like open() or close()
@@ -7,7 +7,7 @@
7
7
  import React, { ReactNode } from 'react';
8
8
  import { UseSelectProps } from 'downshift';
9
9
  import { ReactNodeLike } from 'prop-types';
10
- import { ListBoxSize, ListBoxType } from '../ListBox';
10
+ import { type ListBoxMenuIconTranslationKey, ListBoxSize, ListBoxType } from '../ListBox';
11
11
  import { ReactAttr } from '../../types/common';
12
12
  type ExcludedAttributes = 'id' | 'onChange';
13
13
  export interface OnChangeData<ItemType> {
@@ -123,7 +123,7 @@ export interface DropdownProps<ItemType> extends Omit<ReactAttr<HTMLDivElement>,
123
123
  /**
124
124
  * Callback function for translating ListBoxMenuIcon SVG title
125
125
  */
126
- translateWithId?(messageId: string, args?: Record<string, unknown>): string;
126
+ translateWithId?(messageId: ListBoxMenuIconTranslationKey, args?: Record<string, unknown>): string;
127
127
  /**
128
128
  * The dropdown type, `default` or `inline`
129
129
  */
@@ -137,6 +137,7 @@ export interface DropdownProps<ItemType> extends Omit<ReactAttr<HTMLDivElement>,
137
137
  */
138
138
  warnText?: React.ReactNode;
139
139
  }
140
+ export type DropdownTranslationKey = ListBoxMenuIconTranslationKey;
140
141
  type DropdownComponentProps<ItemType> = React.PropsWithoutRef<React.PropsWithChildren<DropdownProps<ItemType>> & React.RefAttributes<HTMLButtonElement>>;
141
142
  interface DropdownComponent {
142
143
  <ItemType>(props: DropdownComponentProps<ItemType>): React.ReactElement | null;
@@ -4,8 +4,8 @@
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import Dropdown, { OnChangeData } from './Dropdown';
8
- export type { OnChangeData };
7
+ import Dropdown, { type DropdownTranslationKey, type OnChangeData } from './Dropdown';
8
+ export type { DropdownTranslationKey, OnChangeData };
9
9
  export { Dropdown };
10
10
  export { default as DropdownSkeleton } from './Dropdown.Skeleton';
11
11
  export default Dropdown;
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React__default, { useState, useRef } from 'react';
9
+ import React__default, { useState, useRef, useEffect } from 'react';
10
10
  import cx from 'classnames';
11
11
  import Search from '../Search/Search.js';
12
12
  import '../Search/Search.Skeleton.js';
@@ -31,10 +31,13 @@ function ExpandableSearch(_ref) {
31
31
  const prefix = usePrefix();
32
32
  function handleBlur(evt) {
33
33
  const relatedTargetIsAllowed = evt.relatedTarget && evt.relatedTarget.classList.contains(`${prefix}--search-close`);
34
- if (expanded && !relatedTargetIsAllowed && !hasContent) {
34
+ if (expanded && !relatedTargetIsAllowed && !hasContent && !isExpanded) {
35
35
  setExpanded(false);
36
36
  }
37
37
  }
38
+ useEffect(() => {
39
+ setExpanded(!!isExpanded);
40
+ }, [isExpanded]);
38
41
  function handleChange(evt) {
39
42
  setHasContent(evt.target.value !== '');
40
43
  }
@@ -47,7 +50,7 @@ function ExpandableSearch(_ref) {
47
50
  evt.stopPropagation();
48
51
 
49
52
  // escape key only clears if the input is empty, otherwise it clears the input
50
- if (!evt.target?.value) {
53
+ if (!evt.target?.value && !isExpanded) {
51
54
  setExpanded(false);
52
55
  }
53
56
  }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { ReactNodeLike } from 'prop-types';
8
+ import React from 'react';
9
+ import { ButtonSize } from '../Button';
10
+ export declare const IconButtonKinds: readonly ["primary", "secondary", "ghost", "tertiary"];
11
+ export type IconButtonKind = (typeof IconButtonKinds)[number];
12
+ interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
13
+ /**
14
+ * Specify how the trigger should align with the tooltip
15
+ */
16
+ align?: 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right';
17
+ /**
18
+ * Provide an icon or asset to be rendered inside of the IconButton
19
+ */
20
+ children?: React.ReactNode;
21
+ /**
22
+ * Specify an optional className to be added to your Button
23
+ */
24
+ className?: string;
25
+ /**
26
+ * Determines whether the tooltip should close when inner content is activated (click, Enter or Space)
27
+ */
28
+ closeOnActivation?: boolean;
29
+ /**
30
+ * Specify whether the tooltip should be open when it first renders
31
+ */
32
+ defaultOpen?: boolean;
33
+ /**
34
+ * Specify whether the Button should be disabled, or not
35
+ */
36
+ disabled?: boolean;
37
+ /**
38
+ * Specify the duration in milliseconds to delay before displaying the tooltip
39
+ */
40
+ enterDelayMs?: number;
41
+ /**
42
+ * Specify whether the IconButton is currently selected
43
+ */
44
+ isSelected?: boolean;
45
+ /**
46
+ * Specify the type of button to be used as the base for the IconButton
47
+ */
48
+ kind?: IconButtonKind;
49
+ /**
50
+ * Provide the label to be rendered inside of the Tooltip. The label will use
51
+ * `aria-labelledby` and will fully describe the child node that is provided.
52
+ * This means that if you have text in the child node it will not be
53
+ * announced to the screen reader.
54
+ */
55
+ label: ReactNodeLike;
56
+ /**
57
+ * Specify the duration in milliseconds to delay before hiding the tooltip
58
+ */
59
+ leaveDelayMs?: number;
60
+ /**
61
+ * Specify the size of the Button. Defaults to `md`.
62
+ */
63
+ size?: ButtonSize;
64
+ /**
65
+ * Specify an optional className to be added to your Tooltip wrapper
66
+ */
67
+ wrapperClasses?: string;
68
+ }
69
+ declare const IconButton: React.ForwardRefExoticComponent<IconButtonProps & React.RefAttributes<unknown>>;
70
+ export { IconButton };
@@ -15,8 +15,9 @@ import '../Tooltip/DefinitionTooltip.js';
15
15
  import { Tooltip } from '../Tooltip/Tooltip.js';
16
16
  import { usePrefix } from '../../internal/usePrefix.js';
17
17
 
18
- const IconButton = /*#__PURE__*/React__default.forwardRef(function IconButton(props, ref) {
19
- const {
18
+ const IconButtonKinds = ['primary', 'secondary', 'ghost', 'tertiary'];
19
+ const IconButton = /*#__PURE__*/React__default.forwardRef(function IconButton(_ref, ref) {
20
+ let {
20
21
  align,
21
22
  children,
22
23
  className,
@@ -31,7 +32,7 @@ const IconButton = /*#__PURE__*/React__default.forwardRef(function IconButton(pr
31
32
  size,
32
33
  isSelected,
33
34
  ...rest
34
- } = props;
35
+ } = _ref;
35
36
  const prefix = usePrefix();
36
37
  const tooltipClasses = cx(wrapperClasses, `${prefix}--icon-tooltip`, {
37
38
  [`${prefix}--icon-tooltip--disabled`]: disabled
@@ -91,7 +92,7 @@ IconButton.propTypes = {
91
92
  /**
92
93
  * Specify the type of button to be used as the base for the IconButton
93
94
  */
94
- kind: PropTypes.oneOf(['primary', 'secondary', 'ghost', 'tertiary']),
95
+ kind: PropTypes.oneOf(IconButtonKinds),
95
96
  /**
96
97
  * Provide the label to be rendered inside of the Tooltip. The label will use
97
98
  * `aria-labelledby` and will fully describe the child node that is provided.
@@ -113,4 +114,4 @@ IconButton.propTypes = {
113
114
  wrapperClasses: PropTypes.string
114
115
  };
115
116
 
116
- export { IconButton };
117
+ export { IconButton, IconButtonKinds };
@@ -5,10 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- export declare const translationIds: {
9
- 'close.menu': string;
10
- 'open.menu': string;
11
- };
8
+ export type ListBoxMenuIconTranslationKey = 'close.menu' | 'open.menu';
12
9
  export interface ListBoxMenuIconProps {
13
10
  /**
14
11
  * Specify whether the menu is currently open, which will influence the
@@ -17,10 +14,10 @@ export interface ListBoxMenuIconProps {
17
14
  isOpen: boolean;
18
15
  /**
19
16
  * i18n hook used to provide the appropriate description for the given menu
20
- * icon. This function takes in an id defined in `translationIds` and should
17
+ * icon. This function takes in a ListBoxMenuIconTranslationKey and should
21
18
  * return a string message for that given message id.
22
19
  */
23
- translateWithId?(messageId: string, args?: Record<string, unknown>): string;
20
+ translateWithId?(messageId: ListBoxMenuIconTranslationKey, args?: Record<string, unknown>): string;
24
21
  }
25
22
  export type ListBoxMenuIconComponent = React.FC<ListBoxMenuIconProps>;
26
23
  /**
@@ -11,13 +11,9 @@ import PropTypes from 'prop-types';
11
11
  import { ChevronDown } from '@carbon/icons-react';
12
12
  import { usePrefix } from '../../internal/usePrefix.js';
13
13
 
14
- const translationIds = {
15
- 'close.menu': 'close.menu',
16
- 'open.menu': 'open.menu'
17
- };
18
14
  const defaultTranslations = {
19
- [translationIds['close.menu']]: 'Close menu',
20
- [translationIds['open.menu']]: 'Open menu'
15
+ 'close.menu': 'Close menu',
16
+ 'open.menu': 'Open menu'
21
17
  };
22
18
  const defaultTranslateWithId = id => defaultTranslations[id];
23
19
  /**
@@ -49,10 +45,10 @@ ListBoxMenuIcon.propTypes = {
49
45
  isOpen: PropTypes.bool.isRequired,
50
46
  /**
51
47
  * i18n hook used to provide the appropriate description for the given menu
52
- * icon. This function takes in an id defined in `translationIds` and should
48
+ * icon. This function takes a ListBoxMenuIconTranslationKey and should
53
49
  * return a string message for that given message id.
54
50
  */
55
51
  translateWithId: PropTypes.func
56
52
  };
57
53
 
58
- export { ListBoxMenuIcon as default, translationIds };
54
+ export { ListBoxMenuIcon as default };
@@ -21,3 +21,4 @@ export interface ListBoxComponent extends ListBoxPartialComponent {
21
21
  }
22
22
  declare const ListBox: ListBoxComponent;
23
23
  export default ListBox;
24
+ export type { ListBoxMenuIconTranslationKey } from './ListBoxMenuIcon';
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Copyright IBM Corp. 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ interface MenuProps extends React.HTMLAttributes<HTMLUListElement> {
9
+ /**
10
+ * A collection of MenuItems to be rendered within this Menu.
11
+ */
12
+ children?: React.ReactNode;
13
+ /**
14
+ * Additional CSS class names.
15
+ */
16
+ className?: string;
17
+ /**
18
+ * A label describing the Menu.
19
+ */
20
+ label?: string;
21
+ /**
22
+ * The mode of this menu. Defaults to full.
23
+ * `full` supports nesting and selectable menu items, but no icons.
24
+ * `basic` supports icons but no nesting or selectable menu items.
25
+ *
26
+ * **This prop is not intended for use and will be set by the respective implementation (like useContextMenu, MenuButton, and ComboButton).**
27
+ */
28
+ mode?: 'full' | 'basic';
29
+ /**
30
+ * Provide an optional function to be called when the Menu should be closed.
31
+ */
32
+ onClose?: () => void;
33
+ /**
34
+ * Provide an optional function to be called when the Menu is opened.
35
+ */
36
+ onOpen?: () => void;
37
+ /**
38
+ * Whether the Menu is open or not.
39
+ */
40
+ open?: boolean;
41
+ /**
42
+ * Specify the size of the Menu.
43
+ */
44
+ size?: 'xs' | 'sm' | 'md' | 'lg';
45
+ /**
46
+ * Specify a DOM node where the Menu should be rendered in. Defaults to document.body.
47
+ */
48
+ target?: any;
49
+ /**
50
+ * Specify the x position of the Menu. Either pass a single number or an array with two numbers describing your activator's boundaries ([x1, x2])
51
+ */
52
+ x?: number | (number | null | undefined)[];
53
+ /**
54
+ * Specify the y position of the Menu. Either pass a single number or an array with two numbers describing your activator's boundaries ([y1, y2])
55
+ */
56
+ y?: number | (number | null | undefined)[];
57
+ }
58
+ declare const Menu: React.ForwardRefExoticComponent<MenuProps & React.RefAttributes<HTMLUListElement>>;
59
+ export { Menu };
@@ -56,7 +56,7 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
56
56
  dispatch: childDispatch
57
57
  };
58
58
  }, [childState, childDispatch]);
59
- const menu = useRef();
59
+ const menu = useRef(null);
60
60
  const ref = useMergedRefs([forwardRef, menu]);
61
61
  const [position, setPosition] = useState([-1, -1]);
62
62
  const focusableItems = childContext.state.items.filter(item => !item.disabled && item.ref.current);
@@ -144,11 +144,14 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
144
144
  }
145
145
  }
146
146
  function handleBlur(e) {
147
- if (open && onClose && isRoot && !menu.current.contains(e.relatedTarget)) {
147
+ if (open && onClose && isRoot && !menu.current?.contains(e.relatedTarget)) {
148
148
  handleClose(e);
149
149
  }
150
150
  }
151
151
  function fitValue(range, axis) {
152
+ if (!menu.current) {
153
+ return;
154
+ }
152
155
  const {
153
156
  width,
154
157
  height
@@ -187,18 +190,38 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
187
190
  reversedAnchor - size >= 0 ? reversedAnchor - size + offset : false,
188
191
  // align at max (second fallback)
189
192
  max - spacing - size];
193
+
194
+ // Previous array `options`, has at least one item that is a number (the last one - second fallback).
195
+ // That guarantees that the return of `find()` will always be a number
196
+ // and we can safely add the numeric casting `as number`.
190
197
  const bestOption = options.find(option => option !== false);
191
198
  return bestOption >= spacing ? bestOption : spacing;
192
199
  }
200
+ function notEmpty(value) {
201
+ return value !== null && value !== undefined;
202
+ }
203
+ function getPosition(x) {
204
+ if (Array.isArray(x)) {
205
+ // has to be of length 2
206
+ const filtered = x.filter(notEmpty);
207
+ if (filtered.length === 2) {
208
+ return filtered;
209
+ } else {
210
+ return;
211
+ }
212
+ } else {
213
+ return [x, x];
214
+ }
215
+ }
193
216
  function calculatePosition() {
194
- if (menu.current) {
195
- const ranges = {
196
- x: typeof x === 'object' && x.length === 2 ? x : [x, x],
197
- y: typeof y === 'object' && y.length === 2 ? y : [y, y]
198
- };
199
- return [fitValue(ranges.x, 'x'), fitValue(ranges.y, 'y')];
217
+ const ranges = {
218
+ x: getPosition(x),
219
+ y: getPosition(y)
220
+ };
221
+ if (!ranges.x || !ranges.y) {
222
+ return [-1, -1];
200
223
  }
201
- return [-1, -1];
224
+ return [fitValue(ranges.x, 'x') ?? -1, fitValue(ranges.y, 'y') ?? -1];
202
225
  }
203
226
  useEffect(() => {
204
227
  if (open && focusableItems.length > 0) {
@@ -212,7 +235,7 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
212
235
  } else {
213
236
  // reset position when menu is closed in order for the --shown
214
237
  // modifier to be applied correctly
215
- setPosition(-1, -1);
238
+ setPosition([-1, -1]);
216
239
  }
217
240
  // eslint-disable-next-line react-hooks/exhaustive-deps
218
241
  }, [open]);
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright IBM Corp. 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ type ActionType = {
9
+ type: 'enableIcons' | 'registerItem';
10
+ payload: any;
11
+ };
12
+ type StateType = {
13
+ isRoot: boolean;
14
+ mode: 'full' | 'basic';
15
+ hasIcons: boolean;
16
+ size: 'xs' | 'sm' | 'md' | 'lg' | null;
17
+ items: any[];
18
+ requestCloseRoot: (e: Pick<React.KeyboardEvent<HTMLUListElement>, 'type'>) => void;
19
+ };
20
+ declare function menuReducer(state: StateType, action: ActionType): {
21
+ hasIcons: boolean;
22
+ isRoot: boolean;
23
+ mode: "full" | "basic";
24
+ size: "sm" | "md" | "lg" | "xs" | null;
25
+ items: any[];
26
+ requestCloseRoot: (e: Pick<React.KeyboardEvent<HTMLUListElement>, "type">) => void;
27
+ };
28
+ declare const MenuContext: React.Context<{
29
+ state: StateType;
30
+ dispatch: React.Dispatch<any>;
31
+ }>;
32
+ export { MenuContext, menuReducer };