@carbon/react 1.97.0-rc.0 → 1.98.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 (79) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +1010 -975
  2. package/es/components/ButtonSet/ButtonSet.d.ts +5 -0
  3. package/es/components/ButtonSet/ButtonSet.js +68 -4
  4. package/es/components/CodeSnippet/CodeSnippet.d.ts +1 -1
  5. package/es/components/ComposedModal/ComposedModal.js +3 -2
  6. package/es/components/Copy/Copy.d.ts +1 -1
  7. package/es/components/CopyButton/CopyButton.d.ts +1 -1
  8. package/es/components/DataTable/DataTable.d.ts +2 -1
  9. package/es/components/DataTable/TableContainer.d.ts +10 -2
  10. package/es/components/DataTable/TableContainer.js +15 -3
  11. package/es/components/DataTable/state/sorting.d.ts +2 -4
  12. package/es/components/DataTableSkeleton/DataTableSkeleton.d.ts +1 -1
  13. package/es/components/DataTableSkeleton/DataTableSkeleton.js +1 -1
  14. package/es/components/DatePicker/DatePicker.d.ts +3 -2
  15. package/es/components/DatePicker/DatePicker.js +18 -135
  16. package/es/components/DatePicker/DatePickerLocales.d.ts +12 -0
  17. package/es/components/DatePicker/DatePickerLocales.js +135 -0
  18. package/es/components/DatePickerInput/DatePickerInput.js +50 -28
  19. package/es/components/Dropdown/Dropdown.js +9 -1
  20. package/es/components/FileUploader/FileUploader.d.ts +23 -8
  21. package/es/components/FileUploader/FileUploader.js +53 -33
  22. package/es/components/FileUploader/FileUploaderButton.js +2 -2
  23. package/es/components/FileUploader/FileUploaderDropContainer.d.ts +13 -2
  24. package/es/components/FileUploader/FileUploaderDropContainer.js +15 -6
  25. package/es/components/FileUploader/FileUploaderItem.js +9 -6
  26. package/es/components/Menu/index.d.ts +4 -3
  27. package/es/components/Modal/Modal.js +3 -2
  28. package/es/components/Notification/Notification.js +3 -2
  29. package/es/components/Pagination/Pagination.js +5 -5
  30. package/es/components/Popover/index.js +2 -2
  31. package/es/components/Select/Select.js +27 -33
  32. package/es/components/Toggletip/index.d.ts +1 -0
  33. package/es/components/Toggletip/index.js +1 -1
  34. package/es/components/Tooltip/index.d.ts +3 -2
  35. package/es/internal/FloatingMenu.js +8 -6
  36. package/es/internal/OptimizedResize.js +4 -5
  37. package/es/internal/wrapFocus.d.ts +4 -2
  38. package/es/internal/wrapFocus.js +5 -4
  39. package/es/tools/events.d.ts +1 -1
  40. package/lib/components/ButtonSet/ButtonSet.d.ts +5 -0
  41. package/lib/components/ButtonSet/ButtonSet.js +67 -3
  42. package/lib/components/CodeSnippet/CodeSnippet.d.ts +1 -1
  43. package/lib/components/ComposedModal/ComposedModal.js +3 -2
  44. package/lib/components/Copy/Copy.d.ts +1 -1
  45. package/lib/components/CopyButton/CopyButton.d.ts +1 -1
  46. package/lib/components/DataTable/DataTable.d.ts +2 -1
  47. package/lib/components/DataTable/TableContainer.d.ts +10 -2
  48. package/lib/components/DataTable/TableContainer.js +15 -3
  49. package/lib/components/DataTable/state/sorting.d.ts +2 -4
  50. package/lib/components/DataTableSkeleton/DataTableSkeleton.d.ts +1 -1
  51. package/lib/components/DataTableSkeleton/DataTableSkeleton.js +1 -1
  52. package/lib/components/DatePicker/DatePicker.d.ts +3 -2
  53. package/lib/components/DatePicker/DatePicker.js +18 -135
  54. package/lib/components/DatePicker/DatePickerLocales.d.ts +12 -0
  55. package/lib/components/DatePicker/DatePickerLocales.js +137 -0
  56. package/lib/components/DatePickerInput/DatePickerInput.js +49 -27
  57. package/lib/components/Dropdown/Dropdown.js +9 -1
  58. package/lib/components/FileUploader/FileUploader.d.ts +23 -8
  59. package/lib/components/FileUploader/FileUploader.js +53 -33
  60. package/lib/components/FileUploader/FileUploaderButton.js +2 -2
  61. package/lib/components/FileUploader/FileUploaderDropContainer.d.ts +13 -2
  62. package/lib/components/FileUploader/FileUploaderDropContainer.js +15 -6
  63. package/lib/components/FileUploader/FileUploaderItem.js +9 -6
  64. package/lib/components/Menu/index.d.ts +4 -3
  65. package/lib/components/Modal/Modal.js +3 -2
  66. package/lib/components/Notification/Notification.js +3 -2
  67. package/lib/components/Pagination/Pagination.js +5 -5
  68. package/lib/components/Popover/index.js +2 -2
  69. package/lib/components/Select/Select.js +27 -33
  70. package/lib/components/Toggletip/index.d.ts +1 -0
  71. package/lib/components/Toggletip/index.js +3 -0
  72. package/lib/components/Tooltip/index.d.ts +3 -2
  73. package/lib/internal/FloatingMenu.js +8 -6
  74. package/lib/internal/OptimizedResize.js +4 -5
  75. package/lib/internal/wrapFocus.d.ts +4 -2
  76. package/lib/internal/wrapFocus.js +5 -4
  77. package/lib/tools/events.d.ts +1 -1
  78. package/package.json +20 -27
  79. package/telemetry.yml +2 -0
@@ -36,10 +36,10 @@ function FileUploaderItem({
36
36
  const textRef = useRef(null);
37
37
  const [isEllipsisApplied, setIsEllipsisApplied] = useState(false);
38
38
  const prefix = usePrefix();
39
- // eslint-disable-next-line react-hooks/rules-of-hooks -- https://github.com/carbon-design-system/carbon/issues/20452
39
+ const generatedId = useId();
40
40
  const {
41
41
  current: id
42
- } = useRef(uuid || useId());
42
+ } = useRef(uuid || generatedId);
43
43
  const classes = cx(`${prefix}--file__selected-file`, className, {
44
44
  [`${prefix}--file__selected-file--invalid`]: invalid,
45
45
  [`${prefix}--file__selected-file--md`]: size === 'md',
@@ -49,11 +49,14 @@ function FileUploaderItem({
49
49
  const filterSpaceName = name => {
50
50
  return name?.replace(/\s+/g, '');
51
51
  };
52
-
53
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
54
52
  const isEllipsisActive = element => {
55
- setIsEllipsisApplied(element.offsetWidth < element.scrollWidth);
56
- return element.offsetWidth < element.scrollWidth;
53
+ if (!element) {
54
+ setIsEllipsisApplied(false);
55
+ return false;
56
+ }
57
+ const isActive = element.offsetWidth < element.scrollWidth;
58
+ setIsEllipsisApplied(isActive);
59
+ return isActive;
57
60
  };
58
61
  useLayoutEffect(() => {
59
62
  isEllipsisActive(textRef.current);
@@ -4,6 +4,7 @@
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 { Menu } from './Menu';
8
- import { MenuItem, MenuItemDivider, MenuItemGroup, MenuItemRadioGroup, MenuItemSelectable } from './MenuItem';
9
- export { Menu, MenuItem, MenuItemDivider, MenuItemGroup, MenuItemRadioGroup, MenuItemSelectable, };
7
+ import { Menu, type MenuProps } from './Menu';
8
+ import { MenuItem, MenuItemDivider, MenuItemGroup, MenuItemRadioGroup, MenuItemSelectable, type MenuItemProps, type MenuItemDividerProps, type MenuItemGroupProps, type MenuItemRadioGroupProps, type MenuItemSelectableProps } from './MenuItem';
9
+ export { Menu, MenuItem, MenuItemDivider, MenuItemGroup, MenuItemRadioGroup, MenuItemSelectable, type MenuProps, type MenuItemProps, type MenuItemDividerProps, type MenuItemGroupProps, type MenuItemRadioGroupProps, type MenuItemSelectableProps, };
10
+ export default Menu;
@@ -167,7 +167,7 @@ const ModalDialog = /*#__PURE__*/React.forwardRef(function ModalDialog({
167
167
  // behavior by explicitly setting preventCloseOnClickOutside to false,
168
168
  // rather than just leaving it undefined.
169
169
  !passiveModal && preventCloseOnClickOutside === false;
170
- if (shouldCloseOnOutsideClick && target instanceof Node && !elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && innerModal.current && !innerModal.current.contains(target)) {
170
+ if (shouldCloseOnOutsideClick && target instanceof Node && !elementOrParentIsFloatingMenu(target, selectorsFloatingMenus, prefix) && innerModal.current && !innerModal.current.contains(target)) {
171
171
  onRequestClose(evt);
172
172
  }
173
173
  }
@@ -194,7 +194,8 @@ const ModalDialog = /*#__PURE__*/React.forwardRef(function ModalDialog({
194
194
  endTrapNode,
195
195
  currentActiveNode,
196
196
  oldActiveNode,
197
- selectorsFloatingMenus
197
+ selectorsFloatingMenus,
198
+ prefix
198
199
  });
199
200
  if (wrapFocusTimeout.current) {
200
201
  clearTimeout(wrapFocusTimeout.current);
@@ -509,7 +509,7 @@ function ActionableNotification({
509
509
  const focusTrapWithoutSentinels = focusTrapWithoutSentinelsFlag || deprecatedFlag;
510
510
  useIsomorphicEffect(() => {
511
511
  if (hasFocus && role === 'alertdialog') {
512
- const button = document.querySelector('button.cds--actionable-notification__action-button');
512
+ const button = document.querySelector(`button.${prefix}--actionable-notification__action-button`);
513
513
  button?.focus();
514
514
  }
515
515
  });
@@ -532,7 +532,8 @@ function ActionableNotification({
532
532
  startTrapNode,
533
533
  endTrapNode,
534
534
  currentActiveNode,
535
- oldActiveNode
535
+ oldActiveNode,
536
+ prefix
536
537
  });
537
538
  }
538
539
  }
@@ -7,16 +7,16 @@
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import { CaretLeft, CaretRight } from '@carbon/icons-react';
10
- import cx from 'classnames';
11
- import PropTypes from 'prop-types';
12
10
  import React, { useRef, useState, useEffect } from 'react';
11
+ import { IconButton } from '../IconButton/index.js';
12
+ import PropTypes from 'prop-types';
13
13
  import Select from '../Select/Select.js';
14
14
  import '../Select/Select.Skeleton.js';
15
15
  import SelectItem from '../SelectItem/SelectItem.js';
16
+ import cx from 'classnames';
17
+ import isEqual from 'react-fast-compare';
16
18
  import { useFallbackId } from '../../internal/useId.js';
17
19
  import { usePrefix } from '../../internal/usePrefix.js';
18
- import { IconButton } from '../IconButton/index.js';
19
- import isEqual from 'react-fast-compare';
20
20
 
21
21
  var _CaretLeft, _CaretRight;
22
22
  function mapPageSizesToObject(sizes) {
@@ -266,7 +266,7 @@ const Pagination = /*#__PURE__*/React.forwardRef(({
266
266
  onClick: decrementPage,
267
267
  ref: backBtnRef
268
268
  }, _CaretLeft || (_CaretLeft = /*#__PURE__*/React.createElement(CaretLeft, null))), /*#__PURE__*/React.createElement(IconButton, {
269
- align: "top-end",
269
+ align: "top",
270
270
  disabled: forwardButtonDisabled || isLastPage,
271
271
  kind: "ghost",
272
272
  className: forwardButtonClasses,
@@ -116,8 +116,8 @@ forwardRef) {
116
116
  // If a value is not set via a custom property, provide a default value that matches the
117
117
  // default values defined in the sass style file
118
118
  const getStyle = window.getComputedStyle(popover.current, null);
119
- const offsetProperty = getStyle.getPropertyValue('--cds-popover-offset');
120
- const caretProperty = getStyle.getPropertyValue('--cds-popover-caret-height');
119
+ const offsetProperty = getStyle.getPropertyValue(`--${prefix}-popover-offset`);
120
+ const caretProperty = getStyle.getPropertyValue(`--${prefix}-popover-caret-height`);
121
121
 
122
122
  // Handle if the property values are in px or rem.
123
123
  // We want to store just the base number value without a unit suffix
@@ -14,12 +14,12 @@ import { deprecate } from '../../prop-types/deprecate.js';
14
14
  import { usePrefix } from '../../internal/usePrefix.js';
15
15
  import '../FluidForm/FluidForm.js';
16
16
  import { FormContext } from '../FluidForm/FormContext.js';
17
- import { useId } from '../../internal/useId.js';
18
17
  import { composeEventHandlers } from '../../tools/events.js';
19
18
  import { Text } from '../Text/Text.js';
20
19
  import '../Text/TextDirection.js';
21
20
  import { AILabel } from '../AILabel/index.js';
22
21
  import { isComponentElement } from '../../internal/utils.js';
22
+ import { useNormalizedInputProps } from '../../internal/useNormalizedInputProps.js';
23
23
 
24
24
  const Select = /*#__PURE__*/React.forwardRef(({
25
25
  className,
@@ -49,7 +49,6 @@ const Select = /*#__PURE__*/React.forwardRef(({
49
49
  isFluid
50
50
  } = useContext(FormContext);
51
51
  const [isFocused, setIsFocused] = useState(false);
52
- const selectInstanceId = useId();
53
52
  // Convert children to an array of valid elements once using type narrowing
54
53
  const validChildren = React.Children.toArray(children).filter(child => /*#__PURE__*/React.isValidElement(child));
55
54
 
@@ -61,55 +60,50 @@ const Select = /*#__PURE__*/React.forwardRef(({
61
60
  // otherwise, fallback to the first option's text
62
61
  const initialTitle = other?.title || selectedOption?.props?.text || validChildren[0]?.props?.text || '';
63
62
  const [title, setTitle] = useState(initialTitle);
63
+ const normalizedProps = useNormalizedInputProps({
64
+ id,
65
+ disabled,
66
+ readOnly,
67
+ invalid,
68
+ invalidText,
69
+ warn,
70
+ warnText
71
+ });
64
72
  const selectClasses = cx({
65
73
  [`${prefix}--select`]: true,
66
74
  [`${prefix}--select--inline`]: inline,
67
75
  [`${prefix}--select--light`]: light,
68
- [`${prefix}--select--invalid`]: invalid,
69
- [`${prefix}--select--disabled`]: disabled,
76
+ [`${prefix}--select--invalid`]: normalizedProps.invalid,
77
+ [`${prefix}--select--disabled`]: normalizedProps.disabled,
70
78
  [`${prefix}--select--readonly`]: readOnly,
71
- [`${prefix}--select--warning`]: warn,
72
- [`${prefix}--select--fluid--invalid`]: isFluid && invalid,
79
+ [`${prefix}--select--warning`]: normalizedProps.warn,
80
+ [`${prefix}--select--fluid--invalid`]: isFluid && normalizedProps.invalid,
73
81
  [`${prefix}--select--fluid--focus`]: isFluid && isFocused,
74
82
  [`${prefix}--select--slug`]: slug,
75
83
  [`${prefix}--select--decorator`]: decorator
76
84
  });
77
85
  const labelClasses = cx(`${prefix}--label`, {
78
86
  [`${prefix}--visually-hidden`]: hideLabel,
79
- [`${prefix}--label--disabled`]: disabled
87
+ [`${prefix}--label--disabled`]: normalizedProps.disabled
80
88
  });
81
89
  const inputClasses = cx({
82
90
  [`${prefix}--select-input`]: true,
83
91
  [`${prefix}--select-input--${size}`]: size
84
92
  });
85
- const errorId = `${id}-error-msg`;
86
- const errorText = (() => {
87
- if (invalid) {
88
- return invalidText;
89
- }
90
- if (warn) {
91
- return warnText;
92
- }
93
- })();
94
- const error = invalid || warn ? /*#__PURE__*/React.createElement(Text, {
95
- as: "div",
96
- className: `${prefix}--form-requirement`,
97
- id: errorId
98
- }, errorText) : null;
93
+ const error = normalizedProps.validation;
99
94
  const helperTextClasses = cx(`${prefix}--form__helper-text`, {
100
- [`${prefix}--form__helper-text--disabled`]: disabled
95
+ [`${prefix}--form__helper-text--disabled`]: normalizedProps.disabled
101
96
  });
102
- const helperId = !helperText ? undefined : `select-helper-text-${selectInstanceId}`;
103
97
  const helper = helperText ? /*#__PURE__*/React.createElement(Text, {
104
98
  as: "div",
105
- id: helperId,
99
+ id: normalizedProps.helperId,
106
100
  className: helperTextClasses
107
101
  }, helperText) : null;
108
102
  const ariaProps = {};
109
- if (invalid) {
110
- ariaProps['aria-describedby'] = errorId;
103
+ if (normalizedProps.invalid) {
104
+ ariaProps['aria-describedby'] = normalizedProps.invalidId;
111
105
  } else if (!inline && !isFluid) {
112
- ariaProps['aria-describedby'] = helper ? helperId : undefined;
106
+ ariaProps['aria-describedby'] = helper ? normalizedProps.helperId : undefined;
113
107
  }
114
108
  const handleFocus = evt => {
115
109
  setIsFocused(evt.type === 'focus' ? true : false);
@@ -146,8 +140,8 @@ const Select = /*#__PURE__*/React.forwardRef(({
146
140
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("select", _extends({}, other, ariaProps, {
147
141
  id: id,
148
142
  className: inputClasses,
149
- disabled: disabled || undefined,
150
- "aria-invalid": invalid || undefined,
143
+ disabled: normalizedProps.disabled || undefined,
144
+ "aria-invalid": normalizedProps.invalid || undefined,
151
145
  "aria-readonly": readOnly || undefined,
152
146
  title: title,
153
147
  onChange: composeEventHandlers([onChange, handleChange])
@@ -155,9 +149,9 @@ const Select = /*#__PURE__*/React.forwardRef(({
155
149
  ref: ref
156
150
  }), children), /*#__PURE__*/React.createElement(ChevronDown, {
157
151
  className: `${prefix}--select__arrow`
158
- }), invalid && /*#__PURE__*/React.createElement(WarningFilled, {
152
+ }), normalizedProps.invalid && /*#__PURE__*/React.createElement(WarningFilled, {
159
153
  className: `${prefix}--select__invalid-icon`
160
- }), !invalid && warn && /*#__PURE__*/React.createElement(WarningAltFilled, {
154
+ }), !normalizedProps.invalid && normalizedProps.warn && /*#__PURE__*/React.createElement(WarningAltFilled, {
161
155
  className: `${prefix}--select__invalid-icon ${prefix}--select__invalid-icon--warning`
162
156
  }));
163
157
  })();
@@ -173,10 +167,10 @@ const Select = /*#__PURE__*/React.forwardRef(({
173
167
  className: `${prefix}--select-input--inline__wrapper`
174
168
  }, /*#__PURE__*/React.createElement("div", {
175
169
  className: `${prefix}--select-input__wrapper`,
176
- "data-invalid": invalid || null
170
+ "data-invalid": normalizedProps.invalid || null
177
171
  }, input), error), !inline && /*#__PURE__*/React.createElement("div", {
178
172
  className: `${prefix}--select-input__wrapper`,
179
- "data-invalid": invalid || null,
173
+ "data-invalid": normalizedProps.invalid || null,
180
174
  onFocus: handleFocus,
181
175
  onBlur: handleFocus
182
176
  }, input, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
@@ -111,3 +111,4 @@ export declare namespace ToggletipActions {
111
111
  className: PropTypes.Requireable<string>;
112
112
  };
113
113
  }
114
+ export default Toggletip;
@@ -282,4 +282,4 @@ ToggletipActions.propTypes = {
282
282
  className: PropTypes.string
283
283
  };
284
284
 
285
- export { Toggletip, ToggletipActions, ToggletipButton, ToggletipContent, ToggletipLabel };
285
+ export { Toggletip, ToggletipActions, ToggletipButton, ToggletipContent, ToggletipLabel, Toggletip as default };
@@ -4,6 +4,7 @@
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 { DefinitionTooltip } from './DefinitionTooltip';
7
+ import { DefinitionTooltip, type DefinitionTooltipProps } from './DefinitionTooltip';
8
8
  import { Tooltip, type TooltipProps } from './Tooltip';
9
- export { DefinitionTooltip, Tooltip, type TooltipProps };
9
+ export { DefinitionTooltip, Tooltip, type DefinitionTooltipProps, type TooltipProps, };
10
+ export default Tooltip;
@@ -8,7 +8,6 @@
8
8
  import React, { useContext, useState, useRef, useCallback, useEffect, cloneElement } from 'react';
9
9
  import * as FeatureFlags from '@carbon/feature-flags';
10
10
  import ReactDOM from 'react-dom';
11
- import window from 'window-or-global';
12
11
  import { Tab } from './keyboard/keys.js';
13
12
  import { match } from './keyboard/match.js';
14
13
  import { selectorTabbable, selectorFocusable } from './keyboard/navigation.js';
@@ -109,14 +108,16 @@ const FloatingMenu = ({
109
108
  const menuSize = menuBody.getBoundingClientRect();
110
109
  const refPosition = triggerEl ? triggerEl.getBoundingClientRect() : undefined;
111
110
  const offsetValue = typeof menuOffset === 'function' ? menuOffset(menuBody, menuDirection, triggerEl, flipped) : menuOffset;
111
+ const scrollX = globalThis.scrollX ?? 0;
112
+ const scrollY = globalThis.scrollY ?? 0;
112
113
  if (updateOrientation) {
113
114
  updateOrientation({
114
115
  menuSize,
115
116
  refPosition,
116
117
  direction: menuDirection,
117
118
  offset: offsetValue,
118
- scrollX: window.pageXOffset,
119
- scrollY: window.pageYOffset,
119
+ scrollX,
120
+ scrollY,
120
121
  container: {
121
122
  rect: target().getBoundingClientRect(),
122
123
  position: getComputedStyle(target()).position
@@ -136,8 +137,8 @@ const FloatingMenu = ({
136
137
  },
137
138
  offset: offsetValue,
138
139
  direction: menuDirection,
139
- scrollX: window.pageXOffset,
140
- scrollY: window.pageYOffset,
140
+ scrollX,
141
+ scrollY,
141
142
  container: {
142
143
  rect: target().getBoundingClientRect(),
143
144
  position: getComputedStyle(target()).position
@@ -257,7 +258,8 @@ const FloatingMenu = ({
257
258
  startTrapNode: startSentinelRef.current,
258
259
  endTrapNode: endSentinelRef.current,
259
260
  currentActiveNode: relatedTarget,
260
- oldActiveNode: target
261
+ oldActiveNode: target,
262
+ prefix
261
263
  });
262
264
  }
263
265
  };
@@ -5,9 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import window from 'window-or-global';
9
-
10
- // mdn resize function
8
+ // Use `globalThis` for universal access to global object (browser, workers, Node).
9
+ const win = globalThis;
11
10
 
12
11
  /**
13
12
  * A callback function to be executed on `resize`.
@@ -25,7 +24,7 @@ const OptimizedResize = (() => {
25
24
  const handleResize = () => {
26
25
  if (!running) {
27
26
  running = true;
28
- window.requestAnimationFrame(runCallbacks);
27
+ win.requestAnimationFrame(runCallbacks);
29
28
  }
30
29
  };
31
30
  const addCallback = callback => {
@@ -38,7 +37,7 @@ const OptimizedResize = (() => {
38
37
  /** Adds a callback function to be executed on window `resize`. */
39
38
  add: callback => {
40
39
  if (!callbacks.length) {
41
- window.addEventListener('resize', handleResize);
40
+ win.addEventListener('resize', handleResize);
42
41
  }
43
42
  addCallback(callback);
44
43
  return {
@@ -14,12 +14,12 @@
14
14
  * @returns {boolean} Whether the node or one of its ancestors is in a floating
15
15
  * menu.
16
16
  */
17
- export declare const elementOrParentIsFloatingMenu: (node: Node, selectorsFloatingMenus?: string[]) => boolean;
17
+ export declare const elementOrParentIsFloatingMenu: (node: Node, selectorsFloatingMenus?: string[], prefix?: string) => boolean;
18
18
  /**
19
19
  * Ensures the focus is kept within the given container by implementing
20
20
  * "focus-wrap" behavior.
21
21
  */
22
- export declare const wrapFocus: ({ bodyNode, startTrapNode, endTrapNode, currentActiveNode, oldActiveNode, selectorsFloatingMenus, }: {
22
+ export declare const wrapFocus: ({ bodyNode, startTrapNode, endTrapNode, currentActiveNode, oldActiveNode, selectorsFloatingMenus, prefix, }: {
23
23
  /** The DOM node of the container. */
24
24
  bodyNode: HTMLElement | null;
25
25
  /** The start sentinel node for focus trapping. */
@@ -32,6 +32,8 @@ export declare const wrapFocus: ({ bodyNode, startTrapNode, endTrapNode, current
32
32
  oldActiveNode: HTMLElement;
33
33
  /** CSS selectors for floating menus. */
34
34
  selectorsFloatingMenus?: string[];
35
+ /** Classname prefix for Carbon selectors. */
36
+ prefix?: string;
35
37
  }) => void;
36
38
  /**
37
39
  * Ensures the focus is kept in the given container, implementing "focus-wrap"
@@ -30,9 +30,9 @@ const DOCUMENT_POSITION_BROAD_FOLLOWING = typeof Node !== 'undefined' ? Node.DOC
30
30
  * @returns {boolean} Whether the node or one of its ancestors is in a floating
31
31
  * menu.
32
32
  */
33
- const elementOrParentIsFloatingMenu = (node, selectorsFloatingMenus = []) => {
33
+ const elementOrParentIsFloatingMenu = (node, selectorsFloatingMenus = [], prefix = 'cds') => {
34
34
  if (node instanceof Element && typeof node.closest === 'function') {
35
- const allSelectorsFloatingMenus = ['.cds--overflow-menu-options', '.cds--tooltip', '.flatpickr-calendar', ...selectorsFloatingMenus];
35
+ const allSelectorsFloatingMenus = [`.${prefix}--overflow-menu-options`, `.${prefix}--tooltip`, '.flatpickr-calendar', ...selectorsFloatingMenus];
36
36
  return allSelectorsFloatingMenus.some(selector => !!node.closest(selector));
37
37
  }
38
38
  return false;
@@ -48,9 +48,10 @@ const wrapFocus = ({
48
48
  endTrapNode,
49
49
  currentActiveNode,
50
50
  oldActiveNode,
51
- selectorsFloatingMenus
51
+ selectorsFloatingMenus,
52
+ prefix = 'cds'
52
53
  }) => {
53
- if (bodyNode && currentActiveNode && oldActiveNode && !bodyNode.contains(currentActiveNode) && !elementOrParentIsFloatingMenu(currentActiveNode, selectorsFloatingMenus)) {
54
+ if (bodyNode && currentActiveNode && oldActiveNode && !bodyNode.contains(currentActiveNode) && !elementOrParentIsFloatingMenu(currentActiveNode, selectorsFloatingMenus, prefix)) {
54
55
  const comparisonResult = oldActiveNode.compareDocumentPosition(currentActiveNode);
55
56
  if (currentActiveNode === startTrapNode || comparisonResult & DOCUMENT_POSITION_BROAD_PRECEDING) {
56
57
  const tabbableElement = Array.from(bodyNode.querySelectorAll(selectorTabbable)).reverse().find(({
@@ -14,4 +14,4 @@ import type { SyntheticEvent } from 'react';
14
14
  * @param handlers - An array of event handler functions.
15
15
  * @returns A composite event handler.
16
16
  */
17
- export declare const composeEventHandlers: <E extends SyntheticEvent = SyntheticEvent>(handlers: (((event: E, ...args: any[]) => void) | undefined)[]) => (event: E, ...args: any[]) => void;
17
+ export declare const composeEventHandlers: <E extends SyntheticEvent = SyntheticEvent<Element, Event>>(handlers: (((event: E, ...args: any[]) => void) | undefined)[]) => (event: E, ...args: any[]) => void;
@@ -6,6 +6,11 @@
6
6
  */
7
7
  import React from 'react';
8
8
  export interface ButtonSetProps extends React.HTMLAttributes<HTMLDivElement> {
9
+ /**
10
+ * fluid: button set resize to the size of the container up to a maximum dependant on the
11
+ * number of buttons. Overrides `stacked` property.
12
+ */
13
+ fluid?: boolean;
9
14
  /**
10
15
  * Specify the button arrangement of the set (vertically stacked or
11
16
  * horizontal)
@@ -14,22 +14,81 @@ var React = require('react');
14
14
  var PropTypes = require('prop-types');
15
15
  var cx = require('classnames');
16
16
  var usePrefix = require('../../internal/usePrefix.js');
17
+ var useIsomorphicEffect = require('../../internal/useIsomorphicEffect.js');
17
18
 
19
+ const buttonOrder = kind => ({
20
+ ghost: 1,
21
+ 'danger--ghost': 2,
22
+ tertiary: 3,
23
+ danger: 5,
24
+ primary: 6
25
+ })[kind] ?? 4;
26
+ const getButtonKind = element => {
27
+ if (/*#__PURE__*/React.isValidElement(element) && element.props && typeof element.props === 'object') {
28
+ const props = element.props;
29
+ return props.kind ?? 'primary';
30
+ }
31
+ return 'primary';
32
+ };
18
33
  const ButtonSet = /*#__PURE__*/React.forwardRef((props, ref) => {
19
34
  const {
20
35
  children,
21
36
  className,
37
+ fluid,
22
38
  stacked,
23
39
  ...rest
24
40
  } = props;
25
41
  const prefix = usePrefix.usePrefix();
42
+ const fluidInnerRef = React.useRef(null);
43
+ const [isStacked, setIsStacked] = React.useState(false);
44
+ const [sortedChildren, setSortedChildren] = React.useState(React.Children.toArray(children));
45
+
46
+ /**
47
+ * Used to determine if the buttons are currently stacked
48
+ */
49
+ useIsomorphicEffect.default(() => {
50
+ const checkStacking = () => {
51
+ let newIsStacked = stacked || false;
52
+ if (fluidInnerRef && fluidInnerRef.current) {
53
+ const computedStyle = window.getComputedStyle(fluidInnerRef.current);
54
+ newIsStacked = computedStyle?.getPropertyValue?.('--flex-direction') === 'column';
55
+ }
56
+ return newIsStacked;
57
+ };
58
+
59
+ /* initial value not dependant on observer */
60
+ setIsStacked(checkStacking());
61
+ if (!fluidInnerRef.current) {
62
+ return;
63
+ }
64
+ const resizeObserver = new ResizeObserver(() => {
65
+ setIsStacked(checkStacking());
66
+ });
67
+ resizeObserver.observe(fluidInnerRef.current);
68
+ return () => resizeObserver.disconnect();
69
+ }, [isStacked, stacked]);
70
+ React.useEffect(() => {
71
+ const newSortedChildren = React.Children.toArray(children);
72
+ newSortedChildren.sort((a, b) => {
73
+ return (buttonOrder(getButtonKind(a)) - buttonOrder(getButtonKind(b))) * (isStacked ? -1 : 1);
74
+ });
75
+ setSortedChildren(newSortedChildren);
76
+
77
+ // adding sortedChildren to deps causes an infinite loop
78
+ }, [children, isStacked]);
26
79
  const buttonSetClasses = cx(className, `${prefix}--btn-set`, {
27
- [`${prefix}--btn-set--stacked`]: stacked
80
+ [`${prefix}--btn-set--stacked`]: isStacked,
81
+ [`${prefix}--btn-set--fluid`]: fluid
28
82
  });
29
83
  return /*#__PURE__*/React.createElement("div", _rollupPluginBabelHelpers.extends({}, rest, {
30
84
  className: buttonSetClasses,
31
85
  ref: ref
32
- }), children);
86
+ }), fluid ? /*#__PURE__*/React.createElement("div", {
87
+ ref: fluidInnerRef,
88
+ className: cx(`${prefix}--btn-set__fluid-inner`, {
89
+ [`${prefix}--btn-set__fluid-inner--auto-stack`]: true
90
+ })
91
+ }, sortedChildren) : children);
33
92
  });
34
93
  ButtonSet.displayName = 'ButtonSet';
35
94
  ButtonSet.propTypes = {
@@ -41,9 +100,14 @@ ButtonSet.propTypes = {
41
100
  * Specify an optional className to be added to your ButtonSet
42
101
  */
43
102
  className: PropTypes.string,
103
+ /**
104
+ * fluid: button set resize to the size of the container up to a maximum dependant on the
105
+ * number of buttons.
106
+ */
107
+ fluid: PropTypes.bool,
44
108
  /**
45
109
  * Specify the button arrangement of the set (vertically stacked or
46
- * horizontal)
110
+ * horizontal) - ignored when fluid is true
47
111
  */
48
112
  stacked: PropTypes.bool
49
113
  };
@@ -111,7 +111,7 @@ declare namespace CodeSnippet {
111
111
  /**
112
112
  * Specify how the trigger should align with the tooltip
113
113
  */
114
- align: PropTypes.Requireable<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top"> | PropTypes.Validator<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top">;
114
+ align: PropTypes.Requireable<string> | PropTypes.Validator<string>;
115
115
  /**
116
116
  * Specify a label to be read by screen readers on the containing textbox
117
117
  * node
@@ -210,7 +210,7 @@ const ComposedModalDialog = /*#__PURE__*/React.forwardRef(function ComposedModal
210
210
  // behavior by explicitly setting preventCloseOnClickOutside to false,
211
211
  // rather than just leaving it undefined.
212
212
  !isPassive && preventCloseOnClickOutside === false;
213
- if (shouldCloseOnOutsideClick && target instanceof Node && !wrapFocus.elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && innerModal.current && !innerModal.current.contains(target) && !innerModal.current.contains(mouseDownTarget)) {
213
+ if (shouldCloseOnOutsideClick && target instanceof Node && !wrapFocus.elementOrParentIsFloatingMenu(target, selectorsFloatingMenus, prefix) && innerModal.current && !innerModal.current.contains(target) && !innerModal.current.contains(mouseDownTarget)) {
214
214
  closeModal(evt);
215
215
  }
216
216
  }
@@ -234,7 +234,8 @@ const ComposedModalDialog = /*#__PURE__*/React.forwardRef(function ComposedModal
234
234
  endTrapNode: endSentinelNode,
235
235
  currentActiveNode,
236
236
  oldActiveNode,
237
- selectorsFloatingMenus: selectorsFloatingMenus?.filter(Boolean)
237
+ selectorsFloatingMenus: selectorsFloatingMenus?.filter(Boolean),
238
+ prefix
238
239
  });
239
240
  }
240
241
 
@@ -50,7 +50,7 @@ declare namespace Copy {
50
50
  /**
51
51
  * Specify how the trigger should align with the tooltip
52
52
  */
53
- align: PropTypes.Requireable<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top"> | PropTypes.Validator<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top">;
53
+ align: PropTypes.Requireable<string> | PropTypes.Validator<string>;
54
54
  /**
55
55
  * **Experimental**: Will attempt to automatically align the tooltip. Requires
56
56
  * React v17+
@@ -51,7 +51,7 @@ declare namespace CopyButton {
51
51
  /**
52
52
  * Specify how the trigger should align with the tooltip
53
53
  */
54
- align: PropTypes.Requireable<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top"> | PropTypes.Validator<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top">;
54
+ align: PropTypes.Requireable<string> | PropTypes.Validator<string>;
55
55
  /**
56
56
  * **Experimental**: Will attempt to automatically align the tooltip. Requires
57
57
  * React v17+
@@ -282,11 +282,12 @@ export declare const DataTable: {
282
282
  };
283
283
  TableCell: React.ForwardRefExoticComponent<import("./TableCell").TableCellProps & React.RefAttributes<HTMLTableCellElement>>;
284
284
  TableContainer: {
285
- ({ aiEnabled, className, children, title, description, stickyHeader, useStaticWidth, ...rest }: import("./TableContainer").TableContainerProps): import("react/jsx-runtime").JSX.Element;
285
+ ({ aiEnabled, className, children, decorator, title, description, stickyHeader, useStaticWidth, ...rest }: import("./TableContainer").TableContainerProps): import("react/jsx-runtime").JSX.Element;
286
286
  propTypes: {
287
287
  aiEnabled: PropTypes.Requireable<boolean>;
288
288
  children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
289
289
  className: PropTypes.Requireable<string>;
290
+ decorator: PropTypes.Requireable<PropTypes.ReactNodeLike>;
290
291
  description: PropTypes.Requireable<PropTypes.ReactNodeLike>;
291
292
  stickyHeader: PropTypes.Requireable<boolean>;
292
293
  title: PropTypes.Requireable<PropTypes.ReactNodeLike>;
@@ -5,12 +5,16 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import PropTypes from 'prop-types';
8
- import React, { type HTMLAttributes } from 'react';
8
+ import React, { ReactNode, type HTMLAttributes } from 'react';
9
9
  export interface TableContainerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
10
10
  /**
11
11
  * Specify if the entire table has AI generated contents
12
12
  */
13
13
  aiEnabled?: boolean;
14
+ /**
15
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TableContainer` component
16
+ */
17
+ decorator?: ReactNode;
14
18
  /**
15
19
  * Optional description text for the Table
16
20
  */
@@ -29,7 +33,7 @@ export interface TableContainerProps extends Omit<HTMLAttributes<HTMLDivElement>
29
33
  title?: React.ReactNode;
30
34
  }
31
35
  declare const TableContainer: {
32
- ({ aiEnabled, className, children, title, description, stickyHeader, useStaticWidth, ...rest }: TableContainerProps): import("react/jsx-runtime").JSX.Element;
36
+ ({ aiEnabled, className, children, decorator, title, description, stickyHeader, useStaticWidth, ...rest }: TableContainerProps): import("react/jsx-runtime").JSX.Element;
33
37
  propTypes: {
34
38
  /**
35
39
  * Specify if the entire table has AI generated contents
@@ -37,6 +41,10 @@ declare const TableContainer: {
37
41
  aiEnabled: PropTypes.Requireable<boolean>;
38
42
  children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
39
43
  className: PropTypes.Requireable<string>;
44
+ /**
45
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TableContainer` component
46
+ */
47
+ decorator: PropTypes.Requireable<PropTypes.ReactNodeLike>;
40
48
  /**
41
49
  * Optional description text for the Table
42
50
  */