@carbon/react 1.108.0-rc.0 → 1.109.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 (48) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +974 -974
  2. package/es/components/Button/ButtonBase.js +5 -5
  3. package/es/components/ComboBox/ComboBox.js +28 -1
  4. package/es/components/ComposedModal/ModalFooter.d.ts +5 -0
  5. package/es/components/ComposedModal/ModalFooter.js +3 -1
  6. package/es/components/DataTable/DataTable.d.ts +9 -3
  7. package/es/components/DataTable/DataTable.js +10 -8
  8. package/es/components/DataTable/TableToolbar.d.ts +8 -2
  9. package/es/components/DataTable/TableToolbar.js +21 -11
  10. package/es/components/DataTable/TableToolbarMenu.d.ts +5 -1
  11. package/es/components/DataTable/TableToolbarMenu.js +12 -2
  12. package/es/components/DataTable/TableToolbarSearch.d.ts +2 -6
  13. package/es/components/DataTable/TableToolbarSearch.js +5 -1
  14. package/es/components/Dialog/Dialog.d.ts +5 -0
  15. package/es/components/Dialog/Dialog.js +3 -1
  16. package/es/components/Menu/MenuItem.js +3 -2
  17. package/es/components/Modal/Modal.d.ts +5 -0
  18. package/es/components/Modal/Modal.js +17 -7
  19. package/es/components/OverflowMenuItem/OverflowMenuItem.js +3 -2
  20. package/es/components/Tabs/Tabs.d.ts +5 -1
  21. package/es/components/Tabs/Tabs.js +2 -1
  22. package/es/index.d.ts +1 -0
  23. package/es/index.js +2 -1
  24. package/es/internal/FloatingMenu.js +5 -3
  25. package/lib/components/Button/ButtonBase.js +5 -5
  26. package/lib/components/ComboBox/ComboBox.js +28 -1
  27. package/lib/components/ComposedModal/ModalFooter.d.ts +5 -0
  28. package/lib/components/ComposedModal/ModalFooter.js +3 -1
  29. package/lib/components/DataTable/DataTable.d.ts +9 -3
  30. package/lib/components/DataTable/DataTable.js +10 -8
  31. package/lib/components/DataTable/TableToolbar.d.ts +8 -2
  32. package/lib/components/DataTable/TableToolbar.js +20 -9
  33. package/lib/components/DataTable/TableToolbarMenu.d.ts +5 -1
  34. package/lib/components/DataTable/TableToolbarMenu.js +12 -2
  35. package/lib/components/DataTable/TableToolbarSearch.d.ts +2 -6
  36. package/lib/components/DataTable/TableToolbarSearch.js +5 -1
  37. package/lib/components/Dialog/Dialog.d.ts +5 -0
  38. package/lib/components/Dialog/Dialog.js +3 -1
  39. package/lib/components/Menu/MenuItem.js +3 -2
  40. package/lib/components/Modal/Modal.d.ts +5 -0
  41. package/lib/components/Modal/Modal.js +16 -6
  42. package/lib/components/OverflowMenuItem/OverflowMenuItem.js +3 -2
  43. package/lib/components/Tabs/Tabs.d.ts +5 -1
  44. package/lib/components/Tabs/Tabs.js +2 -1
  45. package/lib/index.d.ts +1 -0
  46. package/lib/index.js +2 -0
  47. package/lib/internal/FloatingMenu.js +5 -3
  48. package/package.json +9 -9
@@ -17,7 +17,7 @@ import { jsx } from "react/jsx-runtime";
17
17
  * This source code is licensed under the Apache-2.0 license found in the
18
18
  * LICENSE file in the root directory of this source tree.
19
19
  */
20
- const ButtonBase = React.forwardRef(function ButtonBase({ as, children, className, dangerDescription = "danger", disabled = false, hasIconOnly = false, href, iconDescription, isExpressive = false, isSelected, kind = "primary", onBlur, onClick, onFocus, onMouseEnter, onMouseLeave, renderIcon: ButtonImageElement, size, tabIndex, type = "button", ...rest }, ref) {
20
+ const ButtonBase = React.forwardRef(function ButtonBase({ as, children, className, dangerDescription = "", disabled = false, hasIconOnly = false, href, iconDescription, isExpressive = false, isSelected, kind = "primary", onBlur, onClick, onFocus, onMouseEnter, onMouseLeave, renderIcon: ButtonImageElement, size, tabIndex, type = "button", ...rest }, ref) {
21
21
  const prefix = usePrefix();
22
22
  const commonProps = {
23
23
  tabIndex,
@@ -43,23 +43,23 @@ const ButtonBase = React.forwardRef(function ButtonBase({ as, children, classNam
43
43
  className: `${prefix}--btn__icon`,
44
44
  "aria-hidden": "true"
45
45
  });
46
- const dangerButtonVariants = [
46
+ const hasDangerDescription = [
47
47
  "danger",
48
48
  "danger--tertiary",
49
49
  "danger--ghost"
50
- ];
50
+ ].includes(kind) && Boolean(dangerDescription);
51
51
  let component = "button";
52
52
  const assistiveId = useId("danger-description");
53
53
  const { "aria-pressed": ariaPressed, "aria-describedby": ariaDescribedBy } = rest;
54
54
  let otherProps = {
55
55
  disabled,
56
56
  type,
57
- "aria-describedby": dangerButtonVariants.includes(kind) ? assistiveId : ariaDescribedBy || void 0,
57
+ "aria-describedby": hasDangerDescription ? assistiveId : ariaDescribedBy || void 0,
58
58
  "aria-pressed": ariaPressed ?? (hasIconOnly && kind === "ghost" ? isSelected : void 0)
59
59
  };
60
60
  const anchorProps = { href };
61
61
  let assistiveText = null;
62
- if (dangerButtonVariants.includes(kind)) assistiveText = /* @__PURE__ */ jsx("span", {
62
+ if (hasDangerDescription) assistiveText = /* @__PURE__ */ jsx("span", {
63
63
  id: assistiveId,
64
64
  className: `${prefix}--visually-hidden`,
65
65
  children: dangerDescription
@@ -126,12 +126,21 @@ const ComboBox = forwardRef((props, ref) => {
126
126
  const [isFocused, setIsFocused] = useState(false);
127
127
  const prevInputValue = useRef(inputValue);
128
128
  const prevSelectedItemProp = useRef(selectedItemProp);
129
+ const isSyncingControlledSelectionRef = useRef(false);
130
+ const pendingControlledSelectionRef = useRef({
131
+ pending: false,
132
+ value: void 0
133
+ });
129
134
  useEffect(() => {
130
135
  isManualClearingRef.current = isClearing;
131
136
  if (isClearing) setIsClearing(false);
132
137
  }, [isClearing]);
133
138
  useEffect(() => {
134
139
  if (prevSelectedItemProp.current !== selectedItemProp) {
140
+ pendingControlledSelectionRef.current = {
141
+ pending: true,
142
+ value: selectedItemProp
143
+ };
135
144
  const currentInputValue = getInputValue({
136
145
  initialSelectedItem,
137
146
  itemToString,
@@ -346,11 +355,14 @@ const ComboBox = forwardRef((props, ref) => {
346
355
  isItemDisabled: isDisabledItem,
347
356
  ...downshiftProps,
348
357
  onStateChange: ({ type, selectedItem: newSelectedItem }) => {
358
+ if (isManualClearingRef.current || isSyncingControlledSelectionRef.current) {
359
+ isSyncingControlledSelectionRef.current = false;
360
+ return;
361
+ }
349
362
  downshiftProps?.onStateChange?.({
350
363
  type,
351
364
  selectedItem: newSelectedItem
352
365
  });
353
- if (isManualClearingRef.current) return;
354
366
  if ((type === ItemClick || type === FunctionSelectItem || type === InputKeyDownEnter || !allowCustomValue && type === InputBlur) && typeof newSelectedItem !== "undefined" && !isEqual(currentSelectedItem, newSelectedItem)) {
355
367
  if (items.some((item) => isEqual(item, newSelectedItem))) committedCustomValueRef.current = "";
356
368
  onChange({ selectedItem: newSelectedItem });
@@ -358,6 +370,21 @@ const ComboBox = forwardRef((props, ref) => {
358
370
  }
359
371
  });
360
372
  const currentSelectedItem = typeof selectedItemProp !== "undefined" ? selectedItemProp : selectedItem;
373
+ useEffect(() => {
374
+ if (pendingControlledSelectionRef.current.pending) {
375
+ const { value } = pendingControlledSelectionRef.current;
376
+ const nextSelectedItem = typeof value === "undefined" ? null : value;
377
+ pendingControlledSelectionRef.current.pending = false;
378
+ if (!isEqual(selectedItem, nextSelectedItem)) {
379
+ isSyncingControlledSelectionRef.current = true;
380
+ selectItem(nextSelectedItem);
381
+ }
382
+ }
383
+ }, [
384
+ selectedItem,
385
+ selectedItemProp,
386
+ selectItem
387
+ ]);
361
388
  useEffect(() => {
362
389
  if (downshiftActions) downshiftActions.current = {
363
390
  closeMenu,
@@ -36,6 +36,11 @@ export interface ModalFooterProps {
36
36
  * Note that this prop is not applied if you render primary/danger button by yourself
37
37
  */
38
38
  danger?: boolean;
39
+ /**
40
+ * Specify the message read by screen readers for the danger primary button.
41
+ * Defaults to an empty string; provide localized text to opt in.
42
+ */
43
+ dangerDescription?: string;
39
44
  /**
40
45
  * The `ref` callback for the primary button.
41
46
  */
@@ -61,7 +61,7 @@ SecondaryButtonSet.propTypes = {
61
61
  },
62
62
  secondaryClassName: PropTypes.string
63
63
  };
64
- const ModalFooter = React.forwardRef(function ModalFooter({ children, className: customClassName, closeModal = noopFn, danger, inputref, onRequestClose = noopFn, onRequestSubmit = noopFn, primaryButtonDisabled, primaryButtonText, primaryClassName, secondaryButtonText, secondaryButtons, secondaryClassName, loadingStatus = "inactive", loadingDescription, loadingIconDescription, onLoadingSuccess = noopFn, ...rest }, ref) {
64
+ const ModalFooter = React.forwardRef(function ModalFooter({ children, className: customClassName, closeModal = noopFn, danger, dangerDescription = "", inputref, onRequestClose = noopFn, onRequestSubmit = noopFn, primaryButtonDisabled, primaryButtonText, primaryClassName, secondaryButtonText, secondaryButtons, secondaryClassName, loadingStatus = "inactive", loadingDescription, loadingIconDescription, onLoadingSuccess = noopFn, ...rest }, ref) {
65
65
  const prefix = usePrefix();
66
66
  const footerClass = classNames(`${prefix}--modal-footer`, customClassName, Array.isArray(secondaryButtons) && secondaryButtons.length === 2 ? `${prefix}--modal-footer--three-button` : null);
67
67
  const primaryButtonClass = classNames(primaryClassName, loadingStatus !== "inactive" ? `${prefix}--btn--loading` : null);
@@ -85,6 +85,7 @@ const ModalFooter = React.forwardRef(function ModalFooter({ children, className:
85
85
  onClick: onRequestSubmit,
86
86
  className: primaryButtonClass,
87
87
  disabled: loadingActive || primaryButtonDisabled,
88
+ dangerDescription,
88
89
  kind: danger ? "danger" : "primary",
89
90
  ref: inputref,
90
91
  children: loadingStatus === "inactive" ? primaryButtonText : /* @__PURE__ */ jsx(InlineLoading_default, {
@@ -104,6 +105,7 @@ ModalFooter.propTypes = {
104
105
  className: PropTypes.string,
105
106
  closeModal: PropTypes.func,
106
107
  danger: PropTypes.bool,
108
+ dangerDescription: PropTypes.string,
107
109
  inputref: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]),
108
110
  loadingDescription: PropTypes.string,
109
111
  loadingIconDescription: PropTypes.string,
@@ -69,6 +69,7 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
69
69
  selectedRows: (DataTableRow<ColTypes> & RowType)[];
70
70
  getHeaderProps: (options: {
71
71
  header: DataTableHeader;
72
+ id?: string;
72
73
  isSortable?: boolean;
73
74
  onClick?: (event: MouseEvent<HTMLButtonElement>, sortState: {
74
75
  sortHeaderKey: string;
@@ -76,6 +77,7 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
76
77
  }) => void;
77
78
  [key: string]: unknown;
78
79
  }) => {
80
+ id: string;
79
81
  isSortable: boolean | undefined;
80
82
  isSortHeader: boolean;
81
83
  key: string;
@@ -135,7 +137,7 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
135
137
  getToolbarProps: (options?: {
136
138
  [key: string]: unknown;
137
139
  }) => {
138
- size: 'sm' | undefined;
140
+ size: 'xs' | 'sm' | undefined;
139
141
  [key: string]: unknown;
140
142
  };
141
143
  getBatchActionProps: (options?: {
@@ -163,9 +165,12 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
163
165
  };
164
166
  getCellProps: (options: {
165
167
  cell: DataTableCell<ColTypes>;
168
+ headers?: string;
169
+ [key: string]: unknown;
166
170
  }) => {
167
171
  [key: string]: unknown;
168
172
  hasAILabelHeader?: boolean;
173
+ headers: string;
169
174
  key: string;
170
175
  };
171
176
  /**
@@ -384,7 +389,7 @@ export declare const DataTable: {
384
389
  TableToolbarAction: import("react").ForwardRefExoticComponent<import("./TableToolbarAction").TableToolbarActionProps & import("react").RefAttributes<HTMLDivElement>>;
385
390
  TableToolbarContent: (props: import("react").HTMLAttributes<"div">) => ReactElement;
386
391
  TableToolbarSearch: {
387
- ({ className, searchContainerClass, onChange: onChangeProp, onClear, translateWithId: t, placeholder, labelText, expanded: expandedProp, defaultExpanded, defaultValue, disabled, onExpand, persistent, id, onBlur, onFocus, size, tabIndex, ...rest }: import("./TableToolbarSearch").TableToolbarSearchProps): import("react/jsx-runtime").JSX.Element;
392
+ ({ className, searchContainerClass, onChange: onChangeProp, onClear, translateWithId: t, placeholder, labelText, expanded: expandedProp, defaultExpanded, defaultValue, disabled, onExpand, persistent, id, onBlur, onFocus, size: sizeProp, tabIndex, ...rest }: import("./TableToolbarSearch").TableToolbarSearchProps): import("react/jsx-runtime").JSX.Element;
388
393
  propTypes: {
389
394
  children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
390
395
  className: PropTypes.Requireable<string>;
@@ -408,13 +413,14 @@ export declare const DataTable: {
408
413
  };
409
414
  };
410
415
  TableToolbarMenu: {
411
- ({ className, renderIcon, iconDescription, children, menuOptionsClass, ...rest }: import("./TableToolbarMenu").TableToolbarMenuProps): import("react/jsx-runtime").JSX.Element;
416
+ ({ className, renderIcon, iconDescription, children, menuOptionsClass, size: sizeProp, ...rest }: import("./TableToolbarMenu").TableToolbarMenuProps): import("react/jsx-runtime").JSX.Element;
412
417
  propTypes: {
413
418
  children: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
414
419
  className: PropTypes.Requireable<string>;
415
420
  iconDescription: PropTypes.Requireable<string>;
416
421
  menuOptionsClass: PropTypes.Requireable<string>;
417
422
  renderIcon: PropTypes.Requireable<object>;
423
+ size: PropTypes.Requireable<string>;
418
424
  };
419
425
  };
420
426
  propTypes: {
@@ -103,8 +103,10 @@ const DataTable = (props) => {
103
103
  const getHeaderProps = ({ header, onClick, isSortable: headerIsSortable, ...rest }) => {
104
104
  const { sortDirection, sortHeaderKey } = state;
105
105
  const { key, slug, decorator } = header;
106
+ const id = typeof rest.id === "string" && rest.id.length ? rest.id : getHeaderId(key);
106
107
  return {
107
108
  ...rest,
109
+ id,
108
110
  key,
109
111
  sortDirection,
110
112
  isSortable: headerIsSortable ?? header.isSortable ?? isSortable,
@@ -204,13 +206,10 @@ const DataTable = (props) => {
204
206
  onSelect: composeEventHandlers([handleSelectAll, onClick])
205
207
  };
206
208
  };
207
- const getToolbarProps = (props) => {
208
- const isSmall = size === "xs" || size === "sm";
209
- return {
210
- ...props,
211
- size: isSmall ? "sm" : void 0
212
- };
213
- };
209
+ const getToolbarProps = (props) => ({
210
+ ...props,
211
+ size: size === "xs" || size === "sm" ? size : void 0
212
+ });
214
213
  const getBatchActionProps = (props) => {
215
214
  const { shouldShowBatchActions } = state;
216
215
  const selectedRowCount = selectedRows.length;
@@ -240,10 +239,12 @@ const DataTable = (props) => {
240
239
  useStaticWidth
241
240
  };
242
241
  };
243
- const getCellProps = ({ cell: { hasAILabelHeader, id }, ...rest }) => {
242
+ const getCellProps = ({ cell: { hasAILabelHeader, id, info: { header } }, headers: customHeaders, ...rest }) => {
243
+ const headers = typeof customHeaders === "string" && customHeaders.length ? customHeaders : getHeaderId(header);
244
244
  return {
245
245
  ...rest,
246
246
  hasAILabelHeader,
247
+ headers,
247
248
  key: id
248
249
  };
249
250
  };
@@ -265,6 +266,7 @@ const DataTable = (props) => {
265
266
  * Generates a prefix for table related IDs.
266
267
  */
267
268
  const getTablePrefix = () => `data-table-${instanceId}`;
269
+ const getHeaderId = (headerKey) => `${getTablePrefix()}__header-${headerKey}`;
268
270
  /**
269
271
  * Generates a new `rowsById` object with updated selection state.
270
272
  */
@@ -1,11 +1,17 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2025
2
+ * Copyright IBM Corp. 2016, 2026
3
3
  *
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
7
  import PropTypes from 'prop-types';
8
8
  import React from 'react';
9
+ export declare const TableToolbarContext: React.Context<{
10
+ size?: "xs" | "sm" | "lg";
11
+ }>;
12
+ export declare const useTableToolbar: () => {
13
+ size?: "xs" | "sm" | "lg";
14
+ };
9
15
  export interface TableToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
10
16
  /**
11
17
  * Specify a label to be read by screen readers on the container node
@@ -24,7 +30,7 @@ export interface TableToolbarProps extends React.HTMLAttributes<HTMLDivElement>
24
30
  /**
25
31
  * `lg` Change the row height of table
26
32
  */
27
- size?: 'sm' | 'lg';
33
+ size?: 'xs' | 'sm' | 'lg';
28
34
  }
29
35
  declare const TableToolbar: {
30
36
  ({ ["aria-label"]: ariaLabel, ariaLabel: deprecatedAriaLabel, children, size, ...rest }: TableToolbarProps): import("react/jsx-runtime").JSX.Element;
@@ -8,35 +8,45 @@
8
8
  import { usePrefix } from "../../internal/usePrefix.js";
9
9
  import { deprecate } from "../../prop-types/deprecate.js";
10
10
  import classNames from "classnames";
11
- import "react";
11
+ import { createContext, useContext } from "react";
12
12
  import PropTypes from "prop-types";
13
13
  import { jsx } from "react/jsx-runtime";
14
14
  //#region src/components/DataTable/TableToolbar.tsx
15
15
  /**
16
- * Copyright IBM Corp. 2016, 2025
16
+ * Copyright IBM Corp. 2016, 2026
17
17
  *
18
18
  * This source code is licensed under the Apache-2.0 license found in the
19
19
  * LICENSE file in the root directory of this source tree.
20
20
  */
21
+ const TableToolbarContext = createContext({});
22
+ const useTableToolbar = () => useContext(TableToolbarContext);
21
23
  const TableToolbar = ({ ["aria-label"]: ariaLabel = "data table toolbar", ariaLabel: deprecatedAriaLabel, children, size, ...rest }) => {
22
24
  const prefix = usePrefix();
23
25
  const className = classNames({
24
26
  [`${prefix}--table-toolbar`]: true,
25
- [`${prefix}--table-toolbar--${size}`]: size
27
+ [`${prefix}--table-toolbar--${size}`]: size,
28
+ [`${prefix}--layout--size-${size}`]: size
26
29
  });
27
- return /* @__PURE__ */ jsx("section", {
28
- role: "group",
29
- "aria-label": deprecatedAriaLabel || ariaLabel,
30
- ...rest,
31
- className,
32
- children
30
+ return /* @__PURE__ */ jsx(TableToolbarContext.Provider, {
31
+ value: { size },
32
+ children: /* @__PURE__ */ jsx("section", {
33
+ role: "group",
34
+ "aria-label": deprecatedAriaLabel || ariaLabel,
35
+ ...rest,
36
+ className,
37
+ children
38
+ })
33
39
  });
34
40
  };
35
41
  TableToolbar.propTypes = {
36
42
  ["aria-label"]: PropTypes.string,
37
43
  ariaLabel: deprecate(PropTypes.string, "This prop syntax has been deprecated. Please use the new `aria-label`."),
38
44
  children: PropTypes.node,
39
- size: PropTypes.oneOf(["sm", "lg"])
45
+ size: PropTypes.oneOf([
46
+ "xs",
47
+ "sm",
48
+ "lg"
49
+ ])
40
50
  };
41
51
  //#endregion
42
- export { TableToolbar as default };
52
+ export { TableToolbar as default, useTableToolbar };
@@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
8
8
  import { OverflowMenuProps } from '../OverflowMenu';
9
9
  export type TableToolbarMenuProps = OverflowMenuProps;
10
10
  declare const TableToolbarMenu: {
11
- ({ className, renderIcon, iconDescription, children, menuOptionsClass, ...rest }: TableToolbarMenuProps): import("react/jsx-runtime").JSX.Element;
11
+ ({ className, renderIcon, iconDescription, children, menuOptionsClass, size: sizeProp, ...rest }: TableToolbarMenuProps): import("react/jsx-runtime").JSX.Element;
12
12
  propTypes: {
13
13
  children: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
14
14
  /**
@@ -27,6 +27,10 @@ declare const TableToolbarMenu: {
27
27
  * A component used to render an icon.
28
28
  */
29
29
  renderIcon: PropTypes.Requireable<object>;
30
+ /**
31
+ * Specify the size of the ToolbarMenu.
32
+ */
33
+ size: PropTypes.Requireable<string>;
30
34
  };
31
35
  };
32
36
  export default TableToolbarMenu;
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import { usePrefix } from "../../internal/usePrefix.js";
9
+ import { useTableToolbar } from "./TableToolbar.js";
9
10
  import OverflowMenu from "../OverflowMenu/index.js";
10
11
  import classNames from "classnames";
11
12
  import "react";
@@ -20,13 +21,16 @@ import { Settings } from "@carbon/icons-react";
20
21
  * LICENSE file in the root directory of this source tree.
21
22
  */
22
23
  const defaultIconDescription = "Settings";
23
- const TableToolbarMenu = ({ className, renderIcon = Settings, iconDescription = defaultIconDescription, children, menuOptionsClass, ...rest }) => {
24
+ const TableToolbarMenu = ({ className, renderIcon = Settings, iconDescription = defaultIconDescription, children, menuOptionsClass, size: sizeProp, ...rest }) => {
25
+ const toolbarContext = useTableToolbar();
26
+ const size = sizeProp ?? toolbarContext.size;
24
27
  const prefix = usePrefix();
25
28
  return /* @__PURE__ */ jsx(OverflowMenu, {
26
29
  renderIcon,
27
30
  className: classNames(className, `${prefix}--toolbar-action ${prefix}--overflow-menu`),
28
31
  iconDescription,
29
32
  menuOptionsClass: classNames(menuOptionsClass, `${prefix}--toolbar-action__menu`),
33
+ size,
30
34
  flipped: true,
31
35
  ...rest,
32
36
  children
@@ -37,7 +41,13 @@ TableToolbarMenu.propTypes = {
37
41
  className: PropTypes.string,
38
42
  iconDescription: PropTypes.string,
39
43
  menuOptionsClass: PropTypes.string,
40
- renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
44
+ renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
45
+ size: PropTypes.oneOf([
46
+ "xs",
47
+ "sm",
48
+ "md",
49
+ "lg"
50
+ ])
41
51
  };
42
52
  //#endregion
43
53
  export { TableToolbarMenu as default };
@@ -13,7 +13,7 @@ declare const translationIds: {
13
13
  readonly 'carbon.table.toolbar.search.placeholder': "carbon.table.toolbar.search.placeholder";
14
14
  };
15
15
  type TranslationKey = keyof typeof translationIds;
16
- type ExcludedInheritedProps = 'defaultValue' | 'labelText' | 'onBlur' | 'onChange' | 'onExpand' | 'onFocus' | 'tabIndex' | 'size';
16
+ type ExcludedInheritedProps = 'defaultValue' | 'labelText' | 'onBlur' | 'onChange' | 'onExpand' | 'onFocus' | 'tabIndex';
17
17
  export type TableToolbarSearchHandleExpand = (event: FocusEvent<HTMLInputElement>, newValue?: boolean) => void;
18
18
  /**
19
19
  * @deprecated Passing `''` as the event sentinel is legacy compatibility
@@ -69,14 +69,10 @@ export interface TableToolbarSearchProps extends Omit<SearchProps, ExcludedInher
69
69
  * Provide an optional className for the overall container of the Search
70
70
  */
71
71
  searchContainerClass?: string;
72
- /**
73
- * Specify the size of the Search
74
- */
75
- size?: 'sm' | 'md' | 'lg';
76
72
  tabIndex?: number | string;
77
73
  }
78
74
  declare const TableToolbarSearch: {
79
- ({ className, searchContainerClass, onChange: onChangeProp, onClear, translateWithId: t, placeholder, labelText, expanded: expandedProp, defaultExpanded, defaultValue, disabled, onExpand, persistent, id, onBlur, onFocus, size, tabIndex, ...rest }: TableToolbarSearchProps): import("react/jsx-runtime").JSX.Element;
75
+ ({ className, searchContainerClass, onChange: onChangeProp, onClear, translateWithId: t, placeholder, labelText, expanded: expandedProp, defaultExpanded, defaultValue, disabled, onExpand, persistent, id, onBlur, onFocus, size: sizeProp, tabIndex, ...rest }: TableToolbarSearchProps): import("react/jsx-runtime").JSX.Element;
80
76
  propTypes: {
81
77
  children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
82
78
  /**
@@ -9,6 +9,7 @@ import { usePrefix } from "../../internal/usePrefix.js";
9
9
  import { useId } from "../../internal/useId.js";
10
10
  import { noopFn } from "../../internal/noopFn.js";
11
11
  import Search_default from "../Search/index.js";
12
+ import { useTableToolbar } from "./TableToolbar.js";
12
13
  import classNames from "classnames";
13
14
  import { useEffect, useRef, useState } from "react";
14
15
  import PropTypes from "prop-types";
@@ -31,7 +32,9 @@ const defaultTranslations = {
31
32
  const defaultTranslateWithId = (messageId) => {
32
33
  return defaultTranslations[messageId];
33
34
  };
34
- const TableToolbarSearch = ({ className, searchContainerClass, onChange: onChangeProp, onClear = noopFn, translateWithId: t = defaultTranslateWithId, placeholder, labelText, expanded: expandedProp, defaultExpanded, defaultValue, disabled, onExpand, persistent = false, id, onBlur, onFocus, size = "lg", tabIndex = "0", ...rest }) => {
35
+ const TableToolbarSearch = ({ className, searchContainerClass, onChange: onChangeProp, onClear = noopFn, translateWithId: t = defaultTranslateWithId, placeholder, labelText, expanded: expandedProp, defaultExpanded, defaultValue, disabled, onExpand, persistent = false, id, onBlur, onFocus, size: sizeProp, tabIndex = "0", ...rest }) => {
36
+ const toolbarContext = useTableToolbar();
37
+ const size = sizeProp ?? toolbarContext.size;
35
38
  const { current: controlled } = useRef(expandedProp !== void 0);
36
39
  const [expandedState, setExpandedState] = useState(Boolean(defaultExpanded || defaultValue));
37
40
  const expanded = controlled ? expandedProp : expandedState;
@@ -100,6 +103,7 @@ TableToolbarSearch.propTypes = {
100
103
  placeholder: PropTypes.string,
101
104
  searchContainerClass: PropTypes.string,
102
105
  size: PropTypes.oneOf([
106
+ "xs",
103
107
  "sm",
104
108
  "md",
105
109
  "lg"
@@ -232,6 +232,11 @@ interface DialogFooterProps extends HTMLAttributes<HTMLDivElement> {
232
232
  * Specify whether the Dialog is for dangerous actions
233
233
  */
234
234
  danger?: boolean;
235
+ /**
236
+ * Specify the message read by screen readers for the danger primary button.
237
+ * Defaults to an empty string; provide localized text to opt in.
238
+ */
239
+ dangerDescription?: string;
235
240
  /**
236
241
  * Specify loading status
237
242
  */
@@ -248,7 +248,7 @@ DialogBody.propTypes = {
248
248
  className: PropTypes.string,
249
249
  hasScrollingContent: PropTypes.bool
250
250
  };
251
- const DialogFooter = React.forwardRef(({ children, className, onRequestClose = noopFn, onSecondarySubmit, onRequestSubmit = noopFn, primaryButtonText = "Save", primaryButtonDisabled = false, secondaryButtonText = "Cancel", secondaryButtons, loadingStatus = "inactive", loadingDescription, loadingIconDescription, onLoadingSuccess = noopFn, danger = false, ...rest }, ref) => {
251
+ const DialogFooter = React.forwardRef(({ children, className, onRequestClose = noopFn, onSecondarySubmit, onRequestSubmit = noopFn, primaryButtonText = "Save", primaryButtonDisabled = false, secondaryButtonText = "Cancel", secondaryButtons, loadingStatus = "inactive", loadingDescription, loadingIconDescription, onLoadingSuccess = noopFn, danger = false, dangerDescription = "", ...rest }, ref) => {
252
252
  const prefix = usePrefix();
253
253
  const button = useRef(null);
254
254
  const { isOpen } = useContext(DialogContext);
@@ -296,6 +296,7 @@ const DialogFooter = React.forwardRef(({ children, className, onRequestClose = n
296
296
  }), /* @__PURE__ */ jsx(Button_default, {
297
297
  className: primaryButtonClass,
298
298
  kind: danger ? "danger" : "primary",
299
+ dangerDescription,
299
300
  disabled: loadingActive || primaryButtonDisabled,
300
301
  onClick: onRequestSubmit,
301
302
  ref: button,
@@ -333,6 +334,7 @@ DialogFooter.propTypes = {
333
334
  return null;
334
335
  },
335
336
  danger: PropTypes.bool,
337
+ dangerDescription: PropTypes.string,
336
338
  loadingStatus: PropTypes.oneOf([
337
339
  "inactive",
338
340
  "active",
@@ -29,7 +29,7 @@ import { FloatingFocusManager, autoUpdate, flip, offset, safePolygon, useFloatin
29
29
  * This source code is licensed under the Apache-2.0 license found in the
30
30
  * LICENSE file in the root directory of this source tree.
31
31
  */
32
- const MenuItem = forwardRef(function MenuItem({ children, className, dangerDescription = "danger", disabled, kind = "default", label, onClick, renderIcon: IconElement, shortcut, ...rest }, forwardRef) {
32
+ const MenuItem = forwardRef(function MenuItem({ children, className, dangerDescription = "", disabled, kind = "default", label, onClick, renderIcon: IconElement, shortcut, ...rest }, forwardRef) {
33
33
  const [submenuOpen, setSubmenuOpen] = useState(false);
34
34
  const [rtl, setRtl] = useState(false);
35
35
  const { refs, floatingStyles, context: floatingContext } = useFloating({
@@ -67,6 +67,7 @@ const MenuItem = forwardRef(function MenuItem({ children, className, dangerDescr
67
67
  const hasChildren = React.Children.toArray(children).length > 0;
68
68
  const isDisabled = disabled && !hasChildren;
69
69
  const isDanger = kind === "danger" && !hasChildren;
70
+ const hasDangerDescription = isDanger && Boolean(dangerDescription);
70
71
  function registerItem() {
71
72
  context.dispatch({
72
73
  type: "registerItem",
@@ -169,7 +170,7 @@ const MenuItem = forwardRef(function MenuItem({ children, className, dangerDescr
169
170
  className: `${prefix}--menu-item__label`,
170
171
  children: label
171
172
  }),
172
- isDanger && /* @__PURE__ */ jsx("span", {
173
+ hasDangerDescription && /* @__PURE__ */ jsx("span", {
173
174
  id: assistiveId,
174
175
  className: `${prefix}--visually-hidden`,
175
176
  children: dangerDescription
@@ -38,6 +38,11 @@ export interface ModalProps extends HTMLAttributes<HTMLDivElement> {
38
38
  * Specify whether the Modal is for dangerous actions
39
39
  */
40
40
  danger?: boolean;
41
+ /**
42
+ * Specify the message read by screen readers for the danger primary button.
43
+ * Defaults to an empty string; provide localized text to opt in.
44
+ */
45
+ dangerDescription?: string;
41
46
  /**
42
47
  * **Experimental**: Provide a decorator component to be rendered inside the `Modal` component
43
48
  */
@@ -33,7 +33,7 @@ import { isTopmostVisibleModal } from "./isTopmostVisibleModal.js";
33
33
  import { usePreviousValue } from "../../internal/usePreviousValue.js";
34
34
  import { ModalPresence, ModalPresenceContext, useExclusiveModalPresenceContext } from "./ModalPresence.js";
35
35
  import classNames from "classnames";
36
- import React, { cloneElement, useCallback, useContext, useEffect, useRef } from "react";
36
+ import React, { cloneElement, useCallback, useContext, useEffect, useRef, useState } from "react";
37
37
  import PropTypes from "prop-types";
38
38
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
39
39
  import { Close } from "@carbon/icons-react";
@@ -73,7 +73,7 @@ const Modal = React.forwardRef(function Modal({ open, ...props }, ref) {
73
73
  ...props
74
74
  });
75
75
  });
76
- const ModalDialog = React.forwardRef(function ModalDialog({ "aria-label": ariaLabelProp, children, className, decorator, modalHeading = "", modalLabel = "", modalAriaLabel, passiveModal = false, secondaryButtonText, primaryButtonText, open: externalOpen, onRequestClose = noopFn, onRequestSubmit = noopFn, onSecondarySubmit, primaryButtonDisabled = false, danger, alert, secondaryButtons, selectorPrimaryFocus = "[data-modal-primary-focus]", selectorsFloatingMenus, shouldSubmitOnEnter, size, hasScrollingContent = false, closeButtonLabel = "Close", preventCloseOnClickOutside, isFullWidth, launcherButtonRef, loadingStatus = "inactive", loadingDescription, loadingIconDescription, onLoadingSuccess = noopFn, slug, ...rest }, ref) {
76
+ const ModalDialog = React.forwardRef(function ModalDialog({ "aria-label": ariaLabelProp, children, className, decorator, modalHeading = "", modalLabel = "", modalAriaLabel, passiveModal = false, secondaryButtonText, primaryButtonText, open: externalOpen, onRequestClose = noopFn, onRequestSubmit = noopFn, onSecondarySubmit, primaryButtonDisabled = false, danger, dangerDescription = "", alert, secondaryButtons, selectorPrimaryFocus = "[data-modal-primary-focus]", selectorsFloatingMenus, shouldSubmitOnEnter, size, hasScrollingContent = false, closeButtonLabel = "Close", preventCloseOnClickOutside, isFullWidth, launcherButtonRef, loadingStatus = "inactive", loadingDescription, loadingIconDescription, onLoadingSuccess = noopFn, slug, ...rest }, ref) {
77
77
  const prefix = usePrefix();
78
78
  const button = useRef(null);
79
79
  const secondaryButton = useRef(null);
@@ -167,11 +167,18 @@ const ModalDialog = React.forwardRef(function ModalDialog({ "aria-label": ariaLa
167
167
  [`${prefix}--modal-container--${size}`]: size,
168
168
  [`${prefix}--modal-container--full-width`]: isFullWidth
169
169
  });
170
- /**
171
- * isScrollable is implicitly dependent on height, when height gets updated
172
- * via `useResizeObserver`, clientHeight and scrollHeight get updated too
173
- */
174
- const isScrollable = !!contentRef.current && contentRef?.current?.scrollHeight > contentRef?.current?.clientHeight;
170
+ const currentScrollHeight = contentRef.current?.scrollHeight || 0;
171
+ const currentClientHeight = contentRef.current?.clientHeight || 0;
172
+ const [isScrollable, setIsScrollable] = useState(currentScrollHeight > currentClientHeight);
173
+ useEffect(() => {
174
+ if (!contentRef.current) {
175
+ setIsScrollable(false);
176
+ return;
177
+ }
178
+ const diff = contentRef.current.scrollHeight - contentRef.current.clientHeight;
179
+ if (diff > 5) setIsScrollable(true);
180
+ else if (diff < -5) setIsScrollable(false);
181
+ }, [currentScrollHeight, currentClientHeight]);
175
182
  const contentClasses = classNames(`${prefix}--modal-content`, {
176
183
  [`${prefix}--modal-scroll-content`]: hasScrollingContent || isScrollable,
177
184
  [`${prefix}--modal-scroll-content--no-fade`]: height <= 300
@@ -362,6 +369,7 @@ const ModalDialog = React.forwardRef(function ModalDialog({ "aria-label": ariaLa
362
369
  }), /* @__PURE__ */ jsx(Button_default, {
363
370
  className: primaryButtonClass,
364
371
  kind: danger ? "danger" : "primary",
372
+ dangerDescription,
365
373
  disabled: loadingActive || primaryButtonDisabled,
366
374
  onClick: onRequestSubmit,
367
375
  ref: button,
@@ -438,6 +446,7 @@ const ModalDialog = React.forwardRef(function ModalDialog({ "aria-label": ariaLa
438
446
  }), /* @__PURE__ */ jsx(Button_default, {
439
447
  className: primaryButtonClass,
440
448
  kind: danger ? "danger" : "primary",
449
+ dangerDescription,
441
450
  disabled: loadingActive || primaryButtonDisabled,
442
451
  onClick: onRequestSubmit,
443
452
  ref: button,
@@ -480,6 +489,7 @@ Modal.propTypes = {
480
489
  className: PropTypes.string,
481
490
  closeButtonLabel: PropTypes.string,
482
491
  danger: PropTypes.bool,
492
+ dangerDescription: PropTypes.string,
483
493
  decorator: PropTypes.node,
484
494
  hasScrollingContent: PropTypes.bool,
485
495
  id: PropTypes.string,
@@ -23,7 +23,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
23
23
  * LICENSE file in the root directory of this source tree.
24
24
  */
25
25
  const OverflowMenuItem = forwardRef((props, ref) => {
26
- const { className, closeMenu, dangerDescription = "danger", disabled = false, handleOverflowMenuItemFocus, hasDivider = false, href, isDelete = false, index, itemText = "Provide itemText", onClick = () => {}, onKeyDown = () => {}, requireTitle, title, wrapperClassName, ...rest } = props;
26
+ const { className, closeMenu, dangerDescription = "", disabled = false, handleOverflowMenuItemFocus, hasDivider = false, href, isDelete = false, index, itemText = "Provide itemText", onClick = () => {}, onKeyDown = () => {}, requireTitle, title, wrapperClassName, ...rest } = props;
27
27
  const prefix = usePrefix();
28
28
  function setTabFocus(evt) {
29
29
  if (match(evt, ArrowDown)) handleOverflowMenuItemFocus?.({
@@ -47,13 +47,14 @@ const OverflowMenuItem = forwardRef((props, ref) => {
47
47
  [`${prefix}--overflow-menu-options__option--disabled`]: disabled
48
48
  }, wrapperClassName);
49
49
  const TagToUse = href ? "a" : "button";
50
+ const hasDangerDescription = isDelete && Boolean(dangerDescription);
50
51
  const assistiveId = useId("danger-description");
51
52
  const OverflowMenuItemContent = (() => {
52
53
  if (typeof itemText !== "string") return itemText;
53
54
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
54
55
  className: `${prefix}--overflow-menu-options__option-content`,
55
56
  children: itemText
56
- }), isDelete && /* @__PURE__ */ jsx("span", {
57
+ }), hasDangerDescription && /* @__PURE__ */ jsx("span", {
57
58
  id: assistiveId,
58
59
  className: `${prefix}--visually-hidden`,
59
60
  children: dangerDescription
@@ -192,8 +192,12 @@ export interface TabListProps extends DivAttributes {
192
192
  * on component rerender
193
193
  */
194
194
  scrollIntoView?: boolean;
195
+ /**
196
+ * Specify the size of the tabs.
197
+ */
198
+ size?: 'sm' | 'md' | 'lg';
195
199
  }
196
- declare function TabList({ activation, 'aria-label': label, children, className: customClassName, contained, fullWidth, iconSize, leftOverflowButtonProps, light, rightOverflowButtonProps, scrollDebounceWait, scrollIntoView, ...rest }: TabListProps): import("react/jsx-runtime").JSX.Element;
200
+ declare function TabList({ activation, 'aria-label': label, children, className: customClassName, contained, fullWidth, iconSize, leftOverflowButtonProps, light, rightOverflowButtonProps, scrollDebounceWait, scrollIntoView, size, ...rest }: TabListProps): import("react/jsx-runtime").JSX.Element;
197
201
  declare namespace TabList {
198
202
  var propTypes: {
199
203
  /**