carbon-react 119.0.1 → 119.1.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.
@@ -1,10 +1,12 @@
1
1
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
- import React, { useLayoutEffect, useRef } from "react";
2
+ import React, { useLayoutEffect, useRef, useState, useEffect, useContext } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import styledSystemPropTypes from "@styled-system/prop-types";
5
5
  import { StyledFlatTableCell, StyledCellContent } from "./flat-table-cell.style";
6
6
  import { filterStyledSystemPaddingProps } from "../../../style/utils";
7
7
  import Icon from "../../icon";
8
+ import { FlatTableThemeContext } from "../flat-table.component";
9
+ import guid from "../../../__internal__/utils/helpers/guid";
8
10
  const paddingPropTypes = filterStyledSystemPaddingProps(styledSystemPropTypes.space);
9
11
  const FlatTableCell = _ref => {
10
12
  let {
@@ -26,11 +28,19 @@ const FlatTableCell = _ref => {
26
28
  ...rest
27
29
  } = _ref;
28
30
  const ref = useRef(null);
31
+ const id = useRef(guid());
32
+ const [tabIndex, setTabIndex] = useState(-1);
33
+ const {
34
+ selectedId
35
+ } = useContext(FlatTableThemeContext);
29
36
  useLayoutEffect(() => {
30
37
  if (ref.current && reportCellWidth) {
31
38
  reportCellWidth(ref.current.offsetWidth, cellIndex);
32
39
  }
33
40
  }, [reportCellWidth, cellIndex]);
41
+ useEffect(() => {
42
+ setTabIndex(selectedId === id.current ? 0 : -1);
43
+ }, [selectedId]);
34
44
  return /*#__PURE__*/React.createElement(StyledFlatTableCell, _extends({
35
45
  leftPosition: leftPosition,
36
46
  rightPosition: rightPosition,
@@ -43,11 +53,12 @@ const FlatTableCell = _ref => {
43
53
  rowSpan: rowspan,
44
54
  pl: pl,
45
55
  onClick: expandable && onClick ? onClick : undefined,
46
- tabIndex: expandable && onClick ? 0 : undefined,
56
+ tabIndex: expandable && onClick ? tabIndex : undefined,
47
57
  onKeyDown: expandable && onKeyDown ? onKeyDown : undefined,
48
58
  colWidth: width,
49
59
  isTruncated: truncate,
50
- expandable: expandable
60
+ expandable: expandable,
61
+ id: id.current
51
62
  }, rest), /*#__PURE__*/React.createElement(StyledCellContent, {
52
63
  title: truncate && !title && typeof children === "string" ? children : title,
53
64
  expandable: expandable
@@ -3,6 +3,7 @@ import React, { useLayoutEffect, useRef } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import StyledFlatTableCheckbox from "./flat-table-checkbox.style";
5
5
  import { Checkbox } from "../../checkbox";
6
+ import Events from "../../../__internal__/utils/helpers/events/events";
6
7
  const FlatTableCheckbox = _ref => {
7
8
  let {
8
9
  as = "td",
@@ -29,7 +30,9 @@ const FlatTableCheckbox = _ref => {
29
30
  if (onClick) onClick(event);
30
31
  };
31
32
  const handleKeyDown = event => {
32
- event.stopPropagation();
33
+ if (!Events.isDownKey(event) && !Events.isUpKey(event)) {
34
+ event.stopPropagation();
35
+ }
33
36
  };
34
37
  return /*#__PURE__*/React.createElement(StyledFlatTableCheckbox, _extends({
35
38
  ref: ref,
@@ -9,6 +9,7 @@ import FlatTableCheckbox from "../flat-table-checkbox";
9
9
  import FlatTableRowHeader from "../flat-table-row-header";
10
10
  import FlatTableRowDraggable from "./__internal__/flat-table-row-draggable.component";
11
11
  import { FlatTableThemeContext } from "../flat-table.component";
12
+ import guid from "../../../__internal__/utils/helpers/guid";
12
13
  const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13
14
  let {
14
15
  children,
@@ -32,6 +33,7 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
32
33
  moveItem,
33
34
  ...rest
34
35
  } = _ref;
36
+ const internalId = useRef(id ?? guid());
35
37
  const [isExpanded, setIsExpanded] = useState(expanded);
36
38
  let rowRef = useRef();
37
39
  if (ref) rowRef = ref;
@@ -43,6 +45,7 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
43
45
  const childrenArray = useMemo(() => React.Children.toArray(children), [children]);
44
46
  const lhsRowHeaderIndex = useMemo(() => childrenArray.findIndex(child => child.type.displayName === FlatTableRowHeader.displayName && child.props.stickyAlignment !== "right"), [childrenArray]);
45
47
  const rhsRowHeaderIndex = useMemo(() => childrenArray.findIndex(child => child.type.displayName === FlatTableRowHeader.displayName && child.props.stickyAlignment === "right"), [childrenArray]);
48
+ const [tabIndex, setTabIndex] = useState(-1);
46
49
  const noStickyColumnsOverlap = useMemo(() => {
47
50
  const hasLhsColumn = lhsRowHeaderIndex !== -1;
48
51
  const hasRhsColumn = rhsRowHeaderIndex !== -1;
@@ -50,7 +53,12 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
50
53
  return lhsRowHeaderIndex < rhsRowHeaderIndex;
51
54
  }, [lhsRowHeaderIndex, rhsRowHeaderIndex]);
52
55
  !noStickyColumnsOverlap ? process.env.NODE_ENV !== "production" ? invariant(false, `Do not render a right hand side \`${FlatTableRowHeader.displayName}\` before left hand side \`${FlatTableRowHeader.displayName}\``) : invariant(false) : void 0;
53
- const themeContext = useContext(FlatTableThemeContext);
56
+ const {
57
+ colorTheme,
58
+ size,
59
+ setSelectedId,
60
+ selectedId
61
+ } = useContext(FlatTableThemeContext);
54
62
  const reportCellWidth = useCallback((width, index) => {
55
63
  const isLeftSticky = index < lhsRowHeaderIndex;
56
64
  const copiedArray = isLeftSticky ? leftStickyCellWidths : rightStickyCellWidths;
@@ -79,7 +87,9 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
79
87
  }
80
88
  }
81
89
  function handleClick(ev) {
82
- if (onClick) onClick(ev);
90
+ if (onClick) {
91
+ onClick(ev);
92
+ }
83
93
  if (expandable && !firstColumnExpandable) {
84
94
  toggleExpanded();
85
95
  }
@@ -87,7 +97,7 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
87
97
  if (onClick || expandable) {
88
98
  interactiveRowProps = {
89
99
  isRowInteractive: !firstColumnExpandable,
90
- tabIndex: firstColumnExpandable ? undefined : 0,
100
+ tabIndex: firstColumnExpandable ? undefined : tabIndex,
91
101
  onKeyDown,
92
102
  isFirstColumnInteractive: firstColumnExpandable,
93
103
  isExpanded
@@ -118,6 +128,14 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
118
128
  useEffect(() => {
119
129
  setIsExpanded(expanded);
120
130
  }, [expanded]);
131
+ useEffect(() => {
132
+ if (highlighted || selected) {
133
+ setSelectedId(internalId.current);
134
+ }
135
+ }, [highlighted, selected, setSelectedId]);
136
+ useEffect(() => {
137
+ setTabIndex(selectedId === internalId.current ? 0 : -1);
138
+ }, [selectedId]);
121
139
  const rowComponent = isInSidebar => /*#__PURE__*/React.createElement(StyledFlatTableRow, _extends({
122
140
  isInSidebar: isInSidebar,
123
141
  expandable: expandable,
@@ -131,15 +149,16 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
131
149
  ref: rowRef,
132
150
  lhsRowHeaderIndex: lhsRowHeaderIndex,
133
151
  rhsRowHeaderIndex: rhsRowHeaderIndex,
134
- colorTheme: themeContext.colorTheme,
135
- size: themeContext.size,
152
+ colorTheme: colorTheme,
153
+ size: size,
136
154
  stickyOffset: stickyOffset,
137
155
  bgColor: bgColor,
138
156
  horizontalBorderColor: horizontalBorderColor,
139
157
  horizontalBorderSize: horizontalBorderSize,
140
158
  applyBorderLeft: applyBorderLeft,
141
159
  draggable: draggable,
142
- totalChildren: childrenArray.length
160
+ totalChildren: childrenArray.length,
161
+ id: internalId.current
143
162
  }, interactiveRowProps, rest), React.Children.map(children, (child, index) => {
144
163
  return child && /*#__PURE__*/React.cloneElement(child, {
145
164
  expandable: expandable && index === firstCellIndex,
@@ -153,7 +172,7 @@ const FlatTableRow = /*#__PURE__*/React.forwardRef((_ref, ref) => {
153
172
  });
154
173
  }));
155
174
  const draggableComponent = isInSidebar => /*#__PURE__*/React.createElement(FlatTableRowDraggable, {
156
- id: id,
175
+ id: internalId.current,
157
176
  moveItem: moveItem,
158
177
  findItem: findItem
159
178
  }, rowComponent(isInSidebar));
@@ -109,6 +109,10 @@ const StyledFlatTableRow = styled.tr`
109
109
  color: var(--colorsActionMinor500);
110
110
  }
111
111
 
112
+ :focus-visible {
113
+ outline: none;
114
+ }
115
+
112
116
  ${allCellTypes} {
113
117
  ${backgroundColor && `background-color: ${backgroundColor};`}
114
118
 
@@ -1,10 +1,12 @@
1
1
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
- import React, { useCallback } from "react";
2
+ import React, { useCallback, useEffect, useContext, useState, useRef } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import styledSystemPropTypes from "@styled-system/prop-types";
5
5
  import { filterStyledSystemPaddingProps } from "../../../style/utils";
6
6
  import Icon from "../../icon";
7
7
  import { StyledFlatTableRowHeader, StyledFlatTableRowHeaderContent } from "./flat-table-row-header.style";
8
+ import { FlatTableThemeContext } from "../flat-table.component";
9
+ import guid from "../../../__internal__/utils/helpers/guid";
8
10
  const paddingPropTypes = filterStyledSystemPaddingProps(styledSystemPropTypes.space);
9
11
  const FlatTableRowHeader = _ref => {
10
12
  let {
@@ -23,12 +25,20 @@ const FlatTableRowHeader = _ref => {
23
25
  stickyAlignment = "left",
24
26
  ...rest
25
27
  } = _ref;
28
+ const id = useRef(guid());
29
+ const [tabIndex, setTabIndex] = useState(-1);
30
+ const {
31
+ selectedId
32
+ } = useContext(FlatTableThemeContext);
26
33
  const handleOnClick = useCallback(ev => {
27
34
  if (expandable && onClick) onClick(ev);
28
35
  }, [expandable, onClick]);
29
36
  const handleOnKeyDown = useCallback(ev => {
30
37
  if (expandable && onKeyDown) onKeyDown(ev);
31
38
  }, [expandable, onKeyDown]);
39
+ useEffect(() => {
40
+ setTabIndex(selectedId === id.current ? 0 : -1);
41
+ }, [selectedId]);
32
42
  return /*#__PURE__*/React.createElement(StyledFlatTableRowHeader, _extends({
33
43
  leftPosition: stickyAlignment === "left" ? leftPosition || 0 : undefined,
34
44
  rightPosition: stickyAlignment === "right" ? rightPosition || 0 : undefined,
@@ -38,11 +48,12 @@ const FlatTableRowHeader = _ref => {
38
48
  py: py || "10px",
39
49
  px: px || 3,
40
50
  onClick: handleOnClick,
41
- tabIndex: expandable && onClick ? 0 : undefined,
51
+ tabIndex: expandable && onClick ? tabIndex : undefined,
42
52
  onKeyDown: handleOnKeyDown,
43
53
  isTruncated: truncate,
44
54
  expandable: expandable,
45
- stickyAlignment: stickyAlignment
55
+ stickyAlignment: stickyAlignment,
56
+ id: id.current
46
57
  }, rest), /*#__PURE__*/React.createElement(StyledFlatTableRowHeaderContent, {
47
58
  title: truncate && !title && typeof children === "string" ? children : title,
48
59
  expandable: expandable
@@ -5,8 +5,12 @@ import styledSystemPropTypes from "@styled-system/prop-types";
5
5
  import { StyledFlatTableWrapper, StyledFlatTable, StyledFlatTableFooter, StyledTableContainer } from "./flat-table.style";
6
6
  import { DrawerSidebarContext } from "../drawer";
7
7
  import { filterStyledSystemMarginProps } from "../../style/utils";
8
- export const FlatTableThemeContext = /*#__PURE__*/React.createContext({});
8
+ import Events from "../../__internal__/utils/helpers/events/events";
9
+ export const FlatTableThemeContext = /*#__PURE__*/React.createContext({
10
+ setSelectedId: () => {}
11
+ });
9
12
  const marginPropTypes = filterStyledSystemMarginProps(styledSystemPropTypes.space);
13
+ const FOCUSABLE_ROW_AND_CELL_QUERY = "tbody tr, tbody tr td, tbody tr th";
10
14
  const FlatTable = _ref => {
11
15
  let {
12
16
  caption,
@@ -31,6 +35,7 @@ const FlatTable = _ref => {
31
35
  const [hasHorizontalScrollbar, setHasHorizontalScrollbar] = useState(false);
32
36
  const [firstColRowSpanIndex, setFirstColRowSpanIndex] = useState(-1);
33
37
  const [lastColRowSpanIndex, setLastColRowSpanIndex] = useState(-1);
38
+ const [selectedId, setSelectedId] = useState("");
34
39
  const addDefaultHeight = !height && (hasStickyHead || hasStickyFooter);
35
40
  const tableStylingProps = {
36
41
  caption,
@@ -47,6 +52,8 @@ const FlatTable = _ref => {
47
52
  const rowSpan = cell?.getAttribute("rowspan");
48
53
  return rowSpan >= index + 1;
49
54
  });
55
+
56
+ /* istanbul ignore else */
50
57
  if (wrapperRef.current && tableRef.current) {
51
58
  const {
52
59
  offsetHeight,
@@ -75,6 +82,58 @@ const FlatTable = _ref => {
75
82
  }
76
83
  }
77
84
  }, [footer, children, height, minHeight]);
85
+ const findParentIndexOfFocusedChild = array => array.findIndex(el => {
86
+ const focusableRowElements = el.querySelectorAll("button, input, a, [tabindex]");
87
+
88
+ /* istanbul ignore else */
89
+ if (focusableRowElements) {
90
+ const focusableRowElementsArray = Array.from(focusableRowElements);
91
+ if (focusableRowElementsArray.find(el2 => el2 === document.activeElement)) {
92
+ return true;
93
+ }
94
+ }
95
+ return false;
96
+ });
97
+ const handleKeyDown = ev => {
98
+ const focusableElements = tableRef.current?.querySelectorAll(FOCUSABLE_ROW_AND_CELL_QUERY);
99
+
100
+ /* istanbul ignore if */
101
+ if (!focusableElements) {
102
+ return;
103
+ }
104
+ const focusableElementsArray = Array.from(focusableElements).filter(el => el.getAttribute("tabindex") !== null);
105
+ const currentFocusIndex = focusableElementsArray.findIndex(el => el === document.activeElement);
106
+ if (Events.isDownKey(ev)) {
107
+ if (currentFocusIndex !== -1 && currentFocusIndex < focusableElementsArray.length) {
108
+ focusableElementsArray[currentFocusIndex + 1]?.focus();
109
+ } else {
110
+ // it may be that an element within the row currently has focus
111
+ const index = findParentIndexOfFocusedChild(focusableElementsArray);
112
+ if (index !== -1 && index < focusableElementsArray.length) {
113
+ focusableElementsArray[index + 1]?.focus();
114
+ }
115
+ }
116
+ } else if (Events.isUpKey(ev)) {
117
+ if (currentFocusIndex > 0) {
118
+ focusableElementsArray[currentFocusIndex - 1]?.focus();
119
+ } else {
120
+ // it may be that an element within the row currently has focus
121
+ const index = findParentIndexOfFocusedChild(focusableElementsArray);
122
+ if (index > 0) {
123
+ focusableElementsArray[index - 1]?.focus();
124
+ }
125
+ }
126
+ }
127
+ };
128
+ useLayoutEffect(() => {
129
+ const focusableElements = tableRef.current?.querySelectorAll(FOCUSABLE_ROW_AND_CELL_QUERY);
130
+
131
+ // if no other menu item is selected, we need to make the first row a tab stop
132
+ if (focusableElements && !selectedId) {
133
+ const focusableArray = Array.from(focusableElements).filter(el => el.getAttribute("tabindex") !== null);
134
+ setSelectedId(focusableArray[0]?.getAttribute("id") || "");
135
+ }
136
+ }, [selectedId]);
78
137
  return /*#__PURE__*/React.createElement(DrawerSidebarContext.Consumer, null, _ref2 => {
79
138
  let {
80
139
  isInSidebar
@@ -101,7 +160,8 @@ const FlatTable = _ref => {
101
160
  hasHorizontalScrollbar: hasHorizontalScrollbar,
102
161
  hasFooter: !!footer,
103
162
  firstColRowSpanIndex: firstColRowSpanIndex,
104
- lastColRowSpanIndex: lastColRowSpanIndex
163
+ lastColRowSpanIndex: lastColRowSpanIndex,
164
+ onKeyDown: handleKeyDown
105
165
  }, rest), /*#__PURE__*/React.createElement(StyledTableContainer, {
106
166
  overflowX: overflowX,
107
167
  width: width
@@ -111,7 +171,9 @@ const FlatTable = _ref => {
111
171
  }, tableStylingProps), caption ? /*#__PURE__*/React.createElement("caption", null, caption) : null, /*#__PURE__*/React.createElement(FlatTableThemeContext.Provider, {
112
172
  value: {
113
173
  colorTheme,
114
- size
174
+ size,
175
+ setSelectedId,
176
+ selectedId
115
177
  }
116
178
  }, children)), footer && /*#__PURE__*/React.createElement(StyledFlatTableFooter, {
117
179
  hasStickyFooter: hasStickyFooter
@@ -10,6 +10,8 @@ var _propTypes2 = _interopRequireDefault(require("@styled-system/prop-types"));
10
10
  var _flatTableCell = require("./flat-table-cell.style");
11
11
  var _utils = require("../../../style/utils");
12
12
  var _icon = _interopRequireDefault(require("../../icon"));
13
+ var _flatTable = require("../flat-table.component");
14
+ var _guid = _interopRequireDefault(require("../../../__internal__/utils/helpers/guid"));
13
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
16
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
15
17
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -35,11 +37,19 @@ const FlatTableCell = _ref => {
35
37
  ...rest
36
38
  } = _ref;
37
39
  const ref = (0, _react.useRef)(null);
40
+ const id = (0, _react.useRef)((0, _guid.default)());
41
+ const [tabIndex, setTabIndex] = (0, _react.useState)(-1);
42
+ const {
43
+ selectedId
44
+ } = (0, _react.useContext)(_flatTable.FlatTableThemeContext);
38
45
  (0, _react.useLayoutEffect)(() => {
39
46
  if (ref.current && reportCellWidth) {
40
47
  reportCellWidth(ref.current.offsetWidth, cellIndex);
41
48
  }
42
49
  }, [reportCellWidth, cellIndex]);
50
+ (0, _react.useEffect)(() => {
51
+ setTabIndex(selectedId === id.current ? 0 : -1);
52
+ }, [selectedId]);
43
53
  return /*#__PURE__*/_react.default.createElement(_flatTableCell.StyledFlatTableCell, _extends({
44
54
  leftPosition: leftPosition,
45
55
  rightPosition: rightPosition,
@@ -52,11 +62,12 @@ const FlatTableCell = _ref => {
52
62
  rowSpan: rowspan,
53
63
  pl: pl,
54
64
  onClick: expandable && onClick ? onClick : undefined,
55
- tabIndex: expandable && onClick ? 0 : undefined,
65
+ tabIndex: expandable && onClick ? tabIndex : undefined,
56
66
  onKeyDown: expandable && onKeyDown ? onKeyDown : undefined,
57
67
  colWidth: width,
58
68
  isTruncated: truncate,
59
- expandable: expandable
69
+ expandable: expandable,
70
+ id: id.current
60
71
  }, rest), /*#__PURE__*/_react.default.createElement(_flatTableCell.StyledCellContent, {
61
72
  title: truncate && !title && typeof children === "string" ? children : title,
62
73
  expandable: expandable
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _flatTableCheckbox = _interopRequireDefault(require("./flat-table-checkbox.style"));
10
10
  var _checkbox = require("../../checkbox");
11
+ var _events = _interopRequireDefault(require("../../../__internal__/utils/helpers/events/events"));
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
13
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
14
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -38,7 +39,9 @@ const FlatTableCheckbox = _ref => {
38
39
  if (onClick) onClick(event);
39
40
  };
40
41
  const handleKeyDown = event => {
41
- event.stopPropagation();
42
+ if (!_events.default.isDownKey(event) && !_events.default.isUpKey(event)) {
43
+ event.stopPropagation();
44
+ }
42
45
  };
43
46
  return /*#__PURE__*/_react.default.createElement(_flatTableCheckbox.default, _extends({
44
47
  ref: ref,
@@ -14,6 +14,7 @@ var _flatTableCheckbox = _interopRequireDefault(require("../flat-table-checkbox"
14
14
  var _flatTableRowHeader = _interopRequireDefault(require("../flat-table-row-header"));
15
15
  var _flatTableRowDraggable = _interopRequireDefault(require("./__internal__/flat-table-row-draggable.component"));
16
16
  var _flatTable = require("../flat-table.component");
17
+ var _guid = _interopRequireDefault(require("../../../__internal__/utils/helpers/guid"));
17
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
19
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
19
20
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -41,6 +42,7 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
41
42
  moveItem,
42
43
  ...rest
43
44
  } = _ref;
45
+ const internalId = (0, _react.useRef)(id ?? (0, _guid.default)());
44
46
  const [isExpanded, setIsExpanded] = (0, _react.useState)(expanded);
45
47
  let rowRef = (0, _react.useRef)();
46
48
  if (ref) rowRef = ref;
@@ -52,6 +54,7 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
52
54
  const childrenArray = (0, _react.useMemo)(() => _react.default.Children.toArray(children), [children]);
53
55
  const lhsRowHeaderIndex = (0, _react.useMemo)(() => childrenArray.findIndex(child => child.type.displayName === _flatTableRowHeader.default.displayName && child.props.stickyAlignment !== "right"), [childrenArray]);
54
56
  const rhsRowHeaderIndex = (0, _react.useMemo)(() => childrenArray.findIndex(child => child.type.displayName === _flatTableRowHeader.default.displayName && child.props.stickyAlignment === "right"), [childrenArray]);
57
+ const [tabIndex, setTabIndex] = (0, _react.useState)(-1);
55
58
  const noStickyColumnsOverlap = (0, _react.useMemo)(() => {
56
59
  const hasLhsColumn = lhsRowHeaderIndex !== -1;
57
60
  const hasRhsColumn = rhsRowHeaderIndex !== -1;
@@ -59,7 +62,12 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
59
62
  return lhsRowHeaderIndex < rhsRowHeaderIndex;
60
63
  }, [lhsRowHeaderIndex, rhsRowHeaderIndex]);
61
64
  !noStickyColumnsOverlap ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, `Do not render a right hand side \`${_flatTableRowHeader.default.displayName}\` before left hand side \`${_flatTableRowHeader.default.displayName}\``) : (0, _invariant.default)(false) : void 0;
62
- const themeContext = (0, _react.useContext)(_flatTable.FlatTableThemeContext);
65
+ const {
66
+ colorTheme,
67
+ size,
68
+ setSelectedId,
69
+ selectedId
70
+ } = (0, _react.useContext)(_flatTable.FlatTableThemeContext);
63
71
  const reportCellWidth = (0, _react.useCallback)((width, index) => {
64
72
  const isLeftSticky = index < lhsRowHeaderIndex;
65
73
  const copiedArray = isLeftSticky ? leftStickyCellWidths : rightStickyCellWidths;
@@ -88,7 +96,9 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
88
96
  }
89
97
  }
90
98
  function handleClick(ev) {
91
- if (onClick) onClick(ev);
99
+ if (onClick) {
100
+ onClick(ev);
101
+ }
92
102
  if (expandable && !firstColumnExpandable) {
93
103
  toggleExpanded();
94
104
  }
@@ -96,7 +106,7 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
96
106
  if (onClick || expandable) {
97
107
  interactiveRowProps = {
98
108
  isRowInteractive: !firstColumnExpandable,
99
- tabIndex: firstColumnExpandable ? undefined : 0,
109
+ tabIndex: firstColumnExpandable ? undefined : tabIndex,
100
110
  onKeyDown,
101
111
  isFirstColumnInteractive: firstColumnExpandable,
102
112
  isExpanded
@@ -127,6 +137,14 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
127
137
  (0, _react.useEffect)(() => {
128
138
  setIsExpanded(expanded);
129
139
  }, [expanded]);
140
+ (0, _react.useEffect)(() => {
141
+ if (highlighted || selected) {
142
+ setSelectedId(internalId.current);
143
+ }
144
+ }, [highlighted, selected, setSelectedId]);
145
+ (0, _react.useEffect)(() => {
146
+ setTabIndex(selectedId === internalId.current ? 0 : -1);
147
+ }, [selectedId]);
130
148
  const rowComponent = isInSidebar => /*#__PURE__*/_react.default.createElement(_flatTableRow.default, _extends({
131
149
  isInSidebar: isInSidebar,
132
150
  expandable: expandable,
@@ -140,15 +158,16 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
140
158
  ref: rowRef,
141
159
  lhsRowHeaderIndex: lhsRowHeaderIndex,
142
160
  rhsRowHeaderIndex: rhsRowHeaderIndex,
143
- colorTheme: themeContext.colorTheme,
144
- size: themeContext.size,
161
+ colorTheme: colorTheme,
162
+ size: size,
145
163
  stickyOffset: stickyOffset,
146
164
  bgColor: bgColor,
147
165
  horizontalBorderColor: horizontalBorderColor,
148
166
  horizontalBorderSize: horizontalBorderSize,
149
167
  applyBorderLeft: applyBorderLeft,
150
168
  draggable: draggable,
151
- totalChildren: childrenArray.length
169
+ totalChildren: childrenArray.length,
170
+ id: internalId.current
152
171
  }, interactiveRowProps, rest), _react.default.Children.map(children, (child, index) => {
153
172
  return child && /*#__PURE__*/_react.default.cloneElement(child, {
154
173
  expandable: expandable && index === firstCellIndex,
@@ -162,7 +181,7 @@ const FlatTableRow = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
162
181
  });
163
182
  }));
164
183
  const draggableComponent = isInSidebar => /*#__PURE__*/_react.default.createElement(_flatTableRowDraggable.default, {
165
- id: id,
184
+ id: internalId.current,
166
185
  moveItem: moveItem,
167
186
  findItem: findItem
168
187
  }, rowComponent(isInSidebar));
@@ -118,6 +118,10 @@ const StyledFlatTableRow = _styledComponents.default.tr`
118
118
  color: var(--colorsActionMinor500);
119
119
  }
120
120
 
121
+ :focus-visible {
122
+ outline: none;
123
+ }
124
+
121
125
  ${allCellTypes} {
122
126
  ${backgroundColor && `background-color: ${backgroundColor};`}
123
127
 
@@ -10,6 +10,8 @@ var _propTypes2 = _interopRequireDefault(require("@styled-system/prop-types"));
10
10
  var _utils = require("../../../style/utils");
11
11
  var _icon = _interopRequireDefault(require("../../icon"));
12
12
  var _flatTableRowHeader = require("./flat-table-row-header.style");
13
+ var _flatTable = require("../flat-table.component");
14
+ var _guid = _interopRequireDefault(require("../../../__internal__/utils/helpers/guid"));
13
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
16
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
15
17
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -32,12 +34,20 @@ const FlatTableRowHeader = _ref => {
32
34
  stickyAlignment = "left",
33
35
  ...rest
34
36
  } = _ref;
37
+ const id = (0, _react.useRef)((0, _guid.default)());
38
+ const [tabIndex, setTabIndex] = (0, _react.useState)(-1);
39
+ const {
40
+ selectedId
41
+ } = (0, _react.useContext)(_flatTable.FlatTableThemeContext);
35
42
  const handleOnClick = (0, _react.useCallback)(ev => {
36
43
  if (expandable && onClick) onClick(ev);
37
44
  }, [expandable, onClick]);
38
45
  const handleOnKeyDown = (0, _react.useCallback)(ev => {
39
46
  if (expandable && onKeyDown) onKeyDown(ev);
40
47
  }, [expandable, onKeyDown]);
48
+ (0, _react.useEffect)(() => {
49
+ setTabIndex(selectedId === id.current ? 0 : -1);
50
+ }, [selectedId]);
41
51
  return /*#__PURE__*/_react.default.createElement(_flatTableRowHeader.StyledFlatTableRowHeader, _extends({
42
52
  leftPosition: stickyAlignment === "left" ? leftPosition || 0 : undefined,
43
53
  rightPosition: stickyAlignment === "right" ? rightPosition || 0 : undefined,
@@ -47,11 +57,12 @@ const FlatTableRowHeader = _ref => {
47
57
  py: py || "10px",
48
58
  px: px || 3,
49
59
  onClick: handleOnClick,
50
- tabIndex: expandable && onClick ? 0 : undefined,
60
+ tabIndex: expandable && onClick ? tabIndex : undefined,
51
61
  onKeyDown: handleOnKeyDown,
52
62
  isTruncated: truncate,
53
63
  expandable: expandable,
54
- stickyAlignment: stickyAlignment
64
+ stickyAlignment: stickyAlignment,
65
+ id: id.current
55
66
  }, rest), /*#__PURE__*/_react.default.createElement(_flatTableRowHeader.StyledFlatTableRowHeaderContent, {
56
67
  title: truncate && !title && typeof children === "string" ? children : title,
57
68
  expandable: expandable
@@ -10,13 +10,17 @@ var _propTypes2 = _interopRequireDefault(require("@styled-system/prop-types"));
10
10
  var _flatTable = require("./flat-table.style");
11
11
  var _drawer = require("../drawer");
12
12
  var _utils = require("../../style/utils");
13
+ var _events = _interopRequireDefault(require("../../__internal__/utils/helpers/events/events"));
13
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
15
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
15
16
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
16
17
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
17
- const FlatTableThemeContext = /*#__PURE__*/_react.default.createContext({});
18
+ const FlatTableThemeContext = /*#__PURE__*/_react.default.createContext({
19
+ setSelectedId: () => {}
20
+ });
18
21
  exports.FlatTableThemeContext = FlatTableThemeContext;
19
22
  const marginPropTypes = (0, _utils.filterStyledSystemMarginProps)(_propTypes2.default.space);
23
+ const FOCUSABLE_ROW_AND_CELL_QUERY = "tbody tr, tbody tr td, tbody tr th";
20
24
  const FlatTable = _ref => {
21
25
  let {
22
26
  caption,
@@ -41,6 +45,7 @@ const FlatTable = _ref => {
41
45
  const [hasHorizontalScrollbar, setHasHorizontalScrollbar] = (0, _react.useState)(false);
42
46
  const [firstColRowSpanIndex, setFirstColRowSpanIndex] = (0, _react.useState)(-1);
43
47
  const [lastColRowSpanIndex, setLastColRowSpanIndex] = (0, _react.useState)(-1);
48
+ const [selectedId, setSelectedId] = (0, _react.useState)("");
44
49
  const addDefaultHeight = !height && (hasStickyHead || hasStickyFooter);
45
50
  const tableStylingProps = {
46
51
  caption,
@@ -57,6 +62,8 @@ const FlatTable = _ref => {
57
62
  const rowSpan = cell?.getAttribute("rowspan");
58
63
  return rowSpan >= index + 1;
59
64
  });
65
+
66
+ /* istanbul ignore else */
60
67
  if (wrapperRef.current && tableRef.current) {
61
68
  const {
62
69
  offsetHeight,
@@ -85,6 +92,58 @@ const FlatTable = _ref => {
85
92
  }
86
93
  }
87
94
  }, [footer, children, height, minHeight]);
95
+ const findParentIndexOfFocusedChild = array => array.findIndex(el => {
96
+ const focusableRowElements = el.querySelectorAll("button, input, a, [tabindex]");
97
+
98
+ /* istanbul ignore else */
99
+ if (focusableRowElements) {
100
+ const focusableRowElementsArray = Array.from(focusableRowElements);
101
+ if (focusableRowElementsArray.find(el2 => el2 === document.activeElement)) {
102
+ return true;
103
+ }
104
+ }
105
+ return false;
106
+ });
107
+ const handleKeyDown = ev => {
108
+ const focusableElements = tableRef.current?.querySelectorAll(FOCUSABLE_ROW_AND_CELL_QUERY);
109
+
110
+ /* istanbul ignore if */
111
+ if (!focusableElements) {
112
+ return;
113
+ }
114
+ const focusableElementsArray = Array.from(focusableElements).filter(el => el.getAttribute("tabindex") !== null);
115
+ const currentFocusIndex = focusableElementsArray.findIndex(el => el === document.activeElement);
116
+ if (_events.default.isDownKey(ev)) {
117
+ if (currentFocusIndex !== -1 && currentFocusIndex < focusableElementsArray.length) {
118
+ focusableElementsArray[currentFocusIndex + 1]?.focus();
119
+ } else {
120
+ // it may be that an element within the row currently has focus
121
+ const index = findParentIndexOfFocusedChild(focusableElementsArray);
122
+ if (index !== -1 && index < focusableElementsArray.length) {
123
+ focusableElementsArray[index + 1]?.focus();
124
+ }
125
+ }
126
+ } else if (_events.default.isUpKey(ev)) {
127
+ if (currentFocusIndex > 0) {
128
+ focusableElementsArray[currentFocusIndex - 1]?.focus();
129
+ } else {
130
+ // it may be that an element within the row currently has focus
131
+ const index = findParentIndexOfFocusedChild(focusableElementsArray);
132
+ if (index > 0) {
133
+ focusableElementsArray[index - 1]?.focus();
134
+ }
135
+ }
136
+ }
137
+ };
138
+ (0, _react.useLayoutEffect)(() => {
139
+ const focusableElements = tableRef.current?.querySelectorAll(FOCUSABLE_ROW_AND_CELL_QUERY);
140
+
141
+ // if no other menu item is selected, we need to make the first row a tab stop
142
+ if (focusableElements && !selectedId) {
143
+ const focusableArray = Array.from(focusableElements).filter(el => el.getAttribute("tabindex") !== null);
144
+ setSelectedId(focusableArray[0]?.getAttribute("id") || "");
145
+ }
146
+ }, [selectedId]);
88
147
  return /*#__PURE__*/_react.default.createElement(_drawer.DrawerSidebarContext.Consumer, null, _ref2 => {
89
148
  let {
90
149
  isInSidebar
@@ -111,7 +170,8 @@ const FlatTable = _ref => {
111
170
  hasHorizontalScrollbar: hasHorizontalScrollbar,
112
171
  hasFooter: !!footer,
113
172
  firstColRowSpanIndex: firstColRowSpanIndex,
114
- lastColRowSpanIndex: lastColRowSpanIndex
173
+ lastColRowSpanIndex: lastColRowSpanIndex,
174
+ onKeyDown: handleKeyDown
115
175
  }, rest), /*#__PURE__*/_react.default.createElement(_flatTable.StyledTableContainer, {
116
176
  overflowX: overflowX,
117
177
  width: width
@@ -121,7 +181,9 @@ const FlatTable = _ref => {
121
181
  }, tableStylingProps), caption ? /*#__PURE__*/_react.default.createElement("caption", null, caption) : null, /*#__PURE__*/_react.default.createElement(FlatTableThemeContext.Provider, {
122
182
  value: {
123
183
  colorTheme,
124
- size
184
+ size,
185
+ setSelectedId,
186
+ selectedId
125
187
  }
126
188
  }, children)), footer && /*#__PURE__*/_react.default.createElement(_flatTable.StyledFlatTableFooter, {
127
189
  hasStickyFooter: hasStickyFooter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "119.0.1",
3
+ "version": "119.1.0",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",