@carbon/react 1.49.0 → 1.50.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 (30) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +1011 -982
  2. package/es/components/Button/Button.js +3 -2
  3. package/es/components/ComboButton/index.js +14 -0
  4. package/es/components/ContainedList/ContainedList.js +5 -3
  5. package/es/components/ContainedList/ContainedListItem/ContainedListItem.js +5 -3
  6. package/es/components/Menu/Menu.d.ts +9 -1
  7. package/es/components/Menu/Menu.js +34 -0
  8. package/es/components/MenuButton/index.js +13 -0
  9. package/es/components/MultiSelect/MultiSelect.js +2 -1
  10. package/es/components/Notification/Notification.d.ts +75 -0
  11. package/es/components/Notification/Notification.js +84 -2
  12. package/es/components/Notification/index.d.ts +1 -1
  13. package/es/components/OverflowMenu/next/index.js +16 -2
  14. package/es/index.js +1 -1
  15. package/es/internal/useNoInteractiveChildren.js +13 -1
  16. package/lib/components/Button/Button.js +3 -2
  17. package/lib/components/ComboButton/index.js +14 -0
  18. package/lib/components/ContainedList/ContainedList.js +5 -3
  19. package/lib/components/ContainedList/ContainedListItem/ContainedListItem.js +5 -3
  20. package/lib/components/Menu/Menu.d.ts +9 -1
  21. package/lib/components/Menu/Menu.js +34 -0
  22. package/lib/components/MenuButton/index.js +13 -0
  23. package/lib/components/MultiSelect/MultiSelect.js +2 -1
  24. package/lib/components/Notification/Notification.d.ts +75 -0
  25. package/lib/components/Notification/Notification.js +83 -0
  26. package/lib/components/Notification/index.d.ts +1 -1
  27. package/lib/components/OverflowMenu/next/index.js +16 -2
  28. package/lib/index.js +1 -0
  29. package/lib/internal/useNoInteractiveChildren.js +13 -0
  30. package/package.json +4 -4
@@ -90,12 +90,13 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
90
90
  let component = 'button';
91
91
  const assistiveId = useId('danger-description');
92
92
  const {
93
- 'aria-pressed': ariaPressed
93
+ 'aria-pressed': ariaPressed,
94
+ 'aria-describedby': ariaDescribedBy
94
95
  } = rest;
95
96
  let otherProps = {
96
97
  disabled,
97
98
  type,
98
- 'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : undefined,
99
+ 'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : ariaDescribedBy || undefined,
99
100
  'aria-pressed': ariaPressed ?? (hasIconOnly && kind === 'ghost' ? isSelected : undefined)
100
101
  };
101
102
  const anchorProps = {
@@ -36,6 +36,7 @@ const ComboButton = /*#__PURE__*/React__default.forwardRef(function ComboButton(
36
36
  label,
37
37
  onClick,
38
38
  size = 'lg',
39
+ menuAlignment = 'bottom',
39
40
  tooltipAlignment,
40
41
  translateWithId: t = defaultTranslateWithId,
41
42
  ...rest
@@ -70,10 +71,15 @@ const ComboButton = /*#__PURE__*/React__default.forwardRef(function ComboButton(
70
71
  }
71
72
  function handleOpen() {
72
73
  menuRef.current.style.inlineSize = `${width}px`;
74
+ menuRef.current.style.minInlineSize = `${width}px`;
75
+ if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
76
+ menuRef.current.style.inlineSize = `fit-content`;
77
+ }
73
78
  }
74
79
  const containerClasses = cx(`${prefix}--combo-button__container`, `${prefix}--combo-button__container--${size}`, {
75
80
  [`${prefix}--combo-button__container--open`]: open
76
81
  }, className);
82
+ const menuClasses = cx(`${prefix}--combo-button__${menuAlignment}`);
77
83
  const primaryActionClasses = cx(`${prefix}--combo-button__primary-action`);
78
84
  const triggerClasses = cx(`${prefix}--combo-button__trigger`);
79
85
  return /*#__PURE__*/React__default.createElement("div", _extends({}, rest, {
@@ -83,6 +89,7 @@ const ComboButton = /*#__PURE__*/React__default.forwardRef(function ComboButton(
83
89
  }), /*#__PURE__*/React__default.createElement("div", {
84
90
  className: primaryActionClasses
85
91
  }, /*#__PURE__*/React__default.createElement(Button, {
92
+ title: label,
86
93
  size: size,
87
94
  disabled: disabled,
88
95
  onClick: handlePrimaryActionClick
@@ -98,6 +105,9 @@ const ComboButton = /*#__PURE__*/React__default.forwardRef(function ComboButton(
98
105
  onMouseDown: handleTriggerMousedown,
99
106
  "aria-controls": open ? id : null
100
107
  }, _ChevronDown || (_ChevronDown = /*#__PURE__*/React__default.createElement(ChevronDown, null))), /*#__PURE__*/React__default.createElement(Menu, {
108
+ containerRef: containerRef,
109
+ menuAlignment: menuAlignment,
110
+ className: menuClasses,
101
111
  ref: menuRef,
102
112
  id: id,
103
113
  label: t('carbon.combo-button.additional-actions'),
@@ -127,6 +137,10 @@ ComboButton.propTypes = {
127
137
  * Provide the label to be renderd on the primary action button.
128
138
  */
129
139
  label: PropTypes.string.isRequired,
140
+ /**
141
+ * Experimental property. Specify how the menu should align with the button element
142
+ */
143
+ menuAlignment: PropTypes.oneOf(['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end']),
130
144
  /**
131
145
  * Provide an optional function to be called when the primary action element is clicked.
132
146
  */
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
8
9
  import React__default from 'react';
9
10
  import PropTypes from 'prop-types';
10
11
  import cx from 'classnames';
@@ -44,7 +45,8 @@ function ContainedList(_ref) {
44
45
  isInset,
45
46
  kind = variants[0],
46
47
  label,
47
- size
48
+ size,
49
+ ...rest
48
50
  } = _ref;
49
51
  const labelId = `${useId('contained-list')}-header`;
50
52
  const prefix = usePrefix();
@@ -57,9 +59,9 @@ function ContainedList(_ref) {
57
59
  const filteredChildren = filterChildren(children);
58
60
  const isActionSearch = ['Search', 'ExpandableSearch'].includes(action?.type?.displayName);
59
61
  const renderedChildren = renderChildren(children);
60
- return /*#__PURE__*/React__default.createElement("div", {
62
+ return /*#__PURE__*/React__default.createElement("div", _extends({
61
63
  className: classes
62
- }, /*#__PURE__*/React__default.createElement("div", {
64
+ }, rest), /*#__PURE__*/React__default.createElement("div", {
63
65
  className: `${prefix}--contained-list__header`
64
66
  }, /*#__PURE__*/React__default.createElement("div", {
65
67
  id: labelId,
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import { extends as _extends } from '../../../_virtual/_rollupPluginBabelHelpers.js';
8
9
  import React__default from 'react';
9
10
  import PropTypes from 'prop-types';
10
11
  import cx from 'classnames';
@@ -18,7 +19,8 @@ function ContainedListItem(_ref) {
18
19
  className,
19
20
  disabled = false,
20
21
  onClick,
21
- renderIcon: IconElement
22
+ renderIcon: IconElement,
23
+ ...rest
22
24
  } = _ref;
23
25
  const prefix = usePrefix();
24
26
  const isClickable = onClick !== undefined;
@@ -30,9 +32,9 @@ function ContainedListItem(_ref) {
30
32
  const content = /*#__PURE__*/React__default.createElement(React__default.Fragment, null, IconElement && /*#__PURE__*/React__default.createElement("div", {
31
33
  className: `${prefix}--contained-list-item__icon`
32
34
  }, /*#__PURE__*/React__default.createElement(IconElement, null)), /*#__PURE__*/React__default.createElement("div", null, children));
33
- return /*#__PURE__*/React__default.createElement("li", {
35
+ return /*#__PURE__*/React__default.createElement("li", _extends({
34
36
  className: classes
35
- }, isClickable ? /*#__PURE__*/React__default.createElement("button", {
37
+ }, rest), isClickable ? /*#__PURE__*/React__default.createElement("button", {
36
38
  className: `${prefix}--contained-list-item__content`,
37
39
  type: "button",
38
40
  disabled: disabled,
@@ -4,8 +4,12 @@
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 React from 'react';
7
+ import React, { RefObject } from 'react';
8
8
  interface MenuProps extends React.HTMLAttributes<HTMLUListElement> {
9
+ /**
10
+ * The ref of the containing element, used for positioning and alignment of the menu
11
+ */
12
+ containerRef?: RefObject<HTMLDivElement>;
9
13
  /**
10
14
  * A collection of MenuItems to be rendered within this Menu.
11
15
  */
@@ -18,6 +22,10 @@ interface MenuProps extends React.HTMLAttributes<HTMLUListElement> {
18
22
  * A label describing the Menu.
19
23
  */
20
24
  label?: string;
25
+ /**
26
+ * Specify how the menu should align with the button element
27
+ */
28
+ menuAlignment?: string;
21
29
  /**
22
30
  * The mode of this menu. Defaults to full.
23
31
  * `full` supports nesting and selectable menu items, but no icons.
@@ -24,7 +24,9 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
24
24
  let {
25
25
  children,
26
26
  className,
27
+ containerRef,
27
28
  label,
29
+ menuAlignment,
28
30
  mode = 'full',
29
31
  onClose,
30
32
  onOpen,
@@ -61,6 +63,15 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
61
63
  const [position, setPosition] = useState([-1, -1]);
62
64
  const focusableItems = childContext.state.items.filter(item => !item.disabled && item.ref.current);
63
65
 
66
+ // Getting the width from the parent container element - controlled
67
+ let actionButtonWidth;
68
+ if (containerRef?.current) {
69
+ const {
70
+ width: w
71
+ } = containerRef.current.getBoundingClientRect();
72
+ actionButtonWidth = w;
73
+ }
74
+
64
75
  // Set RTL based on document direction or `LayoutDirection`
65
76
  const {
66
77
  direction
@@ -174,6 +185,16 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
174
185
  }
175
186
  };
176
187
 
188
+ // Avoid that the Menu render incorrectly when the postion is set in the right side of the screen
189
+ if (actionButtonWidth && actionButtonWidth < axes.x.size && (menuAlignment === 'bottom' || menuAlignment === 'top')) {
190
+ axes.x.size = actionButtonWidth;
191
+ }
192
+
193
+ // if 'axes.x.anchor' is lower than 87px dynamically switch render side
194
+ if (actionButtonWidth && (menuAlignment === 'bottom-end' || menuAlignment === 'top-end') && axes.x.anchor >= 87 && actionButtonWidth < axes.x.size) {
195
+ const diff = axes.x.anchor + axes.x.reversedAnchor;
196
+ axes.x.anchor = axes.x.anchor + diff;
197
+ }
177
198
  const {
178
199
  max,
179
200
  size,
@@ -190,6 +211,14 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
190
211
  reversedAnchor - size >= 0 ? reversedAnchor - size + offset : false,
191
212
  // align at max (second fallback)
192
213
  max - spacing - size];
214
+ const topAlignment = menuAlignment === 'top' || menuAlignment === 'top-end' || menuAlignment === 'top-start';
215
+
216
+ // If the tooltip is not visible in the top, switch to the bototm
217
+ if (typeof options[0] === 'number' && topAlignment && options[0] >= 0 && !options[1] && axis === 'y') {
218
+ menu.current.style.transform = 'translate(0)';
219
+ } else if (topAlignment && !options[0] && axis === 'y') {
220
+ options[0] = anchor - offset;
221
+ }
193
222
 
194
223
  // Previous array `options`, has at least one item that is a number (the last one - second fallback).
195
224
  // That guarantees that the return of `find()` will always be a number
@@ -244,6 +273,7 @@ const Menu = /*#__PURE__*/React__default.forwardRef(function Menu(_ref, forwardR
244
273
  // visibility is needed for focusing elements.
245
274
  // opacity is only set once the position has been set correctly
246
275
  // to avoid a flicker effect when opening.
276
+ [`${prefix}--menu--box-shadow-top`]: menuAlignment && menuAlignment.slice(0, 3) === 'top',
247
277
  [`${prefix}--menu--open`]: open,
248
278
  [`${prefix}--menu--shown`]: position[0] >= 0 && position[1] >= 0,
249
279
  [`${prefix}--menu--with-icons`]: childContext.state.hasIcons
@@ -274,6 +304,10 @@ Menu.propTypes = {
274
304
  * A label describing the Menu.
275
305
  */
276
306
  label: PropTypes.string,
307
+ /**
308
+ * Specify how the menu should align with the button element
309
+ */
310
+ menuAlignment: PropTypes.string,
277
311
  /**
278
312
  * The mode of this menu. Defaults to full.
279
313
  * `full` supports nesting and selectable menu items, but no icons.
@@ -30,6 +30,7 @@ const MenuButton = /*#__PURE__*/React__default.forwardRef(function MenuButton(_r
30
30
  kind = defaultButtonKind,
31
31
  label,
32
32
  size = 'lg',
33
+ menuAlignment = 'bottom',
33
34
  tabIndex = 0,
34
35
  ...rest
35
36
  } = _ref;
@@ -58,11 +59,16 @@ const MenuButton = /*#__PURE__*/React__default.forwardRef(function MenuButton(_r
58
59
  }
59
60
  function handleOpen() {
60
61
  menuRef.current.style.inlineSize = `${width}px`;
62
+ menuRef.current.style.minInlineSize = `${width}px`;
63
+ if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
64
+ menuRef.current.style.inlineSize = `fit-content`;
65
+ }
61
66
  }
62
67
  const containerClasses = cx(`${prefix}--menu-button__container`, className);
63
68
  const triggerClasses = cx(`${prefix}--menu-button__trigger`, {
64
69
  [`${prefix}--menu-button__trigger--open`]: open
65
70
  });
71
+ const menuClasses = cx(`${prefix}--menu-button__${menuAlignment}`);
66
72
  const buttonKind = validButtonKinds.includes(kind) ? kind : defaultButtonKind;
67
73
  return /*#__PURE__*/React__default.createElement("div", _extends({}, rest, {
68
74
  ref: ref,
@@ -81,6 +87,9 @@ const MenuButton = /*#__PURE__*/React__default.forwardRef(function MenuButton(_r
81
87
  onMouseDown: handleMousedown,
82
88
  "aria-controls": open ? id : null
83
89
  }, label), /*#__PURE__*/React__default.createElement(Menu, {
90
+ containerRef: triggerRef,
91
+ menuAlignment: menuAlignment,
92
+ className: menuClasses,
84
93
  ref: menuRef,
85
94
  id: id,
86
95
  label: label,
@@ -114,6 +123,10 @@ MenuButton.propTypes = {
114
123
  * Provide the label to be renderd on the trigger button.
115
124
  */
116
125
  label: PropTypes.string.isRequired,
126
+ /**
127
+ * Experimental property. Specify how the menu should align with the button element
128
+ */
129
+ menuAlignment: PropTypes.oneOf(['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end']),
117
130
  /**
118
131
  * Specify the size of the button and menu.
119
132
  */
@@ -306,13 +306,14 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
306
306
  size: 'mini'
307
307
  });
308
308
  }
309
+ const itemsSelectedText = selectedItems.length > 0 && selectedItems.map(item => item.text);
309
310
  return /*#__PURE__*/React__default.createElement("div", {
310
311
  className: wrapperClasses
311
312
  }, /*#__PURE__*/React__default.createElement("label", _extends({
312
313
  className: titleClasses
313
314
  }, getLabelProps()), titleText && titleText, selectedItems.length > 0 && /*#__PURE__*/React__default.createElement("span", {
314
315
  className: `${prefix}--visually-hidden`
315
- }, clearSelectionDescription, " ", selectedItems.length, ",", clearSelectionText)), /*#__PURE__*/React__default.createElement(ListBox, {
316
+ }, clearSelectionDescription, " ", selectedItems.length, ' ', itemsSelectedText, ",", clearSelectionText)), /*#__PURE__*/React__default.createElement(ListBox, {
316
317
  onFocus: isFluid ? handleFocus : undefined,
317
318
  onBlur: isFluid ? handleFocus : undefined,
318
319
  type: type,
@@ -513,3 +513,78 @@ export declare namespace ActionableNotification {
513
513
  title: PropTypes.Requireable<string>;
514
514
  };
515
515
  }
516
+ /**
517
+ * StaticNotification
518
+ * ==================
519
+ */
520
+ export interface StaticNotificationProps extends HTMLAttributes<HTMLDivElement> {
521
+ /**
522
+ * Specify the content
523
+ */
524
+ children?: ReactNode;
525
+ /**
526
+ * Specify an optional className to be applied to the notification box
527
+ */
528
+ className?: string;
529
+ /**
530
+ * Specify what state the notification represents
531
+ */
532
+ kind?: 'error' | 'info' | 'info-square' | 'success' | 'warning' | 'warning-alt';
533
+ /**
534
+ * Specify whether you are using the low contrast variant of the StaticNotification.
535
+ */
536
+ lowContrast?: boolean;
537
+ /**
538
+ * Provide a description for "status" icon that can be read by screen readers
539
+ */
540
+ statusIconDescription?: string;
541
+ /**
542
+ * Specify the subtitle
543
+ */
544
+ subtitle?: string;
545
+ /**
546
+ * Specify the title
547
+ */
548
+ title?: string;
549
+ /**
550
+ * Specify the id for the element containing the title
551
+ */
552
+ titleId?: string;
553
+ }
554
+ export declare function StaticNotification({ children, title, titleId, subtitle, statusIconDescription, className, kind, lowContrast, ...rest }: StaticNotificationProps): import("react/jsx-runtime").JSX.Element;
555
+ export declare namespace StaticNotification {
556
+ var propTypes: {
557
+ /**
558
+ * Specify the content
559
+ */
560
+ children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
561
+ /**
562
+ * Specify an optional className to be applied to the notification box
563
+ */
564
+ className: PropTypes.Requireable<string>;
565
+ /**
566
+ * Specify what state the notification represents
567
+ */
568
+ kind: PropTypes.Requireable<string>;
569
+ /**
570
+ * Specify whether you are using the low contrast variant of the StaticNotification.
571
+ */
572
+ lowContrast: PropTypes.Requireable<boolean>;
573
+ /**
574
+ * Provide a description for "status" icon that can be read by screen readers
575
+ */
576
+ statusIconDescription: PropTypes.Requireable<string>;
577
+ /**
578
+ * Specify the subtitle
579
+ */
580
+ subtitle: PropTypes.Requireable<string>;
581
+ /**
582
+ * Specify the title
583
+ */
584
+ title: PropTypes.Requireable<string>;
585
+ /**
586
+ * Specify the id for the element containing the title
587
+ */
588
+ titleId: PropTypes.Requireable<string>;
589
+ };
590
+ }
@@ -15,7 +15,7 @@ import '../Text/index.js';
15
15
  import Button from '../Button/Button.js';
16
16
  import '../Button/Button.Skeleton.js';
17
17
  import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
18
- import { useNoInteractiveChildren } from '../../internal/useNoInteractiveChildren.js';
18
+ import { useNoInteractiveChildren, useInteractiveChildrenNeedDescription } from '../../internal/useNoInteractiveChildren.js';
19
19
  import { usePrefix } from '../../internal/usePrefix.js';
20
20
  import { useId } from '../../internal/useId.js';
21
21
  import { noopFn } from '../../internal/noopFn.js';
@@ -678,4 +678,86 @@ ActionableNotification.propTypes = {
678
678
  title: PropTypes.string
679
679
  };
680
680
 
681
- export { ActionableNotification, InlineNotification, NotificationActionButton, NotificationButton, ToastNotification };
681
+ /**
682
+ * StaticNotification
683
+ * ==================
684
+ */
685
+
686
+ function StaticNotification(_ref8) {
687
+ let {
688
+ children,
689
+ title,
690
+ titleId,
691
+ subtitle,
692
+ statusIconDescription,
693
+ className,
694
+ kind = 'error',
695
+ lowContrast,
696
+ ...rest
697
+ } = _ref8;
698
+ const prefix = usePrefix();
699
+ const containerClassName = cx(className, {
700
+ [`${prefix}--inline-notification`]: true,
701
+ [`${prefix}--inline-notification--low-contrast`]: lowContrast,
702
+ [`${prefix}--inline-notification--${kind}`]: kind,
703
+ [`${prefix}--inline-notification--hide-close-button`]: true
704
+ });
705
+ const ref = useRef(null);
706
+ useInteractiveChildrenNeedDescription(ref, `interactive child node(s) should have an \`aria-describedby\` property with a value matching the value of \`titleId\``);
707
+ return /*#__PURE__*/React__default.createElement("div", _extends({
708
+ ref: ref
709
+ }, rest, {
710
+ className: containerClassName
711
+ }), /*#__PURE__*/React__default.createElement("div", {
712
+ className: `${prefix}--inline-notification__details`
713
+ }, /*#__PURE__*/React__default.createElement(NotificationIcon, {
714
+ notificationType: "inline",
715
+ kind: kind,
716
+ iconDescription: statusIconDescription || `${kind} icon`
717
+ }), /*#__PURE__*/React__default.createElement("div", {
718
+ className: `${prefix}--inline-notification__text-wrapper`
719
+ }, title && /*#__PURE__*/React__default.createElement(Text, {
720
+ as: "div",
721
+ id: titleId,
722
+ className: `${prefix}--inline-notification__title`
723
+ }, title), subtitle && /*#__PURE__*/React__default.createElement(Text, {
724
+ as: "div",
725
+ className: `${prefix}--inline-notification__subtitle`
726
+ }, subtitle), children)));
727
+ }
728
+ StaticNotification.propTypes = {
729
+ /**
730
+ * Specify the content
731
+ */
732
+ children: PropTypes.node,
733
+ /**
734
+ * Specify an optional className to be applied to the notification box
735
+ */
736
+ className: PropTypes.string,
737
+ /**
738
+ * Specify what state the notification represents
739
+ */
740
+ kind: PropTypes.oneOf(['error', 'info', 'info-square', 'success', 'warning', 'warning-alt']),
741
+ /**
742
+ * Specify whether you are using the low contrast variant of the StaticNotification.
743
+ */
744
+ lowContrast: PropTypes.bool,
745
+ /**
746
+ * Provide a description for "status" icon that can be read by screen readers
747
+ */
748
+ statusIconDescription: PropTypes.string,
749
+ /**
750
+ * Specify the subtitle
751
+ */
752
+ subtitle: PropTypes.string,
753
+ /**
754
+ * Specify the title
755
+ */
756
+ title: PropTypes.string,
757
+ /**
758
+ * Specify the id for the element containing the title
759
+ */
760
+ titleId: PropTypes.string
761
+ };
762
+
763
+ export { ActionableNotification, InlineNotification, NotificationActionButton, NotificationButton, StaticNotification, ToastNotification };
@@ -4,4 +4,4 @@
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
- export { NotificationActionButton, type NotificationActionButtonProps, NotificationButton, type NotificationButtonProps, ToastNotification, type ToastNotificationProps, InlineNotification, type InlineNotificationProps, ActionableNotification, type ActionableNotificationProps, } from './Notification';
7
+ export { NotificationActionButton, type NotificationActionButtonProps, NotificationButton, type NotificationButtonProps, ToastNotification, type ToastNotificationProps, InlineNotification, type InlineNotificationProps, ActionableNotification, type ActionableNotificationProps, StaticNotification, type StaticNotificationProps, } from './Notification';
@@ -25,6 +25,7 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
25
25
  label = 'Options',
26
26
  renderIcon: IconElement = OverflowMenuVertical,
27
27
  size = defaultSize,
28
+ menuAlignment = 'bottom-start',
28
29
  tooltipAlignment,
29
30
  ...rest
30
31
  } = _ref;
@@ -35,11 +36,17 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
35
36
  open,
36
37
  x,
37
38
  y,
38
- handleClick,
39
+ handleClick: hookOnClick,
39
40
  handleMousedown,
40
41
  handleClose
41
42
  } = useAttachedMenu(triggerRef);
43
+ function handleTriggerClick() {
44
+ if (triggerRef.current) {
45
+ hookOnClick();
46
+ }
47
+ }
42
48
  const containerClasses = cx(className, `${prefix}--overflow-menu__container`);
49
+ const menuClasses = cx(`${prefix}--overflow-menu__${menuAlignment}`);
43
50
  const triggerClasses = cx(`${prefix}--overflow-menu`, {
44
51
  [`${prefix}--overflow-menu--open`]: open
45
52
  }, size !== defaultSize && `${prefix}--overflow-menu--${size}`);
@@ -52,7 +59,7 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
52
59
  "aria-haspopup": true,
53
60
  "aria-expanded": open,
54
61
  className: triggerClasses,
55
- onClick: handleClick,
62
+ onClick: handleTriggerClick,
56
63
  onMouseDown: handleMousedown,
57
64
  ref: triggerRef,
58
65
  label: label,
@@ -60,6 +67,9 @@ const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMen
60
67
  }, /*#__PURE__*/React__default.createElement(IconElement, {
61
68
  className: `${prefix}--overflow-menu__icon`
62
69
  })), /*#__PURE__*/React__default.createElement(Menu, {
70
+ containerRef: triggerRef,
71
+ menuAlignment: menuAlignment,
72
+ className: menuClasses,
63
73
  id: id,
64
74
  size: size,
65
75
  open: open,
@@ -82,6 +92,10 @@ OverflowMenu.propTypes = {
82
92
  * A label describing the options available. Is used in the trigger tooltip and as the menu's accessible label.
83
93
  */
84
94
  label: PropTypes.string,
95
+ /**
96
+ * Experimental property. Specify how the menu should align with the button element
97
+ */
98
+ menuAlignment: PropTypes.oneOf(['top-start', 'top-end', 'bottom-start', 'bottom-end']),
85
99
  /**
86
100
  * Otionally provide a custom icon to be rendered on the trigger button.
87
101
  */
package/es/index.js CHANGED
@@ -65,7 +65,7 @@ export { MenuItem, MenuItemDivider, MenuItemGroup, MenuItemRadioGroup, MenuItemS
65
65
  export { MenuButton } from './components/MenuButton/index.js';
66
66
  export { default as Modal } from './components/Modal/Modal.js';
67
67
  export { default as ModalWrapper } from './components/ModalWrapper/ModalWrapper.js';
68
- export { ActionableNotification, InlineNotification, NotificationActionButton, NotificationButton, ToastNotification } from './components/Notification/Notification.js';
68
+ export { ActionableNotification, InlineNotification, NotificationActionButton, NotificationButton, StaticNotification, ToastNotification } from './components/Notification/Notification.js';
69
69
  export { default as NumberInputSkeleton } from './components/NumberInput/NumberInput.Skeleton.js';
70
70
  export { NumberInput } from './components/NumberInput/NumberInput.js';
71
71
  export { default as OrderedList } from './components/OrderedList/OrderedList.js';
@@ -19,6 +19,18 @@ function useNoInteractiveChildren(ref) {
19
19
  });
20
20
  }
21
21
  }
22
+ function useInteractiveChildrenNeedDescription(ref) {
23
+ let message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : `interactive child node(s) should have an \`aria-describedby\` property`;
24
+ if (process.env.NODE_ENV !== "production") {
25
+ // eslint-disable-next-line react-hooks/rules-of-hooks
26
+ useEffect(() => {
27
+ const node = ref.current ? getInteractiveContent(ref.current) : false;
28
+ if (node && !node.hasAttribute('aria-describedby')) {
29
+ throw new Error(`Error: ${message}.\n\nInstead found: ${node.outerHTML}`);
30
+ }
31
+ });
32
+ }
33
+ }
22
34
 
23
35
  /**
24
36
  * Determines if a given DOM node has interactive content, or is itself
@@ -90,4 +102,4 @@ function isFocusable(element) {
90
102
  }
91
103
  }
92
104
 
93
- export { getInteractiveContent, getRoleContent, useNoInteractiveChildren };
105
+ export { getInteractiveContent, getRoleContent, useInteractiveChildrenNeedDescription, useNoInteractiveChildren };
@@ -100,12 +100,13 @@ const Button = /*#__PURE__*/React__default["default"].forwardRef(function Button
100
100
  let component = 'button';
101
101
  const assistiveId = useId.useId('danger-description');
102
102
  const {
103
- 'aria-pressed': ariaPressed
103
+ 'aria-pressed': ariaPressed,
104
+ 'aria-describedby': ariaDescribedBy
104
105
  } = rest;
105
106
  let otherProps = {
106
107
  disabled,
107
108
  type,
108
- 'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : undefined,
109
+ 'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : ariaDescribedBy || undefined,
109
110
  'aria-pressed': ariaPressed ?? (hasIconOnly && kind === 'ghost' ? isSelected : undefined)
110
111
  };
111
112
  const anchorProps = {
@@ -46,6 +46,7 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
46
46
  label,
47
47
  onClick,
48
48
  size = 'lg',
49
+ menuAlignment = 'bottom',
49
50
  tooltipAlignment,
50
51
  translateWithId: t = defaultTranslateWithId,
51
52
  ...rest
@@ -80,10 +81,15 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
80
81
  }
81
82
  function handleOpen() {
82
83
  menuRef.current.style.inlineSize = `${width}px`;
84
+ menuRef.current.style.minInlineSize = `${width}px`;
85
+ if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
86
+ menuRef.current.style.inlineSize = `fit-content`;
87
+ }
83
88
  }
84
89
  const containerClasses = cx__default["default"](`${prefix}--combo-button__container`, `${prefix}--combo-button__container--${size}`, {
85
90
  [`${prefix}--combo-button__container--open`]: open
86
91
  }, className);
92
+ const menuClasses = cx__default["default"](`${prefix}--combo-button__${menuAlignment}`);
87
93
  const primaryActionClasses = cx__default["default"](`${prefix}--combo-button__primary-action`);
88
94
  const triggerClasses = cx__default["default"](`${prefix}--combo-button__trigger`);
89
95
  return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
@@ -93,6 +99,7 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
93
99
  }), /*#__PURE__*/React__default["default"].createElement("div", {
94
100
  className: primaryActionClasses
95
101
  }, /*#__PURE__*/React__default["default"].createElement(Button["default"], {
102
+ title: label,
96
103
  size: size,
97
104
  disabled: disabled,
98
105
  onClick: handlePrimaryActionClick
@@ -108,6 +115,9 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
108
115
  onMouseDown: handleTriggerMousedown,
109
116
  "aria-controls": open ? id : null
110
117
  }, _ChevronDown || (_ChevronDown = /*#__PURE__*/React__default["default"].createElement(iconsReact.ChevronDown, null))), /*#__PURE__*/React__default["default"].createElement(Menu.Menu, {
118
+ containerRef: containerRef,
119
+ menuAlignment: menuAlignment,
120
+ className: menuClasses,
111
121
  ref: menuRef,
112
122
  id: id,
113
123
  label: t('carbon.combo-button.additional-actions'),
@@ -137,6 +147,10 @@ ComboButton.propTypes = {
137
147
  * Provide the label to be renderd on the primary action button.
138
148
  */
139
149
  label: PropTypes__default["default"].string.isRequired,
150
+ /**
151
+ * Experimental property. Specify how the menu should align with the button element
152
+ */
153
+ menuAlignment: PropTypes__default["default"].oneOf(['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end']),
140
154
  /**
141
155
  * Provide an optional function to be called when the primary action element is clicked.
142
156
  */
@@ -9,6 +9,7 @@
9
9
 
10
10
  Object.defineProperty(exports, '__esModule', { value: true });
11
11
 
12
+ var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
12
13
  var React = require('react');
13
14
  var PropTypes = require('prop-types');
14
15
  var cx = require('classnames');
@@ -54,7 +55,8 @@ function ContainedList(_ref) {
54
55
  isInset,
55
56
  kind = variants[0],
56
57
  label,
57
- size
58
+ size,
59
+ ...rest
58
60
  } = _ref;
59
61
  const labelId = `${useId.useId('contained-list')}-header`;
60
62
  const prefix = usePrefix.usePrefix();
@@ -67,9 +69,9 @@ function ContainedList(_ref) {
67
69
  const filteredChildren = filterChildren(children);
68
70
  const isActionSearch = ['Search', 'ExpandableSearch'].includes(action?.type?.displayName);
69
71
  const renderedChildren = renderChildren(children);
70
- return /*#__PURE__*/React__default["default"].createElement("div", {
72
+ return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
71
73
  className: classes
72
- }, /*#__PURE__*/React__default["default"].createElement("div", {
74
+ }, rest), /*#__PURE__*/React__default["default"].createElement("div", {
73
75
  className: `${prefix}--contained-list__header`
74
76
  }, /*#__PURE__*/React__default["default"].createElement("div", {
75
77
  id: labelId,