@carbon/react 1.89.0-rc.1 → 1.90.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 (68) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +1152 -849
  2. package/README.md +2 -2
  3. package/es/components/ComposedModal/ComposedModal.js +16 -5
  4. package/es/components/DataTable/DataTable.d.ts +3 -8
  5. package/es/components/DataTable/DataTable.js +10 -3
  6. package/es/components/DataTable/TableExpandRow.d.ts +33 -5
  7. package/es/components/DataTable/TableExpandRow.js +4 -2
  8. package/es/components/DataTable/TableHeader.d.ts +1 -2
  9. package/es/components/DataTable/TableHeader.js +1 -2
  10. package/es/components/DataTable/TableRow.d.ts +3 -6
  11. package/es/components/DataTable/TableRow.js +35 -22
  12. package/es/components/DataTable/state/sorting.d.ts +55 -14
  13. package/es/components/DataTable/state/sorting.js +40 -50
  14. package/es/components/DataTable/tools/sorting.js +4 -0
  15. package/es/components/Dialog/Dialog.d.ts +245 -0
  16. package/es/components/Dialog/Dialog.js +593 -0
  17. package/es/components/Dialog/index.d.ts +3 -251
  18. package/es/components/Dialog/index.js +1 -609
  19. package/es/components/FeatureFlags/index.d.ts +3 -1
  20. package/es/components/FeatureFlags/index.js +5 -2
  21. package/es/components/FileUploader/FileUploader.d.ts +28 -6
  22. package/es/components/FileUploader/FileUploader.js +152 -38
  23. package/es/components/Menu/MenuItem.js +2 -1
  24. package/es/components/Modal/Modal.js +14 -8
  25. package/es/components/NumberInput/NumberInput.js +11 -6
  26. package/es/components/Popover/index.js +6 -2
  27. package/es/components/StructuredList/StructuredList.js +4 -2
  28. package/es/components/Tag/DismissibleTag.d.ts +5 -0
  29. package/es/components/Tag/DismissibleTag.js +6 -1
  30. package/es/components/Toggletip/index.js +20 -8
  31. package/es/components/TreeView/TreeNode.d.ts +28 -0
  32. package/es/components/TreeView/TreeNode.js +6 -5
  33. package/es/index.d.ts +2 -1
  34. package/es/index.js +2 -0
  35. package/lib/components/ComposedModal/ComposedModal.js +16 -5
  36. package/lib/components/DataTable/DataTable.d.ts +3 -8
  37. package/lib/components/DataTable/DataTable.js +10 -3
  38. package/lib/components/DataTable/TableExpandRow.d.ts +33 -5
  39. package/lib/components/DataTable/TableExpandRow.js +4 -2
  40. package/lib/components/DataTable/TableHeader.d.ts +1 -2
  41. package/lib/components/DataTable/TableHeader.js +1 -2
  42. package/lib/components/DataTable/TableRow.d.ts +3 -6
  43. package/lib/components/DataTable/TableRow.js +34 -21
  44. package/lib/components/DataTable/state/sorting.d.ts +55 -14
  45. package/lib/components/DataTable/state/sorting.js +39 -50
  46. package/lib/components/DataTable/tools/sorting.js +4 -0
  47. package/lib/components/Dialog/Dialog.d.ts +245 -0
  48. package/lib/components/Dialog/Dialog.js +602 -0
  49. package/lib/components/Dialog/index.d.ts +3 -251
  50. package/lib/components/Dialog/index.js +9 -614
  51. package/lib/components/FeatureFlags/index.d.ts +3 -1
  52. package/lib/components/FeatureFlags/index.js +5 -2
  53. package/lib/components/FileUploader/FileUploader.d.ts +28 -6
  54. package/lib/components/FileUploader/FileUploader.js +151 -37
  55. package/lib/components/Menu/MenuItem.js +2 -1
  56. package/lib/components/Modal/Modal.js +21 -15
  57. package/lib/components/NumberInput/NumberInput.js +10 -5
  58. package/lib/components/Popover/index.js +6 -2
  59. package/lib/components/StructuredList/StructuredList.js +4 -2
  60. package/lib/components/Tag/DismissibleTag.d.ts +5 -0
  61. package/lib/components/Tag/DismissibleTag.js +6 -1
  62. package/lib/components/Toggletip/index.js +19 -7
  63. package/lib/components/TreeView/TreeNode.d.ts +28 -0
  64. package/lib/components/TreeView/TreeNode.js +6 -5
  65. package/lib/index.d.ts +2 -1
  66. package/lib/index.js +60 -58
  67. package/package.json +15 -15
  68. package/telemetry.yml +16 -0
@@ -12,6 +12,7 @@ import PropTypes from 'prop-types';
12
12
  import React, { useContext, useRef, useState, useEffect, useCallback } from 'react';
13
13
  import { ArrowLeft, ArrowRight, Enter, Space } from '../../internal/keyboard/keys.js';
14
14
  import { matches, match } from '../../internal/keyboard/match.js';
15
+ import { deprecate } from '../../prop-types/deprecate.js';
15
16
  import { useControllableState } from '../../internal/useControllableState.js';
16
17
  import { usePrefix } from '../../internal/usePrefix.js';
17
18
  import { useId } from '../../internal/useId.js';
@@ -413,7 +414,7 @@ TreeNode.propTypes = {
413
414
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
414
415
  * The ID of the active node in the tree
415
416
  */
416
- active: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
417
+ active: deprecate(PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 'The `active` prop for `TreeNode` is no longer needed and has ' + 'been deprecated. It will be removed in the next major release.'),
417
418
  /**
418
419
  * Specify the children of the TreeNode
419
420
  */
@@ -431,7 +432,7 @@ TreeNode.propTypes = {
431
432
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
432
433
  * TreeNode depth to determine spacing
433
434
  */
434
- depth: PropTypes.number,
435
+ depth: deprecate(PropTypes.number, 'The `depth` prop for `TreeNode` is no longer needed and has ' + 'been deprecated. It will be removed in the next major release.'),
435
436
  /**
436
437
  * Specify if the TreeNode is disabled
437
438
  */
@@ -451,7 +452,7 @@ TreeNode.propTypes = {
451
452
  /**
452
453
  * Callback function for when the node receives or loses focus
453
454
  */
454
- onNodeFocusEvent: PropTypes.func,
455
+ onNodeFocusEvent: deprecate(PropTypes.func, 'The `onNodeFocusEvent` prop for `TreeNode` is no longer needed and has ' + 'been deprecated. It will be removed in the next major release.'),
455
456
  /**
456
457
  * Callback function for when the node is selected
457
458
  */
@@ -463,7 +464,7 @@ TreeNode.propTypes = {
463
464
  /**
464
465
  * Callback function for when any node in the tree is selected
465
466
  */
466
- onTreeSelect: PropTypes.func,
467
+ onTreeSelect: deprecate(PropTypes.func, 'The `onTreeSelect` prop for `TreeNode` is no longer needed and has ' + 'been deprecated. It will be removed in the next major release.'),
467
468
  /**
468
469
  * A component used to render an icon.
469
470
  */
@@ -474,7 +475,7 @@ TreeNode.propTypes = {
474
475
  * Array containing all selected node IDs in the tree
475
476
  */
476
477
  // @ts-ignore
477
- selected: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
478
+ selected: deprecate(PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), 'The `selected` prop for `TreeNode` is no longer needed and has ' + 'been deprecated. It will be removed in the next major release.'),
478
479
  /**
479
480
  * Specify the value of the TreeNode
480
481
  */
package/es/index.d.ts CHANGED
@@ -58,6 +58,7 @@ export * from './components/OrderedList';
58
58
  export * from './components/OverflowMenu';
59
59
  export * from './components/OverflowMenuItem';
60
60
  export * as unstable__PageHeader from './components/PageHeader';
61
+ export * as preview__Dialog from './components/Dialog';
61
62
  export * from './components/Pagination';
62
63
  export * from './components/Pagination/Pagination.Skeleton';
63
64
  export * from './components/PaginationNav';
@@ -185,7 +186,6 @@ export type { TableToolbarSearchProps } from './components/DataTable/TableToolba
185
186
  export type { DataTableSkeletonProps } from './components/DataTableSkeleton/DataTableSkeleton';
186
187
  export type { DatePickerProps } from './components/DatePicker/DatePicker';
187
188
  export type { DatePickerInputProps } from './components/DatePickerInput/DatePickerInput';
188
- export type { DialogProps } from './components/Dialog/index';
189
189
  export type { DropdownProps } from './components/Dropdown/Dropdown';
190
190
  export type { ErrorBoundaryProps } from './components/ErrorBoundary/ErrorBoundary';
191
191
  export type { FeatureFlagsProps } from './components/FeatureFlags/index';
@@ -267,6 +267,7 @@ export type { OrderedListProps } from './components/OrderedList/OrderedList';
267
267
  export type { OverflowMenuProps } from './components/OverflowMenu/OverflowMenu';
268
268
  export type { OverflowMenuItemProps } from './components/OverflowMenuItem/OverflowMenuItem';
269
269
  export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderHeroImageProps, PageHeaderTabBarProps, } from './components/PageHeader';
270
+ export type { DialogProps, DialogHeaderProps, DialogControlsProps, DialogCloseButtonProps, DialogTitleProps, DialogSubtitleProps, DialogBodyProps, DialogFooterProps, } from './components/Dialog';
270
271
  export type { PaginationProps } from './components/Pagination/Pagination';
271
272
  export type { PaginationSkeletonProps } from './components/Pagination/Pagination.Skeleton';
272
273
  export type { DirectionButtonProps } from './components/PaginationNav/PaginationNav';
package/es/index.js CHANGED
@@ -105,6 +105,8 @@ export { default as OverflowMenu } from './components/OverflowMenu/index.js';
105
105
  export { default as OverflowMenuItem } from './components/OverflowMenuItem/OverflowMenuItem.js';
106
106
  import * as index from './components/PageHeader/index.js';
107
107
  export { index as unstable__PageHeader };
108
+ import * as index$1 from './components/Dialog/index.js';
109
+ export { index$1 as preview__Dialog };
108
110
  export { default as Pagination } from './components/Pagination/Pagination.js';
109
111
  export { default as PaginationSkeleton } from './components/Pagination/Pagination.Skeleton.js';
110
112
  export { default as PaginationNav } from './components/PaginationNav/PaginationNav.js';
@@ -28,7 +28,7 @@ var match = require('../../internal/keyboard/match.js');
28
28
  var index$1 = require('../FeatureFlags/index.js');
29
29
  var events = require('../../tools/events.js');
30
30
  var deprecate = require('../../prop-types/deprecate.js');
31
- var index$3 = require('../Dialog/index.js');
31
+ var Dialog = require('../Dialog/Dialog.js');
32
32
  var warning = require('../../internal/warning.js');
33
33
  var index$2 = require('../AILabel/index.js');
34
34
  var utils = require('../../internal/utils.js');
@@ -170,9 +170,14 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
170
170
  } = evt;
171
171
  const mouseDownTarget = onMouseDownTarget.current;
172
172
  evt.stopPropagation();
173
- const containsModalFooter = React.Children.toArray(childrenWithProps).some(child => utils.isComponentElement(child, ModalFooter.ModalFooter));
174
- const isPassive = !containsModalFooter;
175
- const shouldCloseOnOutsideClick = isPassive ? preventCloseOnClickOutside !== false : preventCloseOnClickOutside === true;
173
+ const shouldCloseOnOutsideClick =
174
+ // Passive modals can close on clicks outside the modal when
175
+ // preventCloseOnClickOutside is undefined or explicitly set to false.
176
+ isPassive && !preventCloseOnClickOutside ||
177
+ // Non-passive modals have to explicitly opt-in for close on outside
178
+ // behavior by explicitly setting preventCloseOnClickOutside to false,
179
+ // rather than just leaving it undefined.
180
+ !isPassive && preventCloseOnClickOutside === false;
176
181
  if (shouldCloseOnOutsideClick && target instanceof Node && !wrapFocus.elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && innerModal.current && !innerModal.current.contains(target) && !innerModal.current.contains(mouseDownTarget)) {
177
182
  closeModal(evt);
178
183
  }
@@ -256,6 +261,12 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
256
261
  return child;
257
262
  }
258
263
  });
264
+
265
+ // Modals without a footer are considered passive and carry limitations as
266
+ // outlined in the design spec.
267
+ const containsModalFooter = React.Children.toArray(childrenWithProps).some(child => utils.isComponentElement(child, ModalFooter.ModalFooter));
268
+ const isPassive = !containsModalFooter;
269
+ process.env.NODE_ENV !== "production" ? warning.warning(!(!isPassive && preventCloseOnClickOutside === false), '`<ComposedModal>` prop `preventCloseOnClickOutside` should not be ' + '`false` when `<ModalFooter>` is present. Transactional, non-passive ' + 'Modals should not be dissmissable by clicking outside. ' + 'See: https://carbondesignsystem.com/components/modal/usage/#transactional-modal') : void 0;
259
270
  React.useEffect(() => {
260
271
  if (!open) return;
261
272
  const handleEscapeKey = event => {
@@ -308,7 +319,7 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
308
319
  const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/React.cloneElement(candidate, {
309
320
  size: 'sm'
310
321
  }) : null;
311
- const modalBody = enableDialogElement ? /*#__PURE__*/React.createElement(index$3.unstable__Dialog, {
322
+ const modalBody = enableDialogElement ? /*#__PURE__*/React.createElement(Dialog.Dialog, {
312
323
  open: open,
313
324
  focusAfterCloseRef: launcherButtonRef,
314
325
  modal: true,
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import PropTypes from 'prop-types';
8
8
  import React, { type ChangeEvent, type MouseEvent, type ReactElement, type ReactNode } from 'react';
9
+ import { type SortRowFn } from './state/sorting';
9
10
  import type { DataTableSortState } from './state/sortStates';
10
11
  import { TranslateWithId } from '../../types/common';
11
12
  declare const translationKeys: {
@@ -181,13 +182,7 @@ export interface DataTableProps<RowType, ColTypes extends any[]> extends Transla
181
182
  render?: (renderProps: DataTableRenderProps<RowType, ColTypes>) => ReactElement;
182
183
  rows: Omit<DataTableRow<ColTypes>, 'cells'>[];
183
184
  size?: DataTableSize;
184
- sortRow?: (cellA: any, cellB: any, options: {
185
- sortDirection: DataTableSortState;
186
- sortStates: Record<DataTableSortState, DataTableSortState>;
187
- locale: string;
188
- key: string;
189
- compare: (a: number | string, b: number | string, locale?: string) => number;
190
- }) => number;
185
+ sortRow?: SortRowFn;
191
186
  stickyHeader?: boolean;
192
187
  useStaticWidth?: boolean;
193
188
  useZebraStyles?: boolean;
@@ -286,7 +281,7 @@ export declare const DataTable: {
286
281
  };
287
282
  TableHead: (props: React.HTMLAttributes<"thead">) => React.ReactElement<any>;
288
283
  TableHeader: React.ForwardRefExoticComponent<import("./TableHeader").TableHeaderProps & React.RefAttributes<HTMLTableCellElement>>;
289
- TableRow: React.ForwardRefExoticComponent<import("./TableRow").TableRowProps & React.RefAttributes<HTMLTableCellElement>>;
284
+ TableRow: React.ForwardRefExoticComponent<import("./TableRow").TableRowProps & React.RefAttributes<HTMLTableRowElement>>;
290
285
  TableSelectAll: {
291
286
  ({ ariaLabel: deprecatedAriaLabel, ["aria-label"]: ariaLabel, checked, id, indeterminate, name, onSelect, disabled, className, }: import("./TableSelectAll").TableSelectAllProps): import("react/jsx-runtime").JSX.Element;
292
287
  propTypes: {
@@ -551,9 +551,16 @@ const DataTable = props => {
551
551
  * @param headerKey - The field for the header that we are sorting by.
552
552
  */
553
553
  const handleSortBy = headerKey => () => {
554
- setState(prev => sorting.getNextSortState(props, prev, {
555
- key: headerKey
556
- }));
554
+ setState(prev => {
555
+ const sortState = sorting.getNextSortState(props, prev, {
556
+ key: headerKey
557
+ });
558
+ return {
559
+ ...prev,
560
+ // Preserve ALL existing state
561
+ ...sortState // Then apply only the sorting changes
562
+ };
563
+ });
557
564
  };
558
565
 
559
566
  /**
@@ -4,13 +4,41 @@
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, { type MouseEventHandler, type PropsWithChildren } from 'react';
8
- import { TableRowProps } from './TableRow';
9
- export interface TableExpandRowProps extends PropsWithChildren<TableRowProps> {
7
+ import React, { type HTMLAttributes, type MouseEventHandler, type PropsWithChildren } from 'react';
8
+ /** Props shared between `TableRow` and `TableExpandRow`. */
9
+ export interface TableRowExpandInteropProps {
10
+ /**
11
+ * @deprecated Use `aria-label` instead.
12
+ */
13
+ ariaLabel?: string;
14
+ /**
15
+ * Specify the string read by a voice reader when the expand trigger is
16
+ * focused
17
+ */
18
+ 'aria-label'?: string;
19
+ /**
20
+ * Space separated list of one or more ID values referencing the TableExpandedRow(s) being controlled by the TableExpandRow
21
+ */
22
+ 'aria-controls'?: string;
23
+ /**
24
+ * Specify whether this row is expanded or not. This helps coordinate data
25
+ * attributes so that `TableExpandRow` and `TableExpandedRow` work together
26
+ */
27
+ isExpanded?: boolean;
28
+ /**
29
+ * Hook for when a listener initiates a request to expand the given row
30
+ */
31
+ onExpand?: MouseEventHandler<HTMLButtonElement>;
32
+ /**
33
+ * Specify if the row is selected.
34
+ */
35
+ isSelected?: boolean;
36
+ }
37
+ export interface TableExpandRowProps extends PropsWithChildren<Omit<HTMLAttributes<HTMLTableRowElement>, 'onClick'>>, Omit<TableRowExpandInteropProps, 'aria-label' | 'onExpand'> {
10
38
  /**
11
39
  * Space separated list of one or more ID values referencing the TableExpandedRow(s) being controlled by the TableExpandRow
12
40
  */
13
- ['aria-controls']?: string;
41
+ 'aria-controls'?: string;
14
42
  /**
15
43
  * @deprecated This prop has been deprecated and will be
16
44
  * removed in the next major release of Carbon. Use the
@@ -21,7 +49,7 @@ export interface TableExpandRowProps extends PropsWithChildren<TableRowProps> {
21
49
  * Specify the string read by a voice reader when the expand trigger is
22
50
  * focused
23
51
  */
24
- ['aria-label']: string;
52
+ 'aria-label': string;
25
53
  /**
26
54
  * The id of the matching th node in the table head. Addresses a11y concerns outlined here: https://www.ibm.com/able/guidelines/ci162/info_and_relationships.html and https://www.w3.org/TR/WCAG20-TECHS/H43
27
55
  */
@@ -21,6 +21,8 @@ var TableDecoratorRow = require('./TableDecoratorRow.js');
21
21
  var index = require('../AILabel/index.js');
22
22
  var utils = require('../../internal/utils.js');
23
23
 
24
+ /** Props shared between `TableRow` and `TableExpandRow`. */
25
+
24
26
  const TableExpandRow = /*#__PURE__*/React.forwardRef(({
25
27
  ['aria-controls']: ariaControls,
26
28
  ['aria-label']: ariaLabel,
@@ -89,13 +91,13 @@ TableExpandRow.propTypes = {
89
91
  * Space separated list of one or more ID values referencing the TableExpandedRow(s) being controlled by the TableExpandRow
90
92
  * TODO: make this required in v12
91
93
  */
92
- ['aria-controls']: PropTypes.string,
94
+ 'aria-controls': PropTypes.string,
93
95
  /**
94
96
  * Specify the string read by a voice reader when the expand trigger is
95
97
  * focused
96
98
  */
97
99
  /**@ts-ignore*/
98
- ['aria-label']: PropTypes.string,
100
+ 'aria-label': PropTypes.string,
99
101
  /**
100
102
  * Deprecated, please use `aria-label` instead.
101
103
  * Specify the string read by a voice reader when the expand trigger is
@@ -5,9 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React, { type HTMLAttributes, type MouseEventHandler, type ReactNode } from 'react';
8
- import { sortStates } from './state/sorting';
9
8
  import { TranslateWithId } from '../../types/common';
10
- import { DataTableSortState } from './state/sortStates';
9
+ import { sortStates, type DataTableSortState } from './state/sortStates';
11
10
  export type TableHeaderTranslationKey = 'carbon.table.header.icon.description';
12
11
  export interface TableHeaderTranslationArgs {
13
12
  header: ReactNode;
@@ -14,12 +14,11 @@ var cx = require('classnames');
14
14
  var PropTypes = require('prop-types');
15
15
  var React = require('react');
16
16
  var iconsReact = require('@carbon/icons-react');
17
- require('./state/sorting.js');
18
17
  var useId = require('../../internal/useId.js');
19
18
  var usePrefix = require('../../internal/usePrefix.js');
19
+ var sortStates = require('./state/sortStates.js');
20
20
  var index = require('../AILabel/index.js');
21
21
  var utils = require('../../internal/utils.js');
22
- var sortStates = require('./state/sortStates.js');
23
22
 
24
23
  const defaultScope = 'col';
25
24
  const translationKeys = {
@@ -5,15 +5,12 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React, { type HTMLAttributes } from 'react';
8
- export interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {
8
+ import type { TableRowExpandInteropProps } from './TableExpandRow';
9
+ export interface TableRowProps extends HTMLAttributes<HTMLTableRowElement>, TableRowExpandInteropProps {
9
10
  /**
10
11
  * Specify an optional className to be applied to the container node
11
12
  */
12
13
  className?: string;
13
- /**
14
- * Specify if the row is selected
15
- */
16
- isSelected?: boolean;
17
14
  }
18
- declare const TableRow: React.ForwardRefExoticComponent<TableRowProps & React.RefAttributes<HTMLTableCellElement>>;
15
+ declare const TableRow: React.ForwardRefExoticComponent<TableRowProps & React.RefAttributes<HTMLTableRowElement>>;
19
16
  export default TableRow;
@@ -19,28 +19,10 @@ var TableDecoratorRow = require('./TableDecoratorRow.js');
19
19
  var index = require('../AILabel/index.js');
20
20
  var utils = require('../../internal/utils.js');
21
21
 
22
- const TableRow = /*#__PURE__*/React.forwardRef((props, ref) => {
23
- const prefix = usePrefix.usePrefix();
24
- let rowHasAILabel;
25
- if (props?.children) {
26
- // TODO: Why is this loop a `map`? It's not returning anything. Ideally,
27
- // it seems that it should be a `some`. Maybe I'm missing something?
28
- React.Children.toArray(props.children).map(child => {
29
- if (utils.isComponentElement(child, TableSlugRow.default)) {
30
- if (child.props.slug) {
31
- rowHasAILabel = true;
32
- }
33
- } else if (utils.isComponentElement(child, TableDecoratorRow.default) && utils.isComponentElement(child.props.decorator, index.AILabel)) {
34
- rowHasAILabel = true;
35
- }
36
- });
37
- }
22
+ const frFn = React.forwardRef;
23
+ const TableRow = frFn((props, ref) => {
38
24
  // Remove unnecessary props if provided to this component, these are
39
25
  // only useful in `TableExpandRow`
40
- const className = cx(props.className, {
41
- [`${prefix}--data-table--selected`]: props.isSelected,
42
- [`${prefix}--data-table--slug-row ${prefix}--data-table--ai-label-row`]: rowHasAILabel
43
- });
44
26
  const {
45
27
  ariaLabel,
46
28
  'aria-label': ariaLabelAlt,
@@ -50,6 +32,17 @@ const TableRow = /*#__PURE__*/React.forwardRef((props, ref) => {
50
32
  isSelected,
51
33
  ...cleanProps
52
34
  } = props;
35
+ const prefix = usePrefix.usePrefix();
36
+ const rowHasAILabel = React.Children.toArray(props.children).some(child => {
37
+ if (utils.isComponentElement(child, TableSlugRow.default)) {
38
+ return !!child.props.slug;
39
+ }
40
+ return utils.isComponentElement(child, TableDecoratorRow.default) && utils.isComponentElement(child.props.decorator, index.AILabel);
41
+ });
42
+ const className = cx(props.className, {
43
+ [`${prefix}--data-table--selected`]: isSelected,
44
+ [`${prefix}--data-table--slug-row ${prefix}--data-table--ai-label-row`]: rowHasAILabel
45
+ });
53
46
  if (className) {
54
47
  cleanProps.className = className;
55
48
  }
@@ -65,7 +58,27 @@ TableRow.propTypes = {
65
58
  /**
66
59
  * Specify if the row is selected
67
60
  */
68
- isSelected: PropTypes.bool
61
+ isSelected: PropTypes.bool,
62
+ /**
63
+ * Non-standard alias for `aria-label`.
64
+ */
65
+ ariaLabel: PropTypes.string,
66
+ /**
67
+ * Accessible label for the row element.
68
+ */
69
+ 'aria-label': PropTypes.string,
70
+ /**
71
+ * Associates this row with the id of the corresponding expanded row content.
72
+ */
73
+ 'aria-controls': PropTypes.string,
74
+ /**
75
+ * Handler called when the row’s expand toggle is clicked.
76
+ */
77
+ onExpand: PropTypes.func,
78
+ /**
79
+ * Flag indicating whether the row is currently expanded.
80
+ */
81
+ isExpanded: PropTypes.bool
69
82
  };
70
83
 
71
84
  exports.default = TableRow;
@@ -1,15 +1,56 @@
1
- export { sortStates };
2
- export const initialSortState: import("./sortStates").DataTableSortState;
3
- export function getNextSortDirection(prevHeader: string, header: string, prevState: string): string;
4
- export function getNextSortState(props: any, state: any, { key }: {
5
- key: any;
6
- }): any;
7
- export function getSortedState(props: {
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { type DataTableSortState } from './sortStates';
8
+ import type { DataTableCell } from '../DataTable';
9
+ export interface SortRowParams {
10
+ key: string;
11
+ sortDirection: DataTableSortState;
12
+ sortStates: Record<DataTableSortState, DataTableSortState>;
8
13
  locale: string;
9
- sortRows: Function;
10
- }, state: {
11
- rowIds: Array<string>;
12
- cellsById: object;
13
- initialRowOrder: Array<string>;
14
- }, key: string, sortDirection: string): object;
15
- import { sortStates } from './sortStates';
14
+ compare: (a: string | number, b: string | number, locale?: string) => number;
15
+ }
16
+ export type SortRowFn = (cellA: any, cellB: any, options: SortRowParams) => number;
17
+ interface Props {
18
+ locale?: string;
19
+ sortRow?: SortRowFn;
20
+ }
21
+ interface State<ColTypes extends any[]> {
22
+ rowIds: string[];
23
+ cellsById: Record<string, DataTableCell<ColTypes[number]>>;
24
+ initialRowOrder: string[];
25
+ sortHeaderKey: string | null;
26
+ sortDirection: DataTableSortState;
27
+ }
28
+ export declare const initialSortState: DataTableSortState;
29
+ /**
30
+ * Gets the next sort direction for a header.
31
+ *
32
+ * @param prevHeader - Key of the previously sorted header.
33
+ * @param currentHeader - Key of the currently selected header.
34
+ * @param prevState - Previous sort direction.
35
+ */
36
+ export declare const getNextSortDirection: (prevHeader: string, currentHeader: string, prevState: DataTableSortState) => DataTableSortState;
37
+ /**
38
+ * Gets the next sort state.
39
+ *
40
+ * @param props - Component props.
41
+ * @param state - Current table state.
42
+ * @param key - Header key to sort by.
43
+ */
44
+ export declare const getNextSortState: <ColTypes extends any[]>(props: Props, state: State<ColTypes>, { key }: {
45
+ key: string;
46
+ }) => Pick<State<ColTypes>, "sortHeaderKey" | "sortDirection" | "rowIds">;
47
+ /**
48
+ * Gets a sort state update.
49
+ *
50
+ * @param props - Component props.
51
+ * @param state - Current state of the table.
52
+ * @param key - Header key to sort by.
53
+ * @param sortDirection - Sort direction to apply.
54
+ */
55
+ export declare const getSortedState: <ColTypes extends any[]>({ locale, sortRow }: Props, { rowIds, cellsById, initialRowOrder }: State<ColTypes>, key: string, sortDirection: DataTableSortState) => Pick<State<ColTypes>, "rowIds" | "sortDirection" | "sortHeaderKey">;
56
+ export {};
@@ -10,37 +10,39 @@
10
10
  var sortStates = require('./sortStates.js');
11
11
  var sorting = require('../tools/sorting.js');
12
12
 
13
- // Our initialSortState should be `NONE`, unless a consumer has specified a
14
- // different initialSortState
15
13
  const initialSortState = sortStates.sortStates.NONE;
16
14
 
17
15
  /**
18
- * Utility used to get the next sort state given the following pieces of
19
- * information:
16
+ * Gets the next sort direction for a header.
20
17
  *
21
- * @param {string} prevHeader the value of the previous header
22
- * @param {string} header the value of the currently selected header
23
- * @param {string} prevState the previous sort state of the table
24
- * @returns {string}
18
+ * @param prevHeader - Key of the previously sorted header.
19
+ * @param currentHeader - Key of the currently selected header.
20
+ * @param prevState - Previous sort direction.
25
21
  */
26
- const getNextSortDirection = (prevHeader, header, prevState) => {
27
- // If the previous header is equivalent to the current header, we know that we
28
- // have to derive the next sort state from the previous sort state
29
- if (prevHeader === header) {
30
- // When transitioning, we know that the sequence of states is as follows:
31
- // NONE -> ASC -> DESC -> NONE
32
- if (prevState === 'NONE') {
33
- return sortStates.sortStates.ASC;
22
+ const getNextSortDirection = (prevHeader, currentHeader, prevState) => {
23
+ // Cycle for sorting the same header: NONE -> ASC -> DESC -> NONE.
24
+ if (prevHeader === currentHeader) {
25
+ switch (prevState) {
26
+ case sortStates.sortStates.NONE:
27
+ return sortStates.sortStates.ASC;
28
+ case sortStates.sortStates.ASC:
29
+ return sortStates.sortStates.DESC;
30
+ case sortStates.sortStates.DESC:
31
+ return sortStates.sortStates.NONE;
34
32
  }
35
- if (prevState === 'ASC') {
36
- return sortStates.sortStates.DESC;
37
- }
38
- return sortStates.sortStates.NONE;
39
33
  }
40
- // Otherwise, we have selected a new header and need to start off by sorting
41
- // in descending order by default
34
+
35
+ // Sorting a new header starts at ascending order.
42
36
  return sortStates.sortStates.ASC;
43
37
  };
38
+
39
+ /**
40
+ * Gets the next sort state.
41
+ *
42
+ * @param props - Component props.
43
+ * @param state - Current table state.
44
+ * @param key - Header key to sort by.
45
+ */
44
46
  const getNextSortState = (props, state, {
45
47
  key
46
48
  }) => {
@@ -48,38 +50,26 @@ const getNextSortState = (props, state, {
48
50
  sortDirection,
49
51
  sortHeaderKey
50
52
  } = state;
51
- const nextSortDirection = getNextSortDirection(key, sortHeaderKey, sortDirection);
53
+ const nextSortDirection = getNextSortDirection(key, sortHeaderKey ?? '', sortDirection);
52
54
  return getSortedState(props, state, key, nextSortDirection);
53
55
  };
54
56
 
55
57
  /**
56
- * Derive the set of sorted state fields from props and state for the given
57
- * header key and sortDirection
58
+ * Gets a sort state update.
58
59
  *
59
- * @param {object} props
60
- * @param {string} props.locale The current locale
61
- * @param {Function} props.sortRows Method to handle sorting a collection of
62
- * rows
63
- * @param {object} state
64
- * @param {Array<string>} state.rowIds Array of row ids
65
- * @param {object} state.cellsById Lookup object for cells by id
66
- * @param {Array<string>} state.initialRowOrder Initial row order for the
67
- * current set of rows
68
- * @param {string} key The key for the given header we are serving the
69
- * sorted state for
70
- * @param {string} sortDirection The sortState that we want to order by
71
- * @returns {object}
60
+ * @param props - Component props.
61
+ * @param state - Current state of the table.
62
+ * @param key - Header key to sort by.
63
+ * @param sortDirection - Sort direction to apply.
72
64
  */
73
- const getSortedState = (props, state, key, sortDirection) => {
74
- const {
75
- rowIds,
76
- cellsById,
77
- initialRowOrder
78
- } = state;
79
- const {
80
- locale,
81
- sortRow
82
- } = props;
65
+ const getSortedState = ({
66
+ locale,
67
+ sortRow
68
+ }, {
69
+ rowIds,
70
+ cellsById,
71
+ initialRowOrder
72
+ }, key, sortDirection) => {
83
73
  const nextRowIds = sortDirection !== sortStates.sortStates.NONE ? sorting.sortRows({
84
74
  rowIds,
85
75
  cellsById,
@@ -90,12 +80,11 @@ const getSortedState = (props, state, key, sortDirection) => {
90
80
  }) : initialRowOrder;
91
81
  return {
92
82
  sortHeaderKey: key,
93
- sortDirection: sortDirection,
83
+ sortDirection,
94
84
  rowIds: nextRowIds
95
85
  };
96
86
  };
97
87
 
98
- exports.sortStates = sortStates.sortStates;
99
88
  exports.getNextSortDirection = getNextSortDirection;
100
89
  exports.getNextSortState = getNextSortState;
101
90
  exports.getSortedState = getSortedState;
@@ -44,6 +44,10 @@ const compareStrings = (a, b, locale = 'en') => {
44
44
  numeric: isNumeric
45
45
  });
46
46
  };
47
+
48
+ // TODO: Should `SortRowParams` in
49
+ // packages/react/src/components/DataTable/state/sorting.ts be used here?
50
+
47
51
  /**
48
52
  * Sorts table rows based on the provided column key and direction.
49
53
  */