@carbon/ibm-products 1.8.0 → 1.9.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 (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