@carbon/ibm-products 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. package/css/index-full-carbon.css +82 -9
  2. package/css/index-full-carbon.css.map +1 -1
  3. package/css/index-full-carbon.min.css +3 -3
  4. package/css/index-full-carbon.min.css.map +1 -1
  5. package/css/index-without-carbon-released-only.css +1 -2
  6. package/css/index-without-carbon-released-only.css.map +1 -1
  7. package/css/index-without-carbon-released-only.min.css +1 -1
  8. package/css/index-without-carbon-released-only.min.css.map +1 -1
  9. package/css/index-without-carbon.css +82 -9
  10. package/css/index-without-carbon.css.map +1 -1
  11. package/css/index-without-carbon.min.css +3 -3
  12. package/css/index-without-carbon.min.css.map +1 -1
  13. package/css/index.css +82 -9
  14. package/css/index.css.map +1 -1
  15. package/css/index.min.css +3 -3
  16. package/css/index.min.css.map +1 -1
  17. package/es/components/AddSelect/AddSelect.js +104 -16
  18. package/es/components/AddSelect/AddSelectBreadcrumbs.js +4 -4
  19. package/es/components/AddSelect/AddSelectColumn.js +21 -0
  20. package/es/components/AddSelect/AddSelectList.js +67 -8
  21. package/es/components/AddSelect/AddSelectSidebar.js +7 -1
  22. package/es/components/DataSpreadsheet/DataSpreadsheet.js +42 -2
  23. package/es/components/DataSpreadsheet/DataSpreadsheetBody.js +194 -10
  24. package/es/components/DataSpreadsheet/createActiveCellFn.js +1 -1
  25. package/es/components/DataSpreadsheet/createCellSelectionArea.js +45 -0
  26. package/es/components/InlineEdit/InlineEdit.js +23 -13
  27. package/es/global/js/utils/DisplayBox.js +31 -0
  28. package/es/global/js/utils/deepCloneObject.js +26 -0
  29. package/lib/components/AddSelect/AddSelect.js +102 -15
  30. package/lib/components/AddSelect/AddSelectBreadcrumbs.js +2 -3
  31. package/lib/components/AddSelect/AddSelectColumn.js +37 -0
  32. package/lib/components/AddSelect/AddSelectList.js +65 -8
  33. package/lib/components/AddSelect/AddSelectSidebar.js +7 -1
  34. package/lib/components/DataSpreadsheet/DataSpreadsheet.js +42 -2
  35. package/lib/components/DataSpreadsheet/DataSpreadsheetBody.js +198 -10
  36. package/lib/components/DataSpreadsheet/createActiveCellFn.js +1 -1
  37. package/lib/components/DataSpreadsheet/createCellSelectionArea.js +56 -0
  38. package/lib/components/InlineEdit/InlineEdit.js +23 -13
  39. package/lib/global/js/utils/DisplayBox.js +46 -0
  40. package/lib/global/js/utils/deepCloneObject.js +37 -0
  41. package/package.json +8 -8
  42. package/scss/components/ActionBar/_storybook-styles.scss +8 -0
  43. package/scss/components/ActionSet/_storybook-styles.scss +1 -3
  44. package/scss/components/AddSelect/_add-select.scss +58 -2
  45. package/scss/components/BreadcrumbWithOverflow/_storybook-styles.scss +8 -0
  46. package/scss/components/ButtonSetWithOverflow/_storybook-styles.scss +8 -0
  47. package/scss/components/DataSpreadsheet/_data-spreadsheet.scss +18 -0
  48. package/scss/components/InlineEdit/_inline-edit.scss +11 -4
  49. package/scss/components/InlineEdit/_storybook-styles.scss +1 -0
  50. package/scss/components/TagSet/_storybook-styles.scss +8 -0
  51. package/scss/components/Tearsheet/_tearsheet.scss +1 -2
  52. package/scss/global/styles/_display-box.scss +62 -0
@@ -0,0 +1,21 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ //
3
+ // Copyright IBM Corp. 2022
4
+ //
5
+ // This source code is licensed under the Apache-2.0 license found in the
6
+ // LICENSE file in the root directory of this source tree.
7
+ //
8
+ import React from 'react'; // import PropTypes from 'prop-types';
9
+
10
+ import { pkg } from '../../settings';
11
+ import { AddSelectList } from './AddSelectList';
12
+ var componentName = 'AddSelect';
13
+ export var AddSelectColumn = function AddSelectColumn(props) {
14
+ var blockClass = "".concat(pkg.prefix, "--add-select__col");
15
+ return /*#__PURE__*/React.createElement("div", {
16
+ className: blockClass
17
+ }, /*#__PURE__*/React.createElement(AddSelectList, _extends({}, props, {
18
+ inColumn: true
19
+ })));
20
+ };
21
+ AddSelectColumn.displayName = componentName;
@@ -13,6 +13,7 @@ import { pkg } from '../../settings';
13
13
  var componentName = 'AddSelectList';
14
14
  export var AddSelectList = function AddSelectList(_ref) {
15
15
  var filteredItems = _ref.filteredItems,
16
+ inColumn = _ref.inColumn,
16
17
  multi = _ref.multi,
17
18
  multiSelection = _ref.multiSelection,
18
19
  path = _ref.path,
@@ -41,11 +42,61 @@ export var AddSelectList = function AddSelectList(_ref) {
41
42
 
42
43
  var onNavigateItem = function onNavigateItem(_ref2) {
43
44
  var id = _ref2.id,
44
- title = _ref2.title;
45
- setPath([].concat(_toConsumableArray(path), [{
46
- id: id,
47
- title: title
48
- }]));
45
+ title = _ref2.title,
46
+ parent = _ref2.parent;
47
+
48
+ // if multi select
49
+ if (multi) {
50
+ // if top level reset the path
51
+ if (!parent) {
52
+ setPath([{
53
+ id: id,
54
+ title: title
55
+ }]);
56
+ } else {
57
+ var pathIds = path.map(function (p) {
58
+ return p.id;
59
+ }); // if item is already selected somewhere go back to that item
60
+
61
+ if (pathIds.includes(id)) {
62
+ var pathIdx = pathIds.findIndex(function (pathId) {
63
+ return pathId === id;
64
+ });
65
+
66
+ var newPath = _toConsumableArray(path).splice(0, pathIdx + 1);
67
+
68
+ setPath(_toConsumableArray(newPath));
69
+ } else {
70
+ // if the item is on the same level as another selected item start from the parent level
71
+ if (path.find(function (p) {
72
+ return p.parent === parent;
73
+ })) {
74
+ var parentIdx = path.findIndex(function (p) {
75
+ return p.id === parent;
76
+ });
77
+
78
+ var _newPath = _toConsumableArray(path).splice(0, parentIdx + 1);
79
+
80
+ setPath([].concat(_toConsumableArray(_newPath), [{
81
+ id: id,
82
+ title: title,
83
+ parent: parent
84
+ }]));
85
+ } else {
86
+ setPath([].concat(_toConsumableArray(path), [{
87
+ id: id,
88
+ title: title,
89
+ parent: parent
90
+ }]));
91
+ }
92
+ }
93
+ }
94
+ } else {
95
+ setPath([].concat(_toConsumableArray(path), [{
96
+ id: id,
97
+ title: title
98
+ }]));
99
+ }
49
100
  };
50
101
 
51
102
  return /*#__PURE__*/React.createElement("div", {
@@ -55,15 +106,22 @@ export var AddSelectList = function AddSelectList(_ref) {
55
106
  className: "".concat(blockClass)
56
107
  }, /*#__PURE__*/React.createElement(StructuredListBody, null, filteredItems.map(function (item) {
57
108
  return /*#__PURE__*/React.createElement(StructuredListRow, {
58
- key: item.id
59
- }, /*#__PURE__*/React.createElement(StructuredListCell, null, /*#__PURE__*/React.createElement("div", {
109
+ key: item.id,
110
+ className: "".concat(blockClass, "-row")
111
+ }, /*#__PURE__*/React.createElement(StructuredListCell, {
112
+ className: "".concat(blockClass, "-cell")
113
+ }, /*#__PURE__*/React.createElement("div", {
60
114
  className: "".concat(blockClass, "-cell-wrapper")
61
115
  }, multi ? /*#__PURE__*/React.createElement(Checkbox, {
62
116
  className: "".concat(blockClass, "-checkbox"),
63
117
  onChange: function onChange(value) {
64
118
  return handleMultiSelection(item.id, value);
65
119
  },
66
- labelText: item.title,
120
+ labelText: !inColumn ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
121
+ className: "".concat(blockClass, "-cell-title")
122
+ }, item.title), /*#__PURE__*/React.createElement("span", {
123
+ className: "".concat(blockClass, "-cell-subtitle")
124
+ }, item.subtitle)) : item.title,
67
125
  id: item.id,
68
126
  checked: multiSelection.includes(item.id)
69
127
  }) : /*#__PURE__*/React.createElement(RadioButton, {
@@ -83,6 +141,7 @@ export var AddSelectList = function AddSelectList(_ref) {
83
141
  };
84
142
  AddSelectList.propTypes = {
85
143
  filteredItems: PropTypes.array,
144
+ inColumn: PropTypes.bool,
86
145
  multi: PropTypes.bool,
87
146
  multiSelection: PropTypes.array,
88
147
  path: PropTypes.array,
@@ -53,7 +53,13 @@ export var AddSelectSidebar = function AddSelectSidebar(_ref) {
53
53
  id = _ref2.id;
54
54
  return /*#__PURE__*/React.createElement("div", {
55
55
  className: "".concat(blockClass, "-accordion-title")
56
- }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("p", null, title), /*#__PURE__*/React.createElement("p", null, subtitle)), /*#__PURE__*/React.createElement(Button, {
56
+ }, /*#__PURE__*/React.createElement("div", {
57
+ className: "".concat(blockClass, "-selected-item")
58
+ }, /*#__PURE__*/React.createElement("p", {
59
+ className: "".concat(blockClass, "-selected-item-title")
60
+ }, title), /*#__PURE__*/React.createElement("p", {
61
+ className: "".concat(blockClass, "-selected-item-subtitle")
62
+ }, subtitle)), /*#__PURE__*/React.createElement(Button, {
57
63
  renderIcon: SubtractAlt32,
58
64
  iconDescription: removeIconDescription,
59
65
  hasIconOnly: true,
@@ -66,6 +66,21 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
66
66
  activeCellCoordinates = _useState4[0],
67
67
  setActiveCellCoordinates = _useState4[1];
68
68
 
69
+ var _useState5 = useState([]),
70
+ _useState6 = _slicedToArray(_useState5, 2),
71
+ selectionAreas = _useState6[0],
72
+ setSelectionAreas = _useState6[1];
73
+
74
+ var _useState7 = useState(false),
75
+ _useState8 = _slicedToArray(_useState7, 2),
76
+ clickAndHoldActive = _useState8[0],
77
+ setClickAndHoldActive = _useState8[1];
78
+
79
+ var _useState9 = useState(null),
80
+ _useState10 = _slicedToArray(_useState9, 2),
81
+ currentMatcher = _useState10[0],
82
+ setCurrentMatcher = _useState10[1];
83
+
69
84
  var cellSizeValue = getCellSize(cellSize);
70
85
  var defaultColumn = useMemo(function () {
71
86
  return {
@@ -108,6 +123,13 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
108
123
  if (activeCellHighlight) {
109
124
  activeCellHighlight.remove();
110
125
  }
126
+ }, [spreadsheetRef]); // Removes the cell selection elements
127
+
128
+ var removeCellSelections = useCallback(function () {
129
+ var cellSelections = spreadsheetRef.current.querySelectorAll(".".concat(blockClass, "__selection-area--element"));
130
+ Array.from(cellSelections).forEach(function (element) {
131
+ return element.remove();
132
+ });
111
133
  }, [spreadsheetRef]); // Click outside useEffect
112
134
 
113
135
  useEffect(function () {
@@ -116,7 +138,9 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
116
138
  return;
117
139
  }
118
140
 
141
+ setSelectionAreas([]);
119
142
  removeActiveCell();
143
+ removeCellSelections();
120
144
  setContainerHasFocus(false);
121
145
  setActiveCellCoordinates(null);
122
146
  };
@@ -125,7 +149,7 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
125
149
  return function () {
126
150
  document.removeEventListener('click', handleOutsideClick);
127
151
  };
128
- }, [spreadsheetRef, removeActiveCell]);
152
+ }, [spreadsheetRef, removeActiveCell, removeCellSelections]);
129
153
  var createActiveCell = useCallback(function (_ref2) {
130
154
  var placementElement = _ref2.placementElement,
131
155
  coords = _ref2.coords,
@@ -172,12 +196,21 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
172
196
 
173
197
  if ([35, 36, 37, 38, 39, 40].indexOf(keyCode) > -1) {
174
198
  event.preventDefault();
199
+ } // Clear out all cell selection areas if user uses any arrow key
200
+
201
+
202
+ if ([37, 38, 39, 40].indexOf(keyCode) > -1) {
203
+ if (selectionAreas !== null && selectionAreas !== void 0 && selectionAreas.length) {
204
+ setSelectionAreas([]);
205
+ removeCellSelections();
206
+ }
175
207
  }
176
208
 
177
209
  switch (keyCode) {
178
210
  // Tab
179
211
  case 9:
180
212
  {
213
+ setSelectionAreas([]);
181
214
  removeActiveCell();
182
215
  setContainerHasFocus(false);
183
216
  setActiveCellCoordinates(null);
@@ -321,7 +354,7 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
321
354
  break;
322
355
  }
323
356
  }
324
- }, [handleInitialArrowPress, activeCellCoordinates, removeActiveCell, columns.length, rows.length]); // Adds active cell highlight to correct cell onKeyDown
357
+ }, [handleInitialArrowPress, activeCellCoordinates, selectionAreas === null || selectionAreas === void 0 ? void 0 : selectionAreas.length, removeCellSelections, removeActiveCell, columns.length, rows.length]); // Adds active cell highlight to correct cell onKeyDown
325
358
 
326
359
  useEffect(function () {
327
360
  var activeCellPlacementElement = spreadsheetRef === null || spreadsheetRef === void 0 ? void 0 : spreadsheetRef.current.querySelector("[data-row-index=\"".concat(activeCellCoordinates === null || activeCellCoordinates === void 0 ? void 0 : activeCellCoordinates.row, "\"][data-column-index=\"").concat(activeCellCoordinates === null || activeCellCoordinates === void 0 ? void 0 : activeCellCoordinates.column, "\"]"));
@@ -354,6 +387,13 @@ export var DataSpreadsheet = /*#__PURE__*/React.forwardRef(function (_ref, ref)
354
387
  defaultColumn: defaultColumn,
355
388
  headerGroups: headerGroups
356
389
  }), /*#__PURE__*/React.createElement(DataSpreadsheetBody, {
390
+ clickAndHoldActive: clickAndHoldActive,
391
+ setClickAndHoldActive: setClickAndHoldActive,
392
+ currentMatcher: currentMatcher,
393
+ setCurrentMatcher: setCurrentMatcher,
394
+ setContainerHasFocus: setContainerHasFocus,
395
+ selectionAreas: selectionAreas,
396
+ setSelectionAreas: setSelectionAreas,
357
397
  cellSize: cellSize,
358
398
  defaultColumn: defaultColumn,
359
399
  getTableBodyProps: getTableBodyProps,
@@ -1,4 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
3
 
3
4
  /**
4
5
  * Copyright IBM Corp. 2022, 2022
@@ -11,6 +12,9 @@ import PropTypes from 'prop-types';
11
12
  import { FixedSizeList } from 'react-window';
12
13
  import cx from 'classnames';
13
14
  import { pkg } from '../../settings';
15
+ import { deepCloneObject } from '../../global/js/utils/deepCloneObject';
16
+ import uuidv4 from '../../global/js/utils/uuidv4';
17
+ import { createCellSelectionArea } from './createCellSelectionArea';
14
18
  var blockClass = "".concat(pkg.prefix, "--data-spreadsheet");
15
19
  export var DataSpreadsheetBody = function DataSpreadsheetBody(_ref) {
16
20
  var defaultColumn = _ref.defaultColumn,
@@ -19,10 +23,95 @@ export var DataSpreadsheetBody = function DataSpreadsheetBody(_ref) {
19
23
  prepareRow = _ref.prepareRow,
20
24
  rows = _ref.rows,
21
25
  setActiveCellCoordinates = _ref.setActiveCellCoordinates,
26
+ selectionAreas = _ref.selectionAreas,
27
+ setContainerHasFocus = _ref.setContainerHasFocus,
28
+ setSelectionAreas = _ref.setSelectionAreas,
22
29
  scrollBarSize = _ref.scrollBarSize,
23
- totalColumnsWidth = _ref.totalColumnsWidth;
24
- // Make sure that if the cellSize prop changes, the active
30
+ totalColumnsWidth = _ref.totalColumnsWidth,
31
+ clickAndHoldActive = _ref.clickAndHoldActive,
32
+ setClickAndHoldActive = _ref.setClickAndHoldActive,
33
+ currentMatcher = _ref.currentMatcher,
34
+ setCurrentMatcher = _ref.setCurrentMatcher;
35
+ // Create cell selection areas based on selectionAreas array
36
+ useEffect(function () {
37
+ if (selectionAreas && selectionAreas.length) {
38
+ selectionAreas.map(function (area) {
39
+ if (!area.areaCreated && area.point1 && area.point2 && area.matcher) {
40
+ // Do not create a cell selection area if point1 and point2 have the same values
41
+ // Cell selections must have two distinctly different points for an area to be created
42
+ if (area.point1.row === area.point2.row && area.point1.column === area.point2.column) {
43
+ var selectionAreasClone = deepCloneObject(selectionAreas);
44
+ var indexOfCurrentArea = selectionAreasClone.findIndex(function (item) {
45
+ return item.matcher === area.matcher;
46
+ });
47
+ selectionAreasClone[indexOfCurrentArea].areaCreated = false;
48
+ selectionAreasClone[indexOfCurrentArea].point2 = null;
49
+ return setSelectionAreas(selectionAreasClone);
50
+ }
51
+
52
+ createCellSelectionArea({
53
+ area: area,
54
+ blockClass: blockClass,
55
+ selectionAreas: selectionAreas,
56
+ setSelectionAreas: setSelectionAreas
57
+ });
58
+ }
59
+
60
+ return;
61
+ });
62
+ }
63
+ }, [selectionAreas, setSelectionAreas]); // Mouse up
64
+
65
+ useEffect(function () {
66
+ var handleMouseUp = function handleMouseUp(event) {
67
+ setClickAndHoldActive(false);
68
+ var cellButton = event.target.closest(".".concat(blockClass, "__body--td"));
69
+
70
+ if (cellButton) {
71
+ var endCellCoordinates = {
72
+ row: Number(cellButton.getAttribute('data-row-index')),
73
+ column: Number(cellButton.getAttribute('data-column-index'))
74
+ };
75
+ setCurrentMatcher(null);
76
+ setSelectionAreas(function (prev) {
77
+ var selectionAreaClone = deepCloneObject(prev);
78
+ var indexOfItemToUpdate = selectionAreaClone.findIndex(function (item) {
79
+ return item.matcher === currentMatcher;
80
+ }); // No items in the array have an object that matches the value of currentMatcher
81
+
82
+ if (indexOfItemToUpdate === -1) {
83
+ return prev;
84
+ }
85
+
86
+ selectionAreaClone[indexOfItemToUpdate].point2 = endCellCoordinates;
87
+ selectionAreaClone[indexOfItemToUpdate].areaCreated = false;
88
+ return selectionAreaClone;
89
+ });
90
+ } else {
91
+ var selectionAreaClone = deepCloneObject(selectionAreas);
92
+ var indexOfItemToUpdate = selectionAreaClone.findIndex(function (item) {
93
+ return item.matcher === currentMatcher;
94
+ });
95
+
96
+ if (indexOfItemToUpdate === -1) {
97
+ return;
98
+ }
99
+
100
+ var newArray = selectionAreaClone.filter(function (item) {
101
+ return item.matcher !== currentMatcher;
102
+ });
103
+ setCurrentMatcher(null);
104
+ setSelectionAreas(newArray);
105
+ }
106
+ };
107
+
108
+ document.addEventListener('mouseup', handleMouseUp);
109
+ return function () {
110
+ document.removeEventListener('mouseup', handleMouseUp);
111
+ };
112
+ }, [selectionAreas, currentMatcher, setSelectionAreas, setClickAndHoldActive, setCurrentMatcher]); // Make sure that if the cellSize prop changes, the active
25
113
  // cell also gets updated with the new size
114
+
26
115
  useEffect(function () {
27
116
  var listContainer = spreadsheetBodyRef === null || spreadsheetBodyRef === void 0 ? void 0 : spreadsheetBodyRef.current;
28
117
  var activeCellButton = listContainer.querySelector(".".concat(blockClass, "__active-cell--highlight"));
@@ -33,12 +122,68 @@ export var DataSpreadsheetBody = function DataSpreadsheetBody(_ref) {
33
122
  }, [defaultColumn === null || defaultColumn === void 0 ? void 0 : defaultColumn.rowHeight]); // onClick fn for each cell in the data spreadsheet body,
34
123
  // adds the active cell highlight
35
124
 
36
- var handleBodyCellClick = useCallback(function (cell, columnIndex) {
37
- setActiveCellCoordinates({
125
+ var handleBodyCellClick = useCallback(function (event, cell, columnIndex) {
126
+ var isHoldingCommandKey = event.metaKey || event.ctrlKey;
127
+ setContainerHasFocus(true);
128
+ var activeCoordinates = {
38
129
  row: cell.row.index,
39
130
  column: columnIndex
40
- });
41
- }, [setActiveCellCoordinates]); // Renders each cell in the spreadsheet body
131
+ };
132
+ var tempMatcher = uuidv4();
133
+ setActiveCellCoordinates(activeCoordinates); // prevent multiple selections unless cmd key is held
134
+ // meaning that selectionAreas should only have one item by default
135
+
136
+ if (isHoldingCommandKey) {
137
+ setSelectionAreas(function (prev) {
138
+ return [].concat(_toConsumableArray(prev), [{
139
+ point1: activeCoordinates,
140
+ matcher: tempMatcher
141
+ }]);
142
+ });
143
+ } else {
144
+ // remove all previous cell selections
145
+ var cellSelections = spreadsheetBodyRef.current.querySelectorAll(".".concat(blockClass, "__selection-area--element"));
146
+ Array.from(cellSelections).forEach(function (element) {
147
+ return element.remove();
148
+ });
149
+ setSelectionAreas([{
150
+ point1: activeCoordinates,
151
+ matcher: tempMatcher
152
+ }]);
153
+ }
154
+
155
+ setCurrentMatcher(tempMatcher);
156
+ setClickAndHoldActive(true);
157
+ }, [setActiveCellCoordinates, setSelectionAreas, setContainerHasFocus, setClickAndHoldActive, setCurrentMatcher]);
158
+ var handleBodyCellHover = useCallback(function (event, cell, columnIndex) {
159
+ if (clickAndHoldActive) {
160
+ var cellCoordinates = {
161
+ row: cell.row.index,
162
+ column: columnIndex
163
+ };
164
+ setSelectionAreas(function (prev) {
165
+ var _selectionAreaClone$i, _selectionAreaClone$i2;
166
+
167
+ var selectionAreaClone = deepCloneObject(prev);
168
+ var indexOfItemToUpdate = selectionAreaClone.findIndex(function (item) {
169
+ return item.matcher === currentMatcher;
170
+ }); // No items in the array match up with the currentMatcher value
171
+
172
+ if (indexOfItemToUpdate === -1) {
173
+ return prev;
174
+ } // Do not update state if you're still hovering on the same cell
175
+
176
+
177
+ if (((_selectionAreaClone$i = selectionAreaClone[indexOfItemToUpdate].point2) === null || _selectionAreaClone$i === void 0 ? void 0 : _selectionAreaClone$i.row) === cellCoordinates.row && ((_selectionAreaClone$i2 = selectionAreaClone[indexOfItemToUpdate].point2) === null || _selectionAreaClone$i2 === void 0 ? void 0 : _selectionAreaClone$i2.column) === cellCoordinates.column) {
178
+ return prev;
179
+ }
180
+
181
+ selectionAreaClone[indexOfItemToUpdate].point2 = cellCoordinates;
182
+ selectionAreaClone[indexOfItemToUpdate].areaCreated = false;
183
+ return selectionAreaClone;
184
+ });
185
+ }
186
+ }, [clickAndHoldActive, currentMatcher, setSelectionAreas]); // Renders each cell in the spreadsheet body
42
187
 
43
188
  var RenderRow = useCallback(function (_ref2) {
44
189
  var index = _ref2.index,
@@ -65,15 +210,19 @@ export var DataSpreadsheetBody = function DataSpreadsheetBody(_ref) {
65
210
  "data-row-index": cell.row.index,
66
211
  "data-column-index": index
67
212
  }, cell.getCellProps(), {
68
- className: cx("".concat(blockClass, "__td"), "".concat(blockClass, "--interactive-cell-element")),
213
+ className: cx("".concat(blockClass, "__td"), "".concat(blockClass, "__body--td"), "".concat(blockClass, "--interactive-cell-element")),
69
214
  key: "cell_".concat(index),
70
- onClick: function onClick() {
71
- return handleBodyCellClick(cell, index);
215
+ onMouseDown: function onMouseDown(event) {
216
+ return handleBodyCellClick(event, cell, index);
72
217
  },
218
+ onMouseOver: function onMouseOver(event) {
219
+ return handleBodyCellHover(event, cell, index);
220
+ },
221
+ onFocus: function onFocus() {},
73
222
  type: "button"
74
223
  }), cell.render('Cell'));
75
224
  }));
76
- }, [prepareRow, rows, defaultColumn.rowHeaderWidth, handleBodyCellClick]);
225
+ }, [prepareRow, rows, defaultColumn.rowHeaderWidth, handleBodyCellClick, handleBodyCellHover]);
77
226
  var spreadsheetBodyRef = useRef();
78
227
  return /*#__PURE__*/React.createElement("div", _extends({
79
228
  ref: spreadsheetBodyRef,
@@ -87,6 +236,16 @@ export var DataSpreadsheetBody = function DataSpreadsheetBody(_ref) {
87
236
  }, RenderRow));
88
237
  };
89
238
  DataSpreadsheetBody.propTypes = {
239
+ /**
240
+ * Is the user clicking and holding in the data spreadsheet body
241
+ */
242
+ clickAndHoldActive: PropTypes.bool,
243
+
244
+ /**
245
+ * This represents the id of the current cell selection area
246
+ */
247
+ currentMatcher: PropTypes.string,
248
+
90
249
  /**
91
250
  * Default spreadsheet sizing values
92
251
  */
@@ -126,11 +285,36 @@ DataSpreadsheetBody.propTypes = {
126
285
  */
127
286
  scrollBarSize: PropTypes.number,
128
287
 
288
+ /**
289
+ * Array of selection areas
290
+ */
291
+ selectionAreas: PropTypes.array,
292
+
129
293
  /**
130
294
  * Setter fn for activeCellCoordinates state value
131
295
  */
132
296
  setActiveCellCoordinates: PropTypes.func,
133
297
 
298
+ /**
299
+ * Setter fn for clickAndHold state value
300
+ */
301
+ setClickAndHoldActive: PropTypes.func,
302
+
303
+ /**
304
+ * Setter fn for containerHasFocus state value
305
+ */
306
+ setContainerHasFocus: PropTypes.func,
307
+
308
+ /**
309
+ * Setter fn for currentMatcher state value
310
+ */
311
+ setCurrentMatcher: PropTypes.func,
312
+
313
+ /**
314
+ * Setter fn for selectionAreas state value
315
+ */
316
+ setSelectionAreas: PropTypes.func,
317
+
134
318
  /**
135
319
  * The total columns width
136
320
  */
@@ -40,6 +40,6 @@ export var createActiveCellFn = function createActiveCellFn(_ref) {
40
40
  activeCellButton.focus();
41
41
 
42
42
  if (typeof (coords === null || coords === void 0 ? void 0 : coords.column) === 'number' && typeof (coords === null || coords === void 0 ? void 0 : coords.row) === 'number') {
43
- onActiveCellChange(activeCellValue);
43
+ onActiveCellChange === null || onActiveCellChange === void 0 ? void 0 : onActiveCellChange(activeCellValue);
44
44
  }
45
45
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Copyright IBM Corp. 2022, 2022
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 { px } from '@carbon/layout';
8
+ import { deepCloneObject } from '../../global/js/utils/deepCloneObject';
9
+ export var createCellSelectionArea = function createCellSelectionArea(_ref) {
10
+ var area = _ref.area,
11
+ blockClass = _ref.blockClass,
12
+ selectionAreas = _ref.selectionAreas,
13
+ setSelectionAreas = _ref.setSelectionAreas;
14
+ var greatestRow = Math.max(area.point1.row, area.point2.row);
15
+ var greatestColumn = Math.max(area.point1.column, area.point2.column);
16
+ var lowestRowIndex = Math.min(area.point1.row, area.point2.row);
17
+ var lowestColumnIndex = Math.min(area.point1.column, area.point2.column);
18
+ var point1Element = document.querySelector("[data-row-index=\"".concat(area.point1.row, "\"][data-column-index=\"").concat(area.point1.column, "\"]"));
19
+ var selectionAreaCellWidth = point1Element.offsetWidth;
20
+ var selectionAreaCellHeight = point1Element.offsetHeight;
21
+ var selectionAreaTotalWidth = selectionAreaCellWidth * (greatestColumn - lowestColumnIndex + 1);
22
+ var selectionAreaTotalHeight = selectionAreaCellHeight * (greatestRow - lowestRowIndex + 1);
23
+ var bodyContainer = document.querySelector(".".concat(blockClass, "__list--container")).firstElementChild;
24
+ var placementElement = bodyContainer.querySelector("[data-row-index=\"".concat(lowestRowIndex, "\"][data-column-index=\"").concat(lowestColumnIndex, "\"]"));
25
+ var relativePosition = {
26
+ top: placementElement.getBoundingClientRect().top - bodyContainer.getBoundingClientRect().top,
27
+ left: placementElement.getBoundingClientRect().left - bodyContainer.getBoundingClientRect().left
28
+ };
29
+ var selectionAreaElement = document.querySelector("[data-matcher-id=\"".concat(area.matcher, "\"]")) || document.createElement('div');
30
+ selectionAreaElement.classList.add("".concat(blockClass, "__selection-area--element"));
31
+ selectionAreaElement.setAttribute('data-matcher-id', area.matcher);
32
+ selectionAreaElement.style.width = px(selectionAreaTotalWidth);
33
+ selectionAreaElement.style.height = px(selectionAreaTotalHeight);
34
+ selectionAreaElement.style.left = px(relativePosition.left);
35
+ selectionAreaElement.style.top = px(relativePosition.top);
36
+ bodyContainer.appendChild(selectionAreaElement);
37
+ var selectionAreasClone = deepCloneObject(selectionAreas);
38
+ var indexOfCurrentArea = selectionAreasClone.findIndex(function (item) {
39
+ return item.matcher === area.matcher;
40
+ }); // We need to add another property to the selectionAreas object array to
41
+ // let us know if an area has been created for each item already, ie createdArea: true
42
+
43
+ selectionAreasClone[indexOfCurrentArea].areaCreated = true;
44
+ setSelectionAreas(selectionAreasClone);
45
+ };
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/extends";
2
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
4
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
5
- var _excluded = ["cancelDescription", "className", "disabled", "editDescription", "editVisibleOnHoverOnly", "id", "invalid", "invalidText", "labelText", "light", "onCancel", "onSave", "onChange", "placeholder", "saveDescription", "size", "value", "warn", "warnText"];
5
+ var _excluded = ["cancelDescription", "className", "disabled", "editAlwaysVisible", "editDescription", "id", "invalid", "invalidText", "labelText", "light", "onCancel", "onSave", "onChange", "placeholder", "saveDescription", "size", "value", "warn", "warnText"];
6
6
 
7
7
  /**
8
8
  * Copyright IBM Corp. 2022, 2022
@@ -41,8 +41,8 @@ export var InlineEdit = /*#__PURE__*/React.forwardRef(function (_ref, refIn) {
41
41
  var cancelDescription = _ref.cancelDescription,
42
42
  className = _ref.className,
43
43
  disabled = _ref.disabled,
44
+ editAlwaysVisible = _ref.editAlwaysVisible,
44
45
  editDescription = _ref.editDescription,
45
- editVisibleOnHoverOnly = _ref.editVisibleOnHoverOnly,
46
46
  id = _ref.id,
47
47
  invalid = _ref.invalid,
48
48
  invalidText = _ref.invalidText,
@@ -89,6 +89,7 @@ export var InlineEdit = /*#__PURE__*/React.forwardRef(function (_ref, refIn) {
89
89
  };
90
90
 
91
91
  var handleEdit = function handleEdit(ev) {
92
+ /* istanbul ignore else */
92
93
  if (!disabled) {
93
94
  var rightOfInput = ev.currentTarget.classList.contains("".concat(blockClass, "__edit")) || ev.target.classList.contains("".concat(blockClass, "__after-input-elements"));
94
95
  var leftOfInput = ev.currentTarget = ev.target.classList.contains("".concat(blockClass)); // clicking on the content editable element should not set either of these to true
@@ -135,9 +136,12 @@ export var InlineEdit = /*#__PURE__*/React.forwardRef(function (_ref, refIn) {
135
136
  if (onChange) {
136
137
  onChange(refInput.current.innerText);
137
138
  }
138
- };
139
+ }; // pasting into contentEditable not supported by userEvent
140
+
139
141
 
140
- var handlePaste = function handlePaste(ev) {
142
+ var handlePaste =
143
+ /* istanbul ignore next */
144
+ function handlePaste(ev) {
141
145
  ev.preventDefault(); // Get clipboard as plain text
142
146
 
143
147
  var text = (ev.clipboardData || window.clipboardData).getData('text/plain'); // remove \n
@@ -182,9 +186,16 @@ export var InlineEdit = /*#__PURE__*/React.forwardRef(function (_ref, refIn) {
182
186
  };
183
187
 
184
188
  var handleKeyDown = function handleKeyDown(ev) {
185
- if (ev.key === 'Enter') {
186
- ev.preventDefault();
187
- refInput.current.blur(); // will cause save
189
+ switch (ev.key) {
190
+ case 'Enter':
191
+ ev.preventDefault();
192
+ refInput.current.blur(); // will cause save
193
+
194
+ break;
195
+
196
+ case 'Escape':
197
+ handleCancel();
198
+ break;
188
199
  }
189
200
  };
190
201
  /*
@@ -266,7 +277,7 @@ export var InlineEdit = /*#__PURE__*/React.forwardRef(function (_ref, refIn) {
266
277
  disabled: value === internalValue
267
278
  })) : /*#__PURE__*/React.createElement(Button, {
268
279
  "aria-hidden": "true",
269
- className: cx("".concat(blockClass, "__edit"), _defineProperty({}, "".concat(blockClass, "__edit--hover-visible"), editVisibleOnHoverOnly)),
280
+ className: cx("".concat(blockClass, "__edit"), _defineProperty({}, "".concat(blockClass, "__edit--always-visible"), editAlwaysVisible)),
270
281
  kind: "ghost",
271
282
  hasIconOnly: true,
272
283
  iconDescription: editDescription,
@@ -306,15 +317,14 @@ InlineEdit.propTypes = {
306
317
  disabled: PropTypes.bool,
307
318
 
308
319
  /**
309
- * Label for the edit button
320
+ * By default the edit icon is shown on hover only.
310
321
  */
311
- editDescription: PropTypes.string.isRequired,
322
+ editAlwaysVisible: PropTypes.bool,
312
323
 
313
324
  /**
314
- * In some scenarios the edit icon only needs to be shown on hover. These cases are where continual visibility of
315
- * the edit icon is redundant. E.g. a spreadsheet a property panel.
325
+ * Label for the edit button
316
326
  */
317
- editVisibleOnHoverOnly: PropTypes.bool,
327
+ editDescription: PropTypes.string.isRequired,
318
328
 
319
329
  /**
320
330
  * ID for inline edit