@carbon/react 1.54.0-rc.0 → 1.55.0-rc.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 (82) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +994 -1023
  2. package/es/components/Button/Button.d.ts +1 -1
  3. package/es/components/Button/Button.js +13 -89
  4. package/es/components/Button/ButtonBase.d.ts +10 -0
  5. package/es/components/Button/ButtonBase.js +110 -0
  6. package/es/components/CodeSnippet/CodeSnippet.Skeleton.d.ts +37 -0
  7. package/es/components/CodeSnippet/CodeSnippet.d.ts +196 -0
  8. package/es/components/CodeSnippet/CodeSnippet.js +20 -18
  9. package/es/components/CodeSnippet/index.d.ts +10 -0
  10. package/es/components/ComboBox/ComboBox.d.ts +2 -2
  11. package/es/components/ComboBox/ComboBox.js +13 -5
  12. package/es/components/ComboButton/index.d.ts +51 -0
  13. package/es/components/ComboButton/index.js +9 -7
  14. package/es/components/ComposedModal/ComposedModal.js +2 -2
  15. package/es/components/DataTable/TableBatchAction.d.ts +1 -5
  16. package/es/components/Dropdown/Dropdown.js +3 -1
  17. package/es/components/IconButton/index.js +2 -3
  18. package/es/components/Menu/Menu.js +2 -0
  19. package/es/components/Modal/Modal.js +2 -2
  20. package/es/components/ModalWrapper/ModalWrapper.d.ts +1 -1
  21. package/es/components/MultiSelect/FilterableMultiSelect.js +31 -0
  22. package/es/components/MultiSelect/MultiSelect.js +37 -7
  23. package/es/components/Slider/Slider.Skeleton.js +6 -2
  24. package/es/components/Slug/index.js +8 -13
  25. package/es/components/StructuredList/StructuredList.d.ts +8 -0
  26. package/es/components/StructuredList/StructuredList.js +28 -10
  27. package/es/components/Tag/DismissibleTag.js +119 -0
  28. package/es/components/Tag/OperationalTag.js +99 -0
  29. package/es/components/Tag/SelectableTag.js +98 -0
  30. package/es/components/Tag/index.d.ts +4 -1
  31. package/es/components/TreeView/TreeNode.js +1 -1
  32. package/es/components/UIShell/SideNavMenu.js +11 -1
  33. package/es/components/UIShell/SideNavMenuItem.d.ts +4 -0
  34. package/es/components/UIShell/SideNavMenuItem.js +8 -1
  35. package/es/components/UIShell/SwitcherItem.d.ts +4 -0
  36. package/es/components/UIShell/SwitcherItem.js +6 -0
  37. package/es/feature-flags.js +2 -1
  38. package/es/index.js +5 -2
  39. package/es/internal/environment.js +5 -1
  40. package/es/internal/keyboard/navigation.js +6 -2
  41. package/es/internal/useOutsideClick.js +31 -0
  42. package/lib/components/Button/Button.d.ts +1 -1
  43. package/lib/components/Button/Button.js +13 -90
  44. package/lib/components/Button/ButtonBase.d.ts +10 -0
  45. package/lib/components/Button/ButtonBase.js +119 -0
  46. package/lib/components/CodeSnippet/CodeSnippet.Skeleton.d.ts +37 -0
  47. package/lib/components/CodeSnippet/CodeSnippet.d.ts +196 -0
  48. package/lib/components/CodeSnippet/CodeSnippet.js +20 -18
  49. package/lib/components/CodeSnippet/index.d.ts +10 -0
  50. package/lib/components/ComboBox/ComboBox.d.ts +2 -2
  51. package/lib/components/ComboBox/ComboBox.js +13 -5
  52. package/lib/components/ComboButton/index.d.ts +51 -0
  53. package/lib/components/ComboButton/index.js +9 -7
  54. package/lib/components/ComposedModal/ComposedModal.js +2 -2
  55. package/lib/components/DataTable/TableBatchAction.d.ts +1 -5
  56. package/lib/components/Dropdown/Dropdown.js +3 -1
  57. package/lib/components/IconButton/index.js +2 -3
  58. package/lib/components/Menu/Menu.js +2 -0
  59. package/lib/components/Modal/Modal.js +2 -2
  60. package/lib/components/ModalWrapper/ModalWrapper.d.ts +1 -1
  61. package/lib/components/MultiSelect/FilterableMultiSelect.js +31 -0
  62. package/lib/components/MultiSelect/MultiSelect.js +37 -7
  63. package/lib/components/Slider/Slider.Skeleton.js +5 -1
  64. package/lib/components/Slug/index.js +8 -13
  65. package/lib/components/StructuredList/StructuredList.d.ts +8 -0
  66. package/lib/components/StructuredList/StructuredList.js +27 -9
  67. package/lib/components/Tag/DismissibleTag.js +129 -0
  68. package/lib/components/Tag/OperationalTag.js +109 -0
  69. package/lib/components/Tag/SelectableTag.js +108 -0
  70. package/lib/components/Tag/index.d.ts +4 -1
  71. package/lib/components/TreeView/TreeNode.js +1 -1
  72. package/lib/components/UIShell/SideNavMenu.js +11 -1
  73. package/lib/components/UIShell/SideNavMenuItem.d.ts +4 -0
  74. package/lib/components/UIShell/SideNavMenuItem.js +8 -1
  75. package/lib/components/UIShell/SwitcherItem.d.ts +4 -0
  76. package/lib/components/UIShell/SwitcherItem.js +6 -0
  77. package/lib/feature-flags.js +2 -1
  78. package/lib/index.js +10 -4
  79. package/lib/internal/environment.js +5 -1
  80. package/lib/internal/keyboard/navigation.js +6 -2
  81. package/lib/internal/useOutsideClick.js +35 -0
  82. package/package.json +6 -6
@@ -0,0 +1,99 @@
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
+
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
+ import PropTypes from 'prop-types';
10
+ import React__default from 'react';
11
+ import cx from 'classnames';
12
+ import setupGetInstanceId from '../../tools/setupGetInstanceId.js';
13
+ import { usePrefix } from '../../internal/usePrefix.js';
14
+ import Tag, { SIZES } from './Tag.js';
15
+
16
+ const getInstanceId = setupGetInstanceId();
17
+ const TYPES = {
18
+ red: 'Red',
19
+ magenta: 'Magenta',
20
+ purple: 'Purple',
21
+ blue: 'Blue',
22
+ cyan: 'Cyan',
23
+ teal: 'Teal',
24
+ green: 'Green',
25
+ gray: 'Gray',
26
+ 'cool-gray': 'Cool-Gray',
27
+ 'warm-gray': 'Warm-Gray'
28
+ };
29
+ const OperationalTag = _ref => {
30
+ let {
31
+ children,
32
+ className,
33
+ disabled,
34
+ id,
35
+ renderIcon,
36
+ slug,
37
+ size,
38
+ type = 'gray',
39
+ ...other
40
+ } = _ref;
41
+ const prefix = usePrefix();
42
+ const tagId = id || `tag-${getInstanceId()}`;
43
+ const tagClasses = cx(`${prefix}--tag--operational`, className);
44
+ let normalizedSlug;
45
+ if (slug && slug['type']?.displayName === 'Slug') {
46
+ normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
47
+ size: 'sm',
48
+ kind: 'inline'
49
+ });
50
+ }
51
+ return /*#__PURE__*/React__default.createElement(Tag, _extends({
52
+ type: type,
53
+ size: size,
54
+ renderIcon: renderIcon,
55
+ disabled: disabled,
56
+ className: tagClasses,
57
+ id: tagId
58
+ }, other), /*#__PURE__*/React__default.createElement("div", {
59
+ className: `${prefix}--interactive--tag-children`
60
+ }, children, normalizedSlug));
61
+ };
62
+ OperationalTag.propTypes = {
63
+ /**
64
+ * Provide content to be rendered inside of a `OperationalTag`
65
+ */
66
+ children: PropTypes.node,
67
+ /**
68
+ * Provide a custom className that is applied to the containing <span>
69
+ */
70
+ className: PropTypes.string,
71
+ /**
72
+ * Specify if the `OperationalTag` is disabled
73
+ */
74
+ disabled: PropTypes.bool,
75
+ /**
76
+ * Specify the id for the tag.
77
+ */
78
+ id: PropTypes.string,
79
+ /**
80
+ * Optional prop to render a custom icon.
81
+ * Can be a React component class
82
+ */
83
+ renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
84
+ /**
85
+ * Specify the size of the Tag. Currently supports either `sm`,
86
+ * `md` (default) or `lg` sizes.
87
+ */
88
+ size: PropTypes.oneOf(Object.keys(SIZES)),
89
+ /**
90
+ * **Experimental:** Provide a `Slug` component to be rendered inside the `OperationalTag` component
91
+ */
92
+ slug: PropTypes.node,
93
+ /**
94
+ * Specify the type of the `Tag`
95
+ */
96
+ type: PropTypes.oneOf(Object.keys(TYPES))
97
+ };
98
+
99
+ export { OperationalTag as default };
@@ -0,0 +1,98 @@
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
+
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
+ import PropTypes from 'prop-types';
10
+ import React__default, { useState } from 'react';
11
+ import cx from 'classnames';
12
+ import setupGetInstanceId from '../../tools/setupGetInstanceId.js';
13
+ import { usePrefix } from '../../internal/usePrefix.js';
14
+ import Tag, { SIZES } from './Tag.js';
15
+
16
+ const getInstanceId = setupGetInstanceId();
17
+ const SelectableTag = _ref => {
18
+ let {
19
+ children,
20
+ className,
21
+ disabled,
22
+ id,
23
+ renderIcon,
24
+ selected = false,
25
+ slug,
26
+ size,
27
+ ...other
28
+ } = _ref;
29
+ const prefix = usePrefix();
30
+ const tagId = id || `tag-${getInstanceId()}`;
31
+ const [selectedTag, setSelectedTag] = useState(selected);
32
+ const tagClasses = cx(`${prefix}--tag--selectable`, className, {
33
+ [`${prefix}--tag--selectable-selected`]: selectedTag
34
+ });
35
+ let normalizedSlug;
36
+ if (slug && slug['type']?.displayName === 'Slug') {
37
+ normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
38
+ size: 'sm',
39
+ kind: 'inline'
40
+ });
41
+ }
42
+
43
+ // Removing onClick from the spread operator
44
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
45
+ const {
46
+ onClick,
47
+ ...otherProps
48
+ } = other;
49
+ return /*#__PURE__*/React__default.createElement(Tag, _extends({
50
+ slug: slug,
51
+ size: size,
52
+ renderIcon: renderIcon,
53
+ disabled: disabled,
54
+ className: tagClasses,
55
+ id: tagId,
56
+ onClick: () => setSelectedTag(!selectedTag)
57
+ }, otherProps), /*#__PURE__*/React__default.createElement("div", {
58
+ className: `${prefix}--interactive--tag-children`
59
+ }, children, normalizedSlug));
60
+ };
61
+ SelectableTag.propTypes = {
62
+ /**
63
+ * Provide content to be rendered inside of a `SelectableTag`
64
+ */
65
+ children: PropTypes.node,
66
+ /**
67
+ * Provide a custom className that is applied to the containing <span>
68
+ */
69
+ className: PropTypes.string,
70
+ /**
71
+ * Specify if the `SelectableTag` is disabled
72
+ */
73
+ disabled: PropTypes.bool,
74
+ /**
75
+ * Specify the id for the tag.
76
+ */
77
+ id: PropTypes.string,
78
+ /**
79
+ * Optional prop to render a custom icon.
80
+ * Can be a React component class
81
+ */
82
+ renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
83
+ /**
84
+ * Specify the state of the selectable tag.
85
+ */
86
+ selected: PropTypes.bool,
87
+ /**
88
+ * Specify the size of the Tag. Currently supports either `sm`,
89
+ * `md` (default) or `lg` sizes.
90
+ */
91
+ size: PropTypes.oneOf(Object.keys(SIZES)),
92
+ /**
93
+ * **Experimental:** Provide a `Slug` component to be rendered inside the `SelectableTag` component
94
+ */
95
+ slug: PropTypes.node
96
+ };
97
+
98
+ export { SelectableTag as default };
@@ -5,6 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import Tag from './Tag';
8
+ import DismissibleTag from './DismissibleTag';
9
+ import OperationalTag from './OperationalTag';
10
+ import SelectableTag from './SelectableTag';
8
11
  export * from './Tag.Skeleton';
9
12
  export default Tag;
10
- export { Tag };
13
+ export { Tag, DismissibleTag, OperationalTag, SelectableTag };
@@ -56,7 +56,7 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
56
56
  return /*#__PURE__*/React__default.cloneElement(node, {
57
57
  active,
58
58
  depth: depth + 1,
59
- disabled,
59
+ disabled: disabled || node.props.disabled,
60
60
  onTreeSelect,
61
61
  selected,
62
62
  tabIndex: !node.props.disabled && -1 || null
@@ -28,9 +28,12 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
28
28
  tabIndex,
29
29
  title
30
30
  } = _ref;
31
- const isRail = useContext(SideNavContext);
31
+ const {
32
+ isRail
33
+ } = useContext(SideNavContext);
32
34
  const prefix = usePrefix();
33
35
  const [isExpanded, setIsExpanded] = useState(defaultExpanded);
36
+ const [prevExpanded, setPrevExpanded] = useState(defaultExpanded);
34
37
  const className = cx({
35
38
  [`${prefix}--side-nav__item`]: true,
36
39
  [`${prefix}--side-nav__item--active`]: isActive || hasActiveDescendant(children) && !isExpanded,
@@ -38,6 +41,13 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
38
41
  [`${prefix}--side-nav__item--large`]: large,
39
42
  [customClassName]: !!customClassName
40
43
  });
44
+ if (!isSideNavExpanded && isExpanded && isRail) {
45
+ setIsExpanded(false);
46
+ setPrevExpanded(true);
47
+ } else if (isSideNavExpanded && prevExpanded && isRail) {
48
+ setIsExpanded(true);
49
+ setPrevExpanded(false);
50
+ }
41
51
  return (
42
52
  /*#__PURE__*/
43
53
  // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
@@ -20,6 +20,10 @@ interface SideNavMenuItemProps extends HTMLAttributes<HTMLElement> {
20
20
  * `aria-current="page"`, as well.
21
21
  */
22
22
  isActive?: boolean;
23
+ /**
24
+ * Optionally provide an href for the underlying li`
25
+ */
26
+ href?: string;
23
27
  }
24
28
  declare const SideNavMenuItem: React.ForwardRefExoticComponent<SideNavMenuItemProps & React.RefAttributes<HTMLElement>>;
25
29
  export default SideNavMenuItem;
@@ -19,6 +19,7 @@ const SideNavMenuItem = /*#__PURE__*/React__default.forwardRef(function SideNavM
19
19
  children,
20
20
  className: customClassName,
21
21
  isActive,
22
+ href,
22
23
  ...rest
23
24
  } = props;
24
25
  const className = cx(`${prefix}--side-nav__menu-item`, customClassName);
@@ -28,7 +29,9 @@ const SideNavMenuItem = /*#__PURE__*/React__default.forwardRef(function SideNavM
28
29
  });
29
30
  return /*#__PURE__*/React__default.createElement("li", {
30
31
  className: className
31
- }, /*#__PURE__*/React__default.createElement(Link, _extends({}, rest, {
32
+ }, /*#__PURE__*/React__default.createElement(Link, _extends({
33
+ href: href
34
+ }, rest, {
32
35
  className: linkClassName,
33
36
  ref: ref
34
37
  }), /*#__PURE__*/React__default.createElement(SideNavLinkText, null, children)));
@@ -43,6 +46,10 @@ SideNavMenuItem.propTypes = {
43
46
  * Provide an optional class to be applied to the containing node
44
47
  */
45
48
  className: PropTypes.string,
49
+ /**
50
+ * Optionally provide an href for the underlying li`
51
+ */
52
+ href: PropTypes.string,
46
53
  /**
47
54
  * Optionally specify whether the link is "active". An active link is one that
48
55
  * has an href that is the same as the current page. Can also pass in
@@ -39,6 +39,10 @@ interface BaseSwitcherItemProps {
39
39
  * Specify whether the panel is selected
40
40
  */
41
41
  isSelected?: boolean;
42
+ /**
43
+ * Optionally provide an href for the underlying li`
44
+ */
45
+ href?: string;
42
46
  }
43
47
  interface SwitcherItemWithAriaLabel extends BaseSwitcherItemProps {
44
48
  'aria-label': string;
@@ -27,6 +27,7 @@ const SwitcherItem = /*#__PURE__*/forwardRef(function SwitcherItem(props, forwar
27
27
  index,
28
28
  handleSwitcherItemFocus,
29
29
  onKeyDown = () => {},
30
+ href,
30
31
  ...rest
31
32
  } = props;
32
33
  const prefix = usePrefix();
@@ -63,6 +64,7 @@ const SwitcherItem = /*#__PURE__*/forwardRef(function SwitcherItem(props, forwar
63
64
  setTabFocus(evt);
64
65
  onKeyDown(evt);
65
66
  },
67
+ href: href,
66
68
  ref: forwardRef
67
69
  }, rest, {
68
70
  className: linkClassName,
@@ -84,6 +86,10 @@ SwitcherItem.propTypes = {
84
86
  * event handlers
85
87
  */
86
88
  handleSwitcherItemFocus: PropTypes.func,
89
+ /**
90
+ * Optionally provide an href for the underlying li`
91
+ */
92
+ href: PropTypes.string,
87
93
  /**
88
94
  * Specify the index of the SwitcherItem
89
95
  */
@@ -12,5 +12,6 @@ FeatureFlags.merge({
12
12
  'enable-css-grid': true,
13
13
  'enable-v11-release': true,
14
14
  'enable-experimental-tile-contrast': false,
15
- 'enable-v12-tile-radio-icons': false
15
+ 'enable-v12-tile-radio-icons': false,
16
+ 'enable-v12-structured-list-visible-icons': false
16
17
  });
package/es/index.js CHANGED
@@ -19,6 +19,8 @@ export { default as ButtonSet } from './components/ButtonSet/ButtonSet.js';
19
19
  export { default as Checkbox } from './components/Checkbox/Checkbox.js';
20
20
  export { default as CheckboxSkeleton } from './components/Checkbox/Checkbox.Skeleton.js';
21
21
  export { ClassPrefix } from './components/ClassPrefix/index.js';
22
+ export { default as CodeSnippet } from './components/CodeSnippet/CodeSnippet.js';
23
+ export { default as CodeSnippetSkeleton } from './components/CodeSnippet/CodeSnippet.Skeleton.js';
22
24
  export { default as ComboBox } from './components/ComboBox/ComboBox.js';
23
25
  export { ComboButton } from './components/ComboButton/index.js';
24
26
  export { default as ComposedModal, ModalBody } from './components/ComposedModal/ComposedModal.js';
@@ -105,6 +107,9 @@ export { IconTab, Tab, TabList, TabPanel, TabPanels, Tabs } from './components/T
105
107
  export { default as TabContent } from './components/TabContent/TabContent.js';
106
108
  export { default as TabsSkeleton } from './components/Tabs/Tabs.Skeleton.js';
107
109
  export { default as Tag } from './components/Tag/Tag.js';
110
+ export { default as DismissibleTag } from './components/Tag/DismissibleTag.js';
111
+ export { default as OperationalTag } from './components/Tag/OperationalTag.js';
112
+ export { default as SelectableTag } from './components/Tag/SelectableTag.js';
108
113
  export { default as TagSkeleton } from './components/Tag/Tag.Skeleton.js';
109
114
  export { default as TextArea } from './components/TextArea/TextArea.js';
110
115
  export { default as TextAreaSkeleton } from './components/TextArea/TextArea.Skeleton.js';
@@ -173,8 +178,6 @@ export { default as unstable__FluidTextInputSkeleton } from './components/FluidT
173
178
  export { default as unstable_PageSelector } from './components/Pagination/experimental/PageSelector.js';
174
179
  export { default as unstable_Pagination } from './components/Pagination/experimental/Pagination.js';
175
180
  export { default as CheckboxGroup } from './components/CheckboxGroup/CheckboxGroup.js';
176
- export { default as CodeSnippetSkeleton } from './components/CodeSnippet/CodeSnippet.Skeleton.js';
177
- export { default as CodeSnippet } from './components/CodeSnippet/CodeSnippet.js';
178
181
  export { default as ContainedListItem } from './components/ContainedList/ContainedListItem/ContainedListItem.js';
179
182
  export { default as ContainedList } from './components/ContainedList/ContainedList.js';
180
183
  export { default as useContextMenu } from './components/ContextMenu/useContextMenu.js';
@@ -10,6 +10,10 @@
10
10
  *
11
11
  * @see https://github.com/facebook/fbjs/blob/4d1751311d3f67af2dcce2e40df8512a23c7b9c6/packages/fbjs/src/core/ExecutionEnvironment.js#L12
12
12
  */
13
- const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
13
+ const canUseDOM = !!(typeof window !== 'undefined' &&
14
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
15
+ window.document &&
16
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
17
+ window.document.createElement);
14
18
 
15
19
  export { canUseDOM };
@@ -39,7 +39,9 @@ const getNextIndex = (key, index, arrayLength) => {
39
39
  */
40
40
  const DOCUMENT_POSITION_BROAD_PRECEDING =
41
41
  // Checks `typeof Node` for `react-docgen`
42
- typeof Node !== 'undefined' && Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS;
42
+ typeof Node !== 'undefined' &&
43
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
44
+ Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS;
43
45
 
44
46
  /**
45
47
  * A flag `node.compareDocumentPosition(target)` returns,
@@ -47,7 +49,9 @@ typeof Node !== 'undefined' && Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_
47
49
  */
48
50
  const DOCUMENT_POSITION_BROAD_FOLLOWING =
49
51
  // Checks `typeof Node` for `react-docgen`
50
- typeof Node !== 'undefined' && Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY;
52
+ typeof Node !== 'undefined' &&
53
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
54
+ Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY;
51
55
 
52
56
  /**
53
57
  * CSS selector that selects major nodes that are sequential-focusable.
@@ -0,0 +1,31 @@
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
+
8
+ import { useRef, useEffect } from 'react';
9
+ import { useEvent } from './useEvent.js';
10
+ import { canUseDOM } from './environment.js';
11
+
12
+ function useOutsideClick(ref, callback) {
13
+ const savedCallback = useRef(callback);
14
+ useEffect(() => {
15
+ savedCallback.current = callback;
16
+ });
17
+
18
+ // We conditionally guard the `useEvent` hook for SSR. `canUseDOM` can be
19
+ // treated as a constant as it will be false when executed in a Node.js
20
+ // environment and true when executed in the browser
21
+ if (canUseDOM) {
22
+ // eslint-disable-next-line react-hooks/rules-of-hooks
23
+ useEvent(window, 'click', event => {
24
+ if (ref.current && !ref.current.contains(event.target)) {
25
+ savedCallback.current(event);
26
+ }
27
+ });
28
+ }
29
+ }
30
+
31
+ export { useOutsideClick };
@@ -14,7 +14,7 @@ export declare const ButtonTooltipAlignments: readonly ["start", "center", "end"
14
14
  export type ButtonTooltipAlignment = (typeof ButtonTooltipAlignments)[number];
15
15
  export declare const ButtonTooltipPositions: string[];
16
16
  export type ButtonTooltipPosition = (typeof ButtonTooltipPositions)[number];
17
- interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
17
+ export interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
18
18
  /**
19
19
  * Specify the message read by screen readers for the danger button variant
20
20
  */
@@ -12,17 +12,14 @@ Object.defineProperty(exports, '__esModule', { value: true });
12
12
  var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
13
13
  var PropTypes = require('prop-types');
14
14
  var React = require('react');
15
- var cx = require('classnames');
16
15
  var index = require('../IconButton/index.js');
17
16
  var events = require('../../tools/events.js');
18
- var usePrefix = require('../../internal/usePrefix.js');
19
- var useId = require('../../internal/useId.js');
17
+ var ButtonBase = require('./ButtonBase.js');
20
18
 
21
19
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
22
20
 
23
21
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
24
22
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
25
- var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
26
23
 
27
24
  const ButtonKinds = ['primary', 'secondary', 'danger', 'ghost', 'danger--primary', 'danger--ghost', 'danger--tertiary', 'tertiary'];
28
25
  const ButtonSizes = ['sm', 'md', 'lg', 'xl', '2xl'];
@@ -34,18 +31,13 @@ function isIconOnlyButton(hasIconOnly, _kind) {
34
31
  }
35
32
  return false;
36
33
  }
37
- const Button = /*#__PURE__*/React__default["default"].forwardRef(function Button(_ref, ref) {
38
- let {
34
+ const Button = /*#__PURE__*/React__default["default"].forwardRef(function Button(props, ref) {
35
+ const tooltipRef = React.useRef(null);
36
+ const {
39
37
  as,
40
38
  children,
41
- className,
42
- dangerDescription = 'danger',
43
- disabled = false,
44
39
  hasIconOnly = false,
45
- href,
46
40
  iconDescription,
47
- isExpressive = false,
48
- isSelected,
49
41
  kind = 'primary',
50
42
  onBlur,
51
43
  onClick,
@@ -54,92 +46,21 @@ const Button = /*#__PURE__*/React__default["default"].forwardRef(function Button
54
46
  onMouseLeave,
55
47
  renderIcon: ButtonImageElement,
56
48
  size,
57
- tabIndex,
58
49
  tooltipAlignment = 'center',
59
50
  tooltipPosition = 'top',
60
- type = 'button',
61
51
  ...rest
62
- } = _ref;
63
- const tooltipRef = React.useRef(null);
64
- const prefix = usePrefix.usePrefix();
52
+ } = props;
65
53
  const handleClick = evt => {
66
54
  // Prevent clicks on the tooltip from triggering the button click event
67
55
  if (evt.target === tooltipRef.current) {
68
56
  evt.preventDefault();
69
57
  }
70
58
  };
71
- const buttonClasses = cx__default["default"](className, {
72
- [`${prefix}--btn`]: true,
73
- [`${prefix}--btn--sm`]: size === 'sm' && !isExpressive,
74
- // TODO: V12 - Remove this class
75
- [`${prefix}--btn--md`]: size === 'md' && !isExpressive,
76
- // TODO: V12 - Remove this class
77
- [`${prefix}--btn--xl`]: size === 'xl',
78
- // TODO: V12 - Remove this class
79
- [`${prefix}--btn--2xl`]: size === '2xl',
80
- // TODO: V12 - Remove this class
81
- [`${prefix}--layout--size-${size}`]: size,
82
- [`${prefix}--btn--${kind}`]: kind,
83
- [`${prefix}--btn--disabled`]: disabled,
84
- [`${prefix}--btn--expressive`]: isExpressive,
85
- [`${prefix}--btn--icon-only`]: hasIconOnly,
86
- [`${prefix}--btn--selected`]: hasIconOnly && isSelected && kind === 'ghost'
87
- });
88
- const commonProps = {
89
- tabIndex,
90
- className: buttonClasses,
91
- ref
92
- };
93
- const buttonImage = !ButtonImageElement ? null : /*#__PURE__*/React__default["default"].createElement(ButtonImageElement, {
94
- "aria-label": iconDescription,
95
- className: `${prefix}--btn__icon`,
96
- "aria-hidden": "true"
97
- });
98
59
  const iconOnlyImage = !ButtonImageElement ? null : /*#__PURE__*/React__default["default"].createElement(ButtonImageElement, null);
99
- const dangerButtonVariants = ['danger', 'danger--tertiary', 'danger--ghost'];
100
- let component = 'button';
101
- const assistiveId = useId.useId('danger-description');
102
- const {
103
- 'aria-pressed': ariaPressed,
104
- 'aria-describedby': ariaDescribedBy
105
- } = rest;
106
- let otherProps = {
107
- disabled,
108
- type,
109
- 'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : ariaDescribedBy || undefined,
110
- 'aria-pressed': ariaPressed ?? (hasIconOnly && kind === 'ghost' ? isSelected : undefined)
111
- };
112
- const anchorProps = {
113
- href
114
- };
115
- let assistiveText = null;
116
- if (dangerButtonVariants.includes(kind)) {
117
- assistiveText = /*#__PURE__*/React__default["default"].createElement("span", {
118
- id: assistiveId,
119
- className: `${prefix}--visually-hidden`
120
- }, dangerDescription);
121
- }
122
- if (as) {
123
- component = as;
124
- otherProps = {
125
- ...otherProps,
126
- ...anchorProps
127
- };
128
- } else if (href && !disabled) {
129
- component = 'a';
130
- otherProps = anchorProps;
131
- }
132
60
  if (!isIconOnlyButton(hasIconOnly)) {
133
- return /*#__PURE__*/React__default["default"].createElement(component, {
134
- onMouseEnter,
135
- onMouseLeave,
136
- onFocus,
137
- onBlur,
138
- onClick,
139
- ...rest,
140
- ...commonProps,
141
- ...otherProps
142
- }, assistiveText, children, buttonImage);
61
+ return /*#__PURE__*/React__default["default"].createElement(ButtonBase["default"], _rollupPluginBabelHelpers["extends"]({
62
+ ref: ref
63
+ }, props));
143
64
  } else {
144
65
  let align = undefined;
145
66
  if (tooltipPosition === 'top' || tooltipPosition === 'bottom') {
@@ -156,7 +77,8 @@ const Button = /*#__PURE__*/React__default["default"].forwardRef(function Button
156
77
  if (tooltipPosition === 'right' || tooltipPosition === 'left') {
157
78
  align = tooltipPosition;
158
79
  }
159
- return /*#__PURE__*/React__default["default"].createElement(index.IconButton, _rollupPluginBabelHelpers["extends"]({
80
+ return /*#__PURE__*/React__default["default"].createElement(index.IconButton, _rollupPluginBabelHelpers["extends"]({}, rest, {
81
+ ref: ref,
160
82
  as: as,
161
83
  align: align,
162
84
  label: iconDescription,
@@ -166,8 +88,9 @@ const Button = /*#__PURE__*/React__default["default"].forwardRef(function Button
166
88
  onMouseLeave: onMouseLeave,
167
89
  onFocus: onFocus,
168
90
  onBlur: onBlur,
169
- onClick: events.composeEventHandlers([onClick, handleClick])
170
- }, rest, commonProps, otherProps), iconOnlyImage ?? children);
91
+ onClick: events.composeEventHandlers([onClick, handleClick]),
92
+ renderIcon: iconOnlyImage ? null : ButtonImageElement // avoid doubling the icon.
93
+ }), iconOnlyImage ?? children);
171
94
  }
172
95
  });
173
96
  Button.displayName = 'Button';
@@ -0,0 +1,10 @@
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 React from 'react';
8
+ import { ButtonProps } from './Button';
9
+ declare const ButtonBase: React.ForwardRefExoticComponent<Omit<ButtonProps<React.ElementType<any>>, "ref"> & React.RefAttributes<unknown>>;
10
+ export default ButtonBase;