@carbon/react 1.89.0 → 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 (42) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +922 -881
  2. package/README.md +2 -2
  3. package/es/components/ComposedModal/ComposedModal.js +14 -3
  4. package/es/components/DataTable/DataTable.d.ts +3 -8
  5. package/es/components/DataTable/TableExpandRow.d.ts +33 -5
  6. package/es/components/DataTable/TableExpandRow.js +4 -2
  7. package/es/components/DataTable/TableHeader.d.ts +1 -2
  8. package/es/components/DataTable/TableHeader.js +1 -2
  9. package/es/components/DataTable/TableRow.d.ts +3 -6
  10. package/es/components/DataTable/TableRow.js +35 -22
  11. package/es/components/DataTable/state/sorting.d.ts +55 -14
  12. package/es/components/DataTable/state/sorting.js +40 -50
  13. package/es/components/DataTable/tools/sorting.js +4 -0
  14. package/es/components/Modal/Modal.js +12 -6
  15. package/es/components/NumberInput/NumberInput.js +11 -6
  16. package/es/components/Popover/index.js +6 -2
  17. package/es/components/Tag/DismissibleTag.d.ts +5 -0
  18. package/es/components/Tag/DismissibleTag.js +6 -1
  19. package/es/components/Toggletip/index.js +19 -8
  20. package/es/components/TreeView/TreeNode.d.ts +28 -0
  21. package/es/components/TreeView/TreeNode.js +6 -5
  22. package/lib/components/ComposedModal/ComposedModal.js +14 -3
  23. package/lib/components/DataTable/DataTable.d.ts +3 -8
  24. package/lib/components/DataTable/TableExpandRow.d.ts +33 -5
  25. package/lib/components/DataTable/TableExpandRow.js +4 -2
  26. package/lib/components/DataTable/TableHeader.d.ts +1 -2
  27. package/lib/components/DataTable/TableHeader.js +1 -2
  28. package/lib/components/DataTable/TableRow.d.ts +3 -6
  29. package/lib/components/DataTable/TableRow.js +34 -21
  30. package/lib/components/DataTable/state/sorting.d.ts +55 -14
  31. package/lib/components/DataTable/state/sorting.js +39 -50
  32. package/lib/components/DataTable/tools/sorting.js +4 -0
  33. package/lib/components/Modal/Modal.js +12 -6
  34. package/lib/components/NumberInput/NumberInput.js +10 -5
  35. package/lib/components/Popover/index.js +6 -2
  36. package/lib/components/Tag/DismissibleTag.d.ts +5 -0
  37. package/lib/components/Tag/DismissibleTag.js +6 -1
  38. package/lib/components/Toggletip/index.js +18 -7
  39. package/lib/components/TreeView/TreeNode.d.ts +28 -0
  40. package/lib/components/TreeView/TreeNode.js +6 -5
  41. package/package.json +9 -9
  42. package/telemetry.yml +14 -0
@@ -8,7 +8,7 @@
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import cx from 'classnames';
10
10
  import PropTypes from 'prop-types';
11
- import React, { useContext, useRef, useState } from 'react';
11
+ import React, { useContext, useRef, useState, useEffect } from 'react';
12
12
  import { Popover, PopoverContent } from '../Popover/index.js';
13
13
  import { Escape } from '../../internal/keyboard/keys.js';
14
14
  import { match } from '../../internal/keyboard/match.js';
@@ -127,13 +127,24 @@ function Toggletip({
127
127
  actions.close();
128
128
  }
129
129
  });
130
- useWindowEvent('click', ({
131
- target
132
- }) => {
133
- if (open && target instanceof Node && !ref.current?.contains(target)) {
134
- actions.close();
135
- }
136
- });
130
+ useEffect(() => {
131
+ if (!ref.current) return;
132
+ const targetDocument = ref.current.ownerDocument || document;
133
+ const eventType = 'PointerEvent' in window ? 'pointerdown' : 'mousedown';
134
+ const handleOutsideClick = event => {
135
+ const node = event.target;
136
+ if (open && node && !ref.current.contains(node)) {
137
+ setOpen(false);
138
+ }
139
+ };
140
+ const options = {
141
+ capture: true
142
+ };
143
+ targetDocument.addEventListener(eventType, handleOutsideClick, options);
144
+ return () => {
145
+ targetDocument.removeEventListener(eventType, handleOutsideClick, options);
146
+ };
147
+ }, [open]);
137
148
  return /*#__PURE__*/React.createElement(ToggletipContext.Provider, {
138
149
  value: value
139
150
  }, /*#__PURE__*/React.createElement(Popover, _extends({
@@ -11,6 +11,9 @@ export type TreeNodeProps = {
11
11
  /**
12
12
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
13
13
  * The ID of the active node in the tree
14
+ *
15
+ * @deprecated The `active` prop for `TreeNode` has
16
+ * been deprecated after the introduction of context. It will be removed in the next major release.
14
17
  */
15
18
  active?: string | number;
16
19
  /**
@@ -29,6 +32,9 @@ export type TreeNodeProps = {
29
32
  /**
30
33
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
31
34
  * TreeNode depth to determine spacing
35
+ *
36
+ * @deprecated The `depth` prop for `TreeNode` has
37
+ * been deprecated after the introduction of context. It will be removed in the next major release.
32
38
  */
33
39
  depth?: number;
34
40
  /**
@@ -49,6 +55,9 @@ export type TreeNodeProps = {
49
55
  label: React.ReactNode;
50
56
  /**
51
57
  * Callback function for when the node receives or loses focus
58
+ *
59
+ * @deprecated The `onNodeFocusEvent` prop for `TreeNode` has
60
+ * been deprecated after the introduction of context. It will be removed in the next major release.
52
61
  */
53
62
  onNodeFocusEvent?: (event: React.FocusEvent<HTMLElement>) => void;
54
63
  /**
@@ -61,6 +70,9 @@ export type TreeNodeProps = {
61
70
  onToggle?: UncontrolledOnToggle | ControlledOnToggle;
62
71
  /**
63
72
  * Callback function for when any node in the tree is selected
73
+ *
74
+ * @deprecated The `onTreeSelect` prop for `TreeNode` has
75
+ * been deprecated after the introduction of context. It will be removed in the next major release.
64
76
  */
65
77
  onTreeSelect?: (event: React.MouseEvent | React.KeyboardEvent, node: Pick<TreeNodeProps, 'id' | 'label' | 'value'>) => void;
66
78
  /**
@@ -70,6 +82,8 @@ export type TreeNodeProps = {
70
82
  /**
71
83
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
72
84
  * Array containing all selected node IDs in the tree
85
+ * @deprecated The `selected` prop for `TreeNode` has
86
+ * been deprecated after the introduction of context. It will be removed in the next major release.
73
87
  */
74
88
  selected?: Array<string | number>;
75
89
  /**
@@ -97,6 +111,9 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
97
111
  /**
98
112
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
99
113
  * The ID of the active node in the tree
114
+ *
115
+ * @deprecated The `active` prop for `TreeNode` has
116
+ * been deprecated after the introduction of context. It will be removed in the next major release.
100
117
  */
101
118
  active?: string | number;
102
119
  /**
@@ -115,6 +132,9 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
115
132
  /**
116
133
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
117
134
  * TreeNode depth to determine spacing
135
+ *
136
+ * @deprecated The `depth` prop for `TreeNode` has
137
+ * been deprecated after the introduction of context. It will be removed in the next major release.
118
138
  */
119
139
  depth?: number;
120
140
  /**
@@ -135,6 +155,9 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
135
155
  label: React.ReactNode;
136
156
  /**
137
157
  * Callback function for when the node receives or loses focus
158
+ *
159
+ * @deprecated The `onNodeFocusEvent` prop for `TreeNode` has
160
+ * been deprecated after the introduction of context. It will be removed in the next major release.
138
161
  */
139
162
  onNodeFocusEvent?: (event: React.FocusEvent<HTMLElement>) => void;
140
163
  /**
@@ -147,6 +170,9 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
147
170
  onToggle?: UncontrolledOnToggle | ControlledOnToggle;
148
171
  /**
149
172
  * Callback function for when any node in the tree is selected
173
+ *
174
+ * @deprecated The `onTreeSelect` prop for `TreeNode` has
175
+ * been deprecated after the introduction of context. It will be removed in the next major release.
150
176
  */
151
177
  onTreeSelect?: (event: React.MouseEvent | React.KeyboardEvent, node: Pick<TreeNodeProps, "id" | "label" | "value">) => void;
152
178
  /**
@@ -156,6 +182,8 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
156
182
  /**
157
183
  * **Note:** this is controlled by the parent TreeView component, do not set manually.
158
184
  * Array containing all selected node IDs in the tree
185
+ * @deprecated The `selected` prop for `TreeNode` has
186
+ * been deprecated after the introduction of context. It will be removed in the next major release.
159
187
  */
160
188
  selected?: Array<string | number>;
161
189
  /**
@@ -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
  */
@@ -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 => {
@@ -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: {
@@ -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;