@atlaskit/editor-plugin-insert-block 0.3.0 → 0.3.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atlaskit/editor-plugin-insert-block
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 0.3.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#68670](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/68670) [`801899ef02f2`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/801899ef02f2) - [ux] Added accessibility via keyboard for arrows left, right, up and down
14
+ - Updated dependencies
15
+
3
16
  ## 0.3.0
4
17
 
5
18
  ### Minor Changes
@@ -81,7 +81,8 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
81
81
  isOpenedByKeyboard: false,
82
82
  buttons: [],
83
83
  dropdownItems: [],
84
- isTableSelectorOpen: false
84
+ isTableSelectorOpen: false,
85
+ isTableSelectorOpenedByKeyboard: false
85
86
  });
86
87
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onOpenChange", function (attrs) {
87
88
  var state = {
@@ -211,6 +212,13 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
211
212
  _this.togglePlusMenuVisibility();
212
213
  }
213
214
  });
215
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleTableSelectorOpenByKeyboard", function (event) {
216
+ if (event.key === 'Enter' || event.key === ' ') {
217
+ _this.setState({
218
+ isTableSelectorOpenedByKeyboard: true
219
+ });
220
+ }
221
+ });
214
222
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "toggleLinkPanel", function (inputMethod) {
215
223
  var _pluginInjectionApi$c, _pluginInjectionApi$c2, _pluginInjectionApi$h;
216
224
  var pluginInjectionApi = _this.props.pluginInjectionApi;
@@ -481,6 +489,11 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
481
489
  isOpenedByKeyboard: false
482
490
  }));
483
491
  }
492
+ if (this.state.isTableSelectorOpen) {
493
+ this.setState({
494
+ isTableSelectorOpenedByKeyboard: false
495
+ });
496
+ }
484
497
  }
485
498
  }, {
486
499
  key: "renderPopup",
@@ -522,7 +535,9 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
522
535
  key: "renderTableSelectorPopup",
523
536
  value: function renderTableSelectorPopup() {
524
537
  var _this$tableButtonRef$;
525
- var isTableSelectorOpen = this.state.isTableSelectorOpen;
538
+ var _this$state = this.state,
539
+ isTableSelectorOpen = _this$state.isTableSelectorOpen,
540
+ isTableSelectorOpenedByKeyboard = _this$state.isTableSelectorOpenedByKeyboard;
526
541
  var _this$props13 = this.props,
527
542
  popupsMountPoint = _this$props13.popupsMountPoint,
528
543
  popupsBoundariesElement = _this$props13.popupsBoundariesElement,
@@ -538,7 +553,8 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
538
553
  popupsBoundariesElement: popupsBoundariesElement,
539
554
  popupsScrollableElement: popupsScrollableElement,
540
555
  handleClickOutside: this.handleTableSelectorClickOutside,
541
- handleEscapeKeydown: this.handleTableSelectorPressEscape
556
+ handleEscapeKeydown: this.handleTableSelectorPressEscape,
557
+ isOpenedByKeyboard: isTableSelectorOpenedByKeyboard
542
558
  });
543
559
  }
544
560
  }, {
@@ -560,11 +576,11 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
560
576
  _tableSelectorButton6,
561
577
  _this$props$isDisable,
562
578
  _this$props$replacePl;
563
- var _this$state = this.state,
564
- buttons = _this$state.buttons,
565
- dropdownItems = _this$state.dropdownItems,
566
- emojiPickerOpen = _this$state.emojiPickerOpen,
567
- isTableSelectorOpen = _this$state.isTableSelectorOpen;
579
+ var _this$state2 = this.state,
580
+ buttons = _this$state2.buttons,
581
+ dropdownItems = _this$state2.dropdownItems,
582
+ emojiPickerOpen = _this$state2.emojiPickerOpen,
583
+ isTableSelectorOpen = _this$state2.isTableSelectorOpen;
568
584
  var _this$props14 = this.props,
569
585
  isDisabled = _this$props14.isDisabled,
570
586
  isReducedSpacing = _this$props14.isReducedSpacing;
@@ -649,7 +665,8 @@ var ToolbarInsertBlock = exports.ToolbarInsertBlock = /*#__PURE__*/function (_Re
649
665
  "aria-label": tableSelectorButton ? tableSelectorButton['aria-label'] : undefined,
650
666
  "aria-haspopup": tableSelectorButton ? tableSelectorButton['aria-haspopup'] : undefined,
651
667
  "aria-keyshortcuts": tableSelectorButton ? tableSelectorButton['aria-keyshortcuts'] : undefined,
652
- onItemClick: this.insertToolbarMenuItem
668
+ onItemClick: this.insertToolbarMenuItem,
669
+ onKeyDown: this.handleTableSelectorOpenByKeyboard
653
670
  })), (0, _react2.jsx)("span", {
654
671
  css: _styles.wrapperStyle
655
672
  }, this.renderPopup(), this.renderTableSelectorPopup(), (0, _react2.jsx)(_blockInsertMenu.BlockInsertMenu, {
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.default = exports.TableSelectorPopup = void 0;
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
10
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
11
  var _react = require("react");
11
12
  var _react2 = require("@emotion/react");
@@ -17,8 +18,8 @@ var _colors = require("@atlaskit/theme/colors");
17
18
  var _tableSelectorPopup = _interopRequireWildcard(require("./table-selector-popup"));
18
19
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(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; }
20
- /** @jsx jsx */
21
-
21
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
22
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /** @jsx jsx */
22
23
  var TABLE_SELECTOR_PADDING_TOP = 8;
23
24
  var TABLE_SELECTOR_PADDING_SIDE = 10;
24
25
  var DEFAULT_TABLE_SELECTOR_ROWS = 5;
@@ -26,6 +27,12 @@ var DEFAULT_TABLE_SELECTOR_COLS = 10;
26
27
  var DEFAULT_TABLE_SELECTOR_SELECTION_SIZE = 1;
27
28
  var DEFAULT_MAX_TABLE_SELECTOR_ROWS = 10;
28
29
  var TableSelectorWithListeners = (0, _uiReact.withReactEditorViewOuterListeners)(_tableSelectorPopup.default);
30
+ var initialSizeState = {
31
+ col: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
32
+ row: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
33
+ maxCol: DEFAULT_TABLE_SELECTOR_COLS,
34
+ maxRow: DEFAULT_TABLE_SELECTOR_ROWS
35
+ };
29
36
  var tableSelectorPopupWrapperStyles = (0, _react2.css)({
30
37
  borderRadius: "var(--ds-border-radius, 3px)",
31
38
  backgroundColor: "var(--ds-surface-overlay, ".concat(_colors.N0, ")"),
@@ -33,22 +40,30 @@ var tableSelectorPopupWrapperStyles = (0, _react2.css)({
33
40
  padding: "".concat("var(--ds-space-100, ".concat("".concat(TABLE_SELECTOR_PADDING_TOP, "px"), ")"), " ", TABLE_SELECTOR_PADDING_SIDE, "px")
34
41
  });
35
42
  var TableSelectorPopup = exports.TableSelectorPopup = function TableSelectorPopup(props) {
36
- var _useState = (0, _react.useState)({
37
- col: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
38
- row: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
39
- maxCol: DEFAULT_TABLE_SELECTOR_COLS,
40
- maxRow: DEFAULT_TABLE_SELECTOR_ROWS
41
- }),
43
+ var _useState = (0, _react.useState)(initialSizeState),
42
44
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
43
45
  size = _useState2[0],
44
46
  setSize = _useState2[1];
45
47
  var tablePopupRef = (0, _react.useRef)(null);
48
+ // If popup opened by keyboard enable keyboard mode
49
+ var isKeyboardMode = (0, _react.useRef)(props.isOpenedByKeyboard);
50
+ var enableKeyboardMode = (0, _react.useCallback)(function () {
51
+ if (!isKeyboardMode.current) {
52
+ isKeyboardMode.current = true;
53
+ }
54
+ }, [isKeyboardMode]);
55
+ var disableKeyboardMode = (0, _react.useCallback)(function () {
56
+ if (isKeyboardMode.current) {
57
+ isKeyboardMode.current = false;
58
+ }
59
+ }, [isKeyboardMode]);
46
60
 
47
61
  // Mouse move is used to allow selection changes outside of the popup and is more reactive to changes.
48
62
  var handleMouseMove = (0, _react.useCallback)(function (e) {
49
63
  if (!tablePopupRef.current) {
50
64
  return;
51
65
  }
66
+ disableKeyboardMode();
52
67
  var tablePopup = tablePopupRef.current;
53
68
  var _tablePopup$getBoundi = tablePopup.getBoundingClientRect(),
54
69
  left = _tablePopup$getBoundi.left,
@@ -89,7 +104,110 @@ var TableSelectorPopup = exports.TableSelectorPopup = function TableSelectorPopu
89
104
  maxRow: gridRows
90
105
  });
91
106
  }
92
- }, [size, setSize]);
107
+ }, [disableKeyboardMode, size, setSize]);
108
+ var decreasingSequence = function decreasingSequence(maxNumber, prevNumber) {
109
+ var nextNumber = prevNumber - 1;
110
+ if (prevNumber === 1) {
111
+ nextNumber = maxNumber;
112
+ }
113
+ return nextNumber;
114
+ };
115
+ var getMaxRow = function getMaxRow(prevSize, eventKey) {
116
+ switch (eventKey) {
117
+ case 'ArrowDown':
118
+ // Expand the grid size when last row selected
119
+ if (prevSize.maxRow < DEFAULT_MAX_TABLE_SELECTOR_ROWS && prevSize.row >= DEFAULT_TABLE_SELECTOR_ROWS - 1) {
120
+ return prevSize.maxRow + 1;
121
+ }
122
+ if (prevSize.row === DEFAULT_MAX_TABLE_SELECTOR_ROWS) {
123
+ return DEFAULT_TABLE_SELECTOR_ROWS;
124
+ }
125
+ return prevSize.maxRow;
126
+ case 'ArrowLeft':
127
+ var moveToPrevRow = prevSize.col === 1 && prevSize.row > 1;
128
+ var moveToLastRow = prevSize.row === 1 && prevSize.col === 1;
129
+ // Expand the popup to max size when selected row wraps around to last row
130
+ if (moveToLastRow) {
131
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
132
+ }
133
+ // Decrease the popup when decreased row selection
134
+ if (prevSize.maxRow > DEFAULT_TABLE_SELECTOR_ROWS && moveToPrevRow) {
135
+ return prevSize.row;
136
+ }
137
+ return prevSize.maxRow;
138
+ case 'ArrowUp':
139
+ // const moveToLastRow: boolean = prevSize.row === 1;
140
+ if (prevSize.row === 1) {
141
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
142
+ // Decrease the popup size when decreased row selection
143
+ } else if (prevSize.maxRow > DEFAULT_TABLE_SELECTOR_ROWS) {
144
+ return prevSize.row;
145
+ }
146
+ return prevSize.maxRow;
147
+ default:
148
+ return prevSize.maxRow;
149
+ }
150
+ };
151
+ var handleInitialButtonFocus = (0, _react.useCallback)(function () {
152
+ if (isKeyboardMode.current !== true) {
153
+ enableKeyboardMode();
154
+ setSize(initialSizeState);
155
+ }
156
+ }, [enableKeyboardMode, setSize]);
157
+ var handleKeyDown = (0, _react.useCallback)(function (event) {
158
+ if (event.key === 'ArrowDown') {
159
+ enableKeyboardMode();
160
+ setSize(function (prevSize) {
161
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
162
+ row: prevSize.row % prevSize.maxRow + 1,
163
+ maxRow: getMaxRow(prevSize, event.key)
164
+ });
165
+ });
166
+ }
167
+ if (event.key === 'ArrowRight') {
168
+ enableKeyboardMode();
169
+ setSize(function (prevSize) {
170
+ var moveToNextRow = prevSize.col === DEFAULT_TABLE_SELECTOR_COLS;
171
+ var increaseMaxRow = prevSize.maxRow < DEFAULT_MAX_TABLE_SELECTOR_ROWS && moveToNextRow && prevSize.row + 1 === prevSize.maxRow;
172
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
173
+ col: prevSize.col % DEFAULT_TABLE_SELECTOR_COLS + 1,
174
+ row: moveToNextRow ? prevSize.row % prevSize.maxRow + 1 : prevSize.row,
175
+ maxRow: increaseMaxRow ? prevSize.maxRow + 1 : prevSize.maxRow
176
+ });
177
+ });
178
+ }
179
+ if (event.key === 'ArrowLeft') {
180
+ enableKeyboardMode();
181
+ setSize(function (prevSize) {
182
+ var getRow = function getRow(prevRow, prevCol) {
183
+ var row = prevRow;
184
+ // Move to previous row for wrap around
185
+ if (prevSize.col === 1 && prevSize.row > 1) {
186
+ return prevRow - 1;
187
+ // Increase the selection to max size when selected row and column wraps around
188
+ } else if (prevRow === 1 && prevCol === 1) {
189
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
190
+ }
191
+ return row;
192
+ };
193
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
194
+ col: decreasingSequence(prevSize.maxCol, prevSize.col),
195
+ row: getRow(prevSize.row, prevSize.col),
196
+ maxRow: getMaxRow(prevSize, event.key)
197
+ });
198
+ });
199
+ }
200
+ if (event.key === 'ArrowUp') {
201
+ enableKeyboardMode();
202
+ setSize(function (prevSize) {
203
+ var moveToLastRow = prevSize.row === 1;
204
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
205
+ row: moveToLastRow ? DEFAULT_MAX_TABLE_SELECTOR_ROWS : decreasingSequence(prevSize.maxRow, prevSize.row),
206
+ maxRow: getMaxRow(prevSize, event.key)
207
+ });
208
+ });
209
+ }
210
+ }, [enableKeyboardMode, setSize]);
93
211
  (0, _react.useEffect)(function () {
94
212
  var unbind = (0, _bindEventListener.bind)(window, {
95
213
  type: 'mousemove',
@@ -115,7 +233,10 @@ var TableSelectorPopup = exports.TableSelectorPopup = function TableSelectorPopu
115
233
  maxRows: size.maxRow,
116
234
  onSelection: props.onSelection,
117
235
  selectedCol: size.col,
118
- selectedRow: size.row
236
+ selectedRow: size.row,
237
+ onKeyDown: handleKeyDown,
238
+ isFocused: isKeyboardMode.current,
239
+ handleInitialButtonFocus: handleInitialButtonFocus
119
240
  })));
120
241
  };
121
242
  var _default = exports.default = TableSelectorPopup;
@@ -9,6 +9,7 @@ var _react2 = require("@emotion/react");
9
9
  var _reactIntlNext = require("react-intl-next");
10
10
  var _messages = require("@atlaskit/editor-common/messages");
11
11
  var _primitives = require("@atlaskit/primitives");
12
+ var _colors = require("@atlaskit/theme/colors");
12
13
  /** @jsx jsx */
13
14
 
14
15
  var TABLE_SELECTOR_BUTTON_GAP = exports.TABLE_SELECTOR_BUTTON_GAP = 2;
@@ -25,9 +26,10 @@ var buttonStyles = (0, _react2.css)({
25
26
  borderRadius: '3px',
26
27
  cursor: 'pointer',
27
28
  display: 'block',
28
- '&:hover': {
29
- backgroundColor: "var(--ds-background-accent-blue-subtlest, #579DFF)",
30
- border: "1px solid ".concat("var(--ds-background-accent-blue-subtle, #579DFF)")
29
+ '&:focus': {
30
+ outline: 'none',
31
+ border: "1px solid ".concat("var(--ds-border-focused, ".concat(_colors.B100, ")")),
32
+ boxShadow: "0 0 0 0.5px ".concat("var(--ds-border-focused, ".concat(_colors.B100, ")"))
31
33
  }
32
34
  });
33
35
  var selectionSizeTextStyles = (0, _react2.css)({
@@ -42,13 +44,32 @@ var TableSelectorButton = function TableSelectorButton(_ref) {
42
44
  col = _ref.col,
43
45
  isActive = _ref.isActive,
44
46
  _onClick = _ref.onClick,
45
- label = _ref.label;
47
+ label = _ref.label,
48
+ onKeyDown = _ref.onKeyDown,
49
+ isFocused = _ref.isFocused,
50
+ handleInitialButtonFocus = _ref.handleInitialButtonFocus;
51
+ var btnRef = (0, _react.useRef)(null);
52
+ (0, _react.useEffect)(function () {
53
+ if (btnRef.current) {
54
+ if (isFocused) {
55
+ btnRef.current.focus();
56
+ } else {
57
+ btnRef.current.blur();
58
+ }
59
+ }
60
+ }, [isFocused, btnRef]);
61
+ var handleFocus = col === 1 && row === 1 ? function () {
62
+ return handleInitialButtonFocus();
63
+ } : undefined;
46
64
  return (0, _react2.jsx)("button", {
47
65
  css: [buttonStyles, isActive ? selectedButtonStyles : undefined],
48
66
  onClick: function onClick() {
49
67
  return _onClick(row, col);
50
68
  },
51
- "aria-label": label
69
+ "aria-label": label,
70
+ onKeyDown: onKeyDown,
71
+ ref: btnRef,
72
+ onFocus: handleFocus
52
73
  });
53
74
  };
54
75
  var createArray = function createArray(maxCols, maxRows) {
@@ -79,6 +100,9 @@ var TableSelectorPopup = function TableSelectorPopup(_ref3) {
79
100
  onSelection = _ref3.onSelection,
80
101
  selectedCol = _ref3.selectedCol,
81
102
  selectedRow = _ref3.selectedRow,
103
+ onKeyDown = _ref3.onKeyDown,
104
+ isFocused = _ref3.isFocused,
105
+ handleInitialButtonFocus = _ref3.handleInitialButtonFocus,
82
106
  formatMessage = _ref3.intl.formatMessage;
83
107
  var buttons = (0, _react.useMemo)(function () {
84
108
  return createArray(maxCols, maxRows);
@@ -94,6 +118,7 @@ var TableSelectorPopup = function TableSelectorPopup(_ref3) {
94
118
  }, buttons.map(function (_ref4, index) {
95
119
  var col = _ref4.col,
96
120
  row = _ref4.row;
121
+ var isCurrentFocused = isFocused && selectedCol === col && selectedRow === row;
97
122
  var isActive = selectedCol >= col && selectedRow >= row ? true : false;
98
123
  return (0, _react2.jsx)(TableSelectorButton, {
99
124
  key: index,
@@ -101,7 +126,10 @@ var TableSelectorPopup = function TableSelectorPopup(_ref3) {
101
126
  col: col,
102
127
  row: row,
103
128
  onClick: onSelection,
104
- label: "".concat(formatMessage(_messages.toolbarInsertBlockMessages.tableSizeSelectorButton), " ").concat(row, " x ").concat(col)
129
+ label: "".concat(formatMessage(_messages.toolbarInsertBlockMessages.tableSizeSelectorButton), " ").concat(row, " x ").concat(col),
130
+ onKeyDown: onKeyDown,
131
+ isFocused: isCurrentFocused,
132
+ handleInitialButtonFocus: handleInitialButtonFocus
105
133
  });
106
134
  })), (0, _react2.jsx)("span", {
107
135
  css: selectionSizeTextStyles,
@@ -76,7 +76,8 @@ export class ToolbarInsertBlock extends React.PureComponent {
76
76
  isOpenedByKeyboard: false,
77
77
  buttons: [],
78
78
  dropdownItems: [],
79
- isTableSelectorOpen: false
79
+ isTableSelectorOpen: false,
80
+ isTableSelectorOpenedByKeyboard: false
80
81
  });
81
82
  _defineProperty(this, "onOpenChange", attrs => {
82
83
  const state = {
@@ -209,6 +210,13 @@ export class ToolbarInsertBlock extends React.PureComponent {
209
210
  this.togglePlusMenuVisibility();
210
211
  }
211
212
  });
213
+ _defineProperty(this, "handleTableSelectorOpenByKeyboard", event => {
214
+ if (event.key === 'Enter' || event.key === ' ') {
215
+ this.setState({
216
+ isTableSelectorOpenedByKeyboard: true
217
+ });
218
+ }
219
+ });
212
220
  _defineProperty(this, "toggleLinkPanel", inputMethod => {
213
221
  var _pluginInjectionApi$c, _pluginInjectionApi$c2, _pluginInjectionApi$h;
214
222
  const {
@@ -536,6 +544,11 @@ export class ToolbarInsertBlock extends React.PureComponent {
536
544
  isOpenedByKeyboard: false
537
545
  });
538
546
  }
547
+ if (this.state.isTableSelectorOpen) {
548
+ this.setState({
549
+ isTableSelectorOpenedByKeyboard: false
550
+ });
551
+ }
539
552
  }
540
553
  renderPopup() {
541
554
  const {
@@ -578,7 +591,8 @@ export class ToolbarInsertBlock extends React.PureComponent {
578
591
  renderTableSelectorPopup() {
579
592
  var _this$tableButtonRef$;
580
593
  const {
581
- isTableSelectorOpen
594
+ isTableSelectorOpen,
595
+ isTableSelectorOpenedByKeyboard
582
596
  } = this.state;
583
597
  const {
584
598
  popupsMountPoint,
@@ -596,7 +610,8 @@ export class ToolbarInsertBlock extends React.PureComponent {
596
610
  popupsBoundariesElement: popupsBoundariesElement,
597
611
  popupsScrollableElement: popupsScrollableElement,
598
612
  handleClickOutside: this.handleTableSelectorClickOutside,
599
- handleEscapeKeydown: this.handleTableSelectorPressEscape
613
+ handleEscapeKeydown: this.handleTableSelectorPressEscape,
614
+ isOpenedByKeyboard: isTableSelectorOpenedByKeyboard
600
615
  });
601
616
  }
602
617
  render() {
@@ -683,7 +698,8 @@ export class ToolbarInsertBlock extends React.PureComponent {
683
698
  "aria-label": tableSelectorButton ? tableSelectorButton['aria-label'] : undefined,
684
699
  "aria-haspopup": tableSelectorButton ? tableSelectorButton['aria-haspopup'] : undefined,
685
700
  "aria-keyshortcuts": tableSelectorButton ? tableSelectorButton['aria-keyshortcuts'] : undefined,
686
- onItemClick: this.insertToolbarMenuItem
701
+ onItemClick: this.insertToolbarMenuItem,
702
+ onKeyDown: this.handleTableSelectorOpenByKeyboard
687
703
  })), jsx("span", {
688
704
  css: wrapperStyle
689
705
  }, this.renderPopup(), this.renderTableSelectorPopup(), jsx(BlockInsertMenu, {
@@ -15,6 +15,12 @@ const DEFAULT_TABLE_SELECTOR_COLS = 10;
15
15
  const DEFAULT_TABLE_SELECTOR_SELECTION_SIZE = 1;
16
16
  const DEFAULT_MAX_TABLE_SELECTOR_ROWS = 10;
17
17
  const TableSelectorWithListeners = withOuterListeners(tableSelectorPopup);
18
+ const initialSizeState = {
19
+ col: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
20
+ row: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
21
+ maxCol: DEFAULT_TABLE_SELECTOR_COLS,
22
+ maxRow: DEFAULT_TABLE_SELECTOR_ROWS
23
+ };
18
24
  const tableSelectorPopupWrapperStyles = css({
19
25
  borderRadius: "var(--ds-border-radius, 3px)",
20
26
  backgroundColor: `var(--ds-surface-overlay, ${N0})`,
@@ -22,19 +28,27 @@ const tableSelectorPopupWrapperStyles = css({
22
28
  padding: `${`var(--ds-space-100, ${`${TABLE_SELECTOR_PADDING_TOP}px`})`} ${TABLE_SELECTOR_PADDING_SIDE}px`
23
29
  });
24
30
  export const TableSelectorPopup = props => {
25
- const [size, setSize] = useState({
26
- col: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
27
- row: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
28
- maxCol: DEFAULT_TABLE_SELECTOR_COLS,
29
- maxRow: DEFAULT_TABLE_SELECTOR_ROWS
30
- });
31
+ const [size, setSize] = useState(initialSizeState);
31
32
  const tablePopupRef = useRef(null);
33
+ // If popup opened by keyboard enable keyboard mode
34
+ const isKeyboardMode = useRef(props.isOpenedByKeyboard);
35
+ const enableKeyboardMode = useCallback(() => {
36
+ if (!isKeyboardMode.current) {
37
+ isKeyboardMode.current = true;
38
+ }
39
+ }, [isKeyboardMode]);
40
+ const disableKeyboardMode = useCallback(() => {
41
+ if (isKeyboardMode.current) {
42
+ isKeyboardMode.current = false;
43
+ }
44
+ }, [isKeyboardMode]);
32
45
 
33
46
  // Mouse move is used to allow selection changes outside of the popup and is more reactive to changes.
34
47
  const handleMouseMove = useCallback(e => {
35
48
  if (!tablePopupRef.current) {
36
49
  return;
37
50
  }
51
+ disableKeyboardMode();
38
52
  const tablePopup = tablePopupRef.current;
39
53
  const {
40
54
  left,
@@ -76,7 +90,114 @@ export const TableSelectorPopup = props => {
76
90
  maxRow: gridRows
77
91
  });
78
92
  }
79
- }, [size, setSize]);
93
+ }, [disableKeyboardMode, size, setSize]);
94
+ const decreasingSequence = (maxNumber, prevNumber) => {
95
+ let nextNumber = prevNumber - 1;
96
+ if (prevNumber === 1) {
97
+ nextNumber = maxNumber;
98
+ }
99
+ return nextNumber;
100
+ };
101
+ const getMaxRow = (prevSize, eventKey) => {
102
+ switch (eventKey) {
103
+ case 'ArrowDown':
104
+ // Expand the grid size when last row selected
105
+ if (prevSize.maxRow < DEFAULT_MAX_TABLE_SELECTOR_ROWS && prevSize.row >= DEFAULT_TABLE_SELECTOR_ROWS - 1) {
106
+ return prevSize.maxRow + 1;
107
+ }
108
+ if (prevSize.row === DEFAULT_MAX_TABLE_SELECTOR_ROWS) {
109
+ return DEFAULT_TABLE_SELECTOR_ROWS;
110
+ }
111
+ return prevSize.maxRow;
112
+ case 'ArrowLeft':
113
+ const moveToPrevRow = prevSize.col === 1 && prevSize.row > 1;
114
+ const moveToLastRow = prevSize.row === 1 && prevSize.col === 1;
115
+ // Expand the popup to max size when selected row wraps around to last row
116
+ if (moveToLastRow) {
117
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
118
+ }
119
+ // Decrease the popup when decreased row selection
120
+ if (prevSize.maxRow > DEFAULT_TABLE_SELECTOR_ROWS && moveToPrevRow) {
121
+ return prevSize.row;
122
+ }
123
+ return prevSize.maxRow;
124
+ case 'ArrowUp':
125
+ // const moveToLastRow: boolean = prevSize.row === 1;
126
+ if (prevSize.row === 1) {
127
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
128
+ // Decrease the popup size when decreased row selection
129
+ } else if (prevSize.maxRow > DEFAULT_TABLE_SELECTOR_ROWS) {
130
+ return prevSize.row;
131
+ }
132
+ return prevSize.maxRow;
133
+ default:
134
+ return prevSize.maxRow;
135
+ }
136
+ };
137
+ const handleInitialButtonFocus = useCallback(() => {
138
+ if (isKeyboardMode.current !== true) {
139
+ enableKeyboardMode();
140
+ setSize(initialSizeState);
141
+ }
142
+ }, [enableKeyboardMode, setSize]);
143
+ const handleKeyDown = useCallback(event => {
144
+ if (event.key === 'ArrowDown') {
145
+ enableKeyboardMode();
146
+ setSize(prevSize => {
147
+ return {
148
+ ...prevSize,
149
+ row: prevSize.row % prevSize.maxRow + 1,
150
+ maxRow: getMaxRow(prevSize, event.key)
151
+ };
152
+ });
153
+ }
154
+ if (event.key === 'ArrowRight') {
155
+ enableKeyboardMode();
156
+ setSize(prevSize => {
157
+ const moveToNextRow = prevSize.col === DEFAULT_TABLE_SELECTOR_COLS;
158
+ const increaseMaxRow = prevSize.maxRow < DEFAULT_MAX_TABLE_SELECTOR_ROWS && moveToNextRow && prevSize.row + 1 === prevSize.maxRow;
159
+ return {
160
+ ...prevSize,
161
+ col: prevSize.col % DEFAULT_TABLE_SELECTOR_COLS + 1,
162
+ row: moveToNextRow ? prevSize.row % prevSize.maxRow + 1 : prevSize.row,
163
+ maxRow: increaseMaxRow ? prevSize.maxRow + 1 : prevSize.maxRow
164
+ };
165
+ });
166
+ }
167
+ if (event.key === 'ArrowLeft') {
168
+ enableKeyboardMode();
169
+ setSize(prevSize => {
170
+ const getRow = (prevRow, prevCol) => {
171
+ let row = prevRow;
172
+ // Move to previous row for wrap around
173
+ if (prevSize.col === 1 && prevSize.row > 1) {
174
+ return prevRow - 1;
175
+ // Increase the selection to max size when selected row and column wraps around
176
+ } else if (prevRow === 1 && prevCol === 1) {
177
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
178
+ }
179
+ return row;
180
+ };
181
+ return {
182
+ ...prevSize,
183
+ col: decreasingSequence(prevSize.maxCol, prevSize.col),
184
+ row: getRow(prevSize.row, prevSize.col),
185
+ maxRow: getMaxRow(prevSize, event.key)
186
+ };
187
+ });
188
+ }
189
+ if (event.key === 'ArrowUp') {
190
+ enableKeyboardMode();
191
+ setSize(prevSize => {
192
+ const moveToLastRow = prevSize.row === 1;
193
+ return {
194
+ ...prevSize,
195
+ row: moveToLastRow ? DEFAULT_MAX_TABLE_SELECTOR_ROWS : decreasingSequence(prevSize.maxRow, prevSize.row),
196
+ maxRow: getMaxRow(prevSize, event.key)
197
+ };
198
+ });
199
+ }
200
+ }, [enableKeyboardMode, setSize]);
80
201
  useEffect(() => {
81
202
  const unbind = bind(window, {
82
203
  type: 'mousemove',
@@ -102,7 +223,10 @@ export const TableSelectorPopup = props => {
102
223
  maxRows: size.maxRow,
103
224
  onSelection: props.onSelection,
104
225
  selectedCol: size.col,
105
- selectedRow: size.row
226
+ selectedRow: size.row,
227
+ onKeyDown: handleKeyDown,
228
+ isFocused: isKeyboardMode.current,
229
+ handleInitialButtonFocus: handleInitialButtonFocus
106
230
  })));
107
231
  };
108
232
  export default TableSelectorPopup;
@@ -1,9 +1,10 @@
1
1
  /** @jsx jsx */
2
- import { useMemo } from 'react';
2
+ import { useEffect, useMemo, useRef } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
4
  import { injectIntl } from 'react-intl-next';
5
5
  import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import { Stack } from '@atlaskit/primitives';
7
+ import { B100 } from '@atlaskit/theme/colors';
7
8
  export const TABLE_SELECTOR_BUTTON_GAP = 2;
8
9
  export const TABLE_SELECTOR_BUTTON_SIZE = 17;
9
10
  const selectedButtonStyles = css({
@@ -18,9 +19,10 @@ const buttonStyles = css({
18
19
  borderRadius: '3px',
19
20
  cursor: 'pointer',
20
21
  display: 'block',
21
- '&:hover': {
22
- backgroundColor: "var(--ds-background-accent-blue-subtlest, #579DFF)",
23
- border: `1px solid ${"var(--ds-background-accent-blue-subtle, #579DFF)"}`
22
+ '&:focus': {
23
+ outline: 'none',
24
+ border: `1px solid ${`var(--ds-border-focused, ${B100})`}`,
25
+ boxShadow: `0 0 0 0.5px ${`var(--ds-border-focused, ${B100})`}`
24
26
  }
25
27
  });
26
28
  const selectionSizeTextStyles = css({
@@ -35,12 +37,29 @@ const TableSelectorButton = ({
35
37
  col,
36
38
  isActive,
37
39
  onClick,
38
- label
40
+ label,
41
+ onKeyDown,
42
+ isFocused,
43
+ handleInitialButtonFocus
39
44
  }) => {
45
+ const btnRef = useRef(null);
46
+ useEffect(() => {
47
+ if (btnRef.current) {
48
+ if (isFocused) {
49
+ btnRef.current.focus();
50
+ } else {
51
+ btnRef.current.blur();
52
+ }
53
+ }
54
+ }, [isFocused, btnRef]);
55
+ const handleFocus = col === 1 && row === 1 ? () => handleInitialButtonFocus() : undefined;
40
56
  return jsx("button", {
41
57
  css: [buttonStyles, isActive ? selectedButtonStyles : undefined],
42
58
  onClick: () => onClick(row, col),
43
- "aria-label": label
59
+ "aria-label": label,
60
+ onKeyDown: onKeyDown,
61
+ ref: btnRef,
62
+ onFocus: handleFocus
44
63
  });
45
64
  };
46
65
  const createArray = (maxCols, maxRows) => {
@@ -70,6 +89,9 @@ const TableSelectorPopup = ({
70
89
  onSelection,
71
90
  selectedCol,
72
91
  selectedRow,
92
+ onKeyDown,
93
+ isFocused,
94
+ handleInitialButtonFocus,
73
95
  intl: {
74
96
  formatMessage
75
97
  }
@@ -89,6 +111,7 @@ const TableSelectorPopup = ({
89
111
  col,
90
112
  row
91
113
  }, index) => {
114
+ const isCurrentFocused = isFocused && selectedCol === col && selectedRow === row;
92
115
  const isActive = selectedCol >= col && selectedRow >= row ? true : false;
93
116
  return jsx(TableSelectorButton, {
94
117
  key: index,
@@ -96,7 +119,10 @@ const TableSelectorPopup = ({
96
119
  col: col,
97
120
  row: row,
98
121
  onClick: onSelection,
99
- label: `${formatMessage(messages.tableSizeSelectorButton)} ${row} x ${col}`
122
+ label: `${formatMessage(messages.tableSizeSelectorButton)} ${row} x ${col}`,
123
+ onKeyDown: onKeyDown,
124
+ isFocused: isCurrentFocused,
125
+ handleInitialButtonFocus: handleInitialButtonFocus
100
126
  });
101
127
  })), jsx("span", {
102
128
  css: selectionSizeTextStyles,
@@ -71,7 +71,8 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
71
71
  isOpenedByKeyboard: false,
72
72
  buttons: [],
73
73
  dropdownItems: [],
74
- isTableSelectorOpen: false
74
+ isTableSelectorOpen: false,
75
+ isTableSelectorOpenedByKeyboard: false
75
76
  });
76
77
  _defineProperty(_assertThisInitialized(_this), "onOpenChange", function (attrs) {
77
78
  var state = {
@@ -201,6 +202,13 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
201
202
  _this.togglePlusMenuVisibility();
202
203
  }
203
204
  });
205
+ _defineProperty(_assertThisInitialized(_this), "handleTableSelectorOpenByKeyboard", function (event) {
206
+ if (event.key === 'Enter' || event.key === ' ') {
207
+ _this.setState({
208
+ isTableSelectorOpenedByKeyboard: true
209
+ });
210
+ }
211
+ });
204
212
  _defineProperty(_assertThisInitialized(_this), "toggleLinkPanel", function (inputMethod) {
205
213
  var _pluginInjectionApi$c, _pluginInjectionApi$c2, _pluginInjectionApi$h;
206
214
  var pluginInjectionApi = _this.props.pluginInjectionApi;
@@ -471,6 +479,11 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
471
479
  isOpenedByKeyboard: false
472
480
  }));
473
481
  }
482
+ if (this.state.isTableSelectorOpen) {
483
+ this.setState({
484
+ isTableSelectorOpenedByKeyboard: false
485
+ });
486
+ }
474
487
  }
475
488
  }, {
476
489
  key: "renderPopup",
@@ -512,7 +525,9 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
512
525
  key: "renderTableSelectorPopup",
513
526
  value: function renderTableSelectorPopup() {
514
527
  var _this$tableButtonRef$;
515
- var isTableSelectorOpen = this.state.isTableSelectorOpen;
528
+ var _this$state = this.state,
529
+ isTableSelectorOpen = _this$state.isTableSelectorOpen,
530
+ isTableSelectorOpenedByKeyboard = _this$state.isTableSelectorOpenedByKeyboard;
516
531
  var _this$props13 = this.props,
517
532
  popupsMountPoint = _this$props13.popupsMountPoint,
518
533
  popupsBoundariesElement = _this$props13.popupsBoundariesElement,
@@ -528,7 +543,8 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
528
543
  popupsBoundariesElement: popupsBoundariesElement,
529
544
  popupsScrollableElement: popupsScrollableElement,
530
545
  handleClickOutside: this.handleTableSelectorClickOutside,
531
- handleEscapeKeydown: this.handleTableSelectorPressEscape
546
+ handleEscapeKeydown: this.handleTableSelectorPressEscape,
547
+ isOpenedByKeyboard: isTableSelectorOpenedByKeyboard
532
548
  });
533
549
  }
534
550
  }, {
@@ -550,11 +566,11 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
550
566
  _tableSelectorButton6,
551
567
  _this$props$isDisable,
552
568
  _this$props$replacePl;
553
- var _this$state = this.state,
554
- buttons = _this$state.buttons,
555
- dropdownItems = _this$state.dropdownItems,
556
- emojiPickerOpen = _this$state.emojiPickerOpen,
557
- isTableSelectorOpen = _this$state.isTableSelectorOpen;
569
+ var _this$state2 = this.state,
570
+ buttons = _this$state2.buttons,
571
+ dropdownItems = _this$state2.dropdownItems,
572
+ emojiPickerOpen = _this$state2.emojiPickerOpen,
573
+ isTableSelectorOpen = _this$state2.isTableSelectorOpen;
558
574
  var _this$props14 = this.props,
559
575
  isDisabled = _this$props14.isDisabled,
560
576
  isReducedSpacing = _this$props14.isReducedSpacing;
@@ -639,7 +655,8 @@ export var ToolbarInsertBlock = /*#__PURE__*/function (_React$PureComponent) {
639
655
  "aria-label": tableSelectorButton ? tableSelectorButton['aria-label'] : undefined,
640
656
  "aria-haspopup": tableSelectorButton ? tableSelectorButton['aria-haspopup'] : undefined,
641
657
  "aria-keyshortcuts": tableSelectorButton ? tableSelectorButton['aria-keyshortcuts'] : undefined,
642
- onItemClick: this.insertToolbarMenuItem
658
+ onItemClick: this.insertToolbarMenuItem,
659
+ onKeyDown: this.handleTableSelectorOpenByKeyboard
643
660
  })), jsx("span", {
644
661
  css: wrapperStyle
645
662
  }, this.renderPopup(), this.renderTableSelectorPopup(), jsx(BlockInsertMenu, {
@@ -1,4 +1,7 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
1
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
5
  /** @jsx jsx */
3
6
 
4
7
  import { useCallback, useEffect, useRef, useState } from 'react';
@@ -16,6 +19,12 @@ var DEFAULT_TABLE_SELECTOR_COLS = 10;
16
19
  var DEFAULT_TABLE_SELECTOR_SELECTION_SIZE = 1;
17
20
  var DEFAULT_MAX_TABLE_SELECTOR_ROWS = 10;
18
21
  var TableSelectorWithListeners = withOuterListeners(tableSelectorPopup);
22
+ var initialSizeState = {
23
+ col: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
24
+ row: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
25
+ maxCol: DEFAULT_TABLE_SELECTOR_COLS,
26
+ maxRow: DEFAULT_TABLE_SELECTOR_ROWS
27
+ };
19
28
  var tableSelectorPopupWrapperStyles = css({
20
29
  borderRadius: "var(--ds-border-radius, 3px)",
21
30
  backgroundColor: "var(--ds-surface-overlay, ".concat(N0, ")"),
@@ -23,22 +32,30 @@ var tableSelectorPopupWrapperStyles = css({
23
32
  padding: "".concat("var(--ds-space-100, ".concat("".concat(TABLE_SELECTOR_PADDING_TOP, "px"), ")"), " ", TABLE_SELECTOR_PADDING_SIDE, "px")
24
33
  });
25
34
  export var TableSelectorPopup = function TableSelectorPopup(props) {
26
- var _useState = useState({
27
- col: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
28
- row: DEFAULT_TABLE_SELECTOR_SELECTION_SIZE,
29
- maxCol: DEFAULT_TABLE_SELECTOR_COLS,
30
- maxRow: DEFAULT_TABLE_SELECTOR_ROWS
31
- }),
35
+ var _useState = useState(initialSizeState),
32
36
  _useState2 = _slicedToArray(_useState, 2),
33
37
  size = _useState2[0],
34
38
  setSize = _useState2[1];
35
39
  var tablePopupRef = useRef(null);
40
+ // If popup opened by keyboard enable keyboard mode
41
+ var isKeyboardMode = useRef(props.isOpenedByKeyboard);
42
+ var enableKeyboardMode = useCallback(function () {
43
+ if (!isKeyboardMode.current) {
44
+ isKeyboardMode.current = true;
45
+ }
46
+ }, [isKeyboardMode]);
47
+ var disableKeyboardMode = useCallback(function () {
48
+ if (isKeyboardMode.current) {
49
+ isKeyboardMode.current = false;
50
+ }
51
+ }, [isKeyboardMode]);
36
52
 
37
53
  // Mouse move is used to allow selection changes outside of the popup and is more reactive to changes.
38
54
  var handleMouseMove = useCallback(function (e) {
39
55
  if (!tablePopupRef.current) {
40
56
  return;
41
57
  }
58
+ disableKeyboardMode();
42
59
  var tablePopup = tablePopupRef.current;
43
60
  var _tablePopup$getBoundi = tablePopup.getBoundingClientRect(),
44
61
  left = _tablePopup$getBoundi.left,
@@ -79,7 +96,110 @@ export var TableSelectorPopup = function TableSelectorPopup(props) {
79
96
  maxRow: gridRows
80
97
  });
81
98
  }
82
- }, [size, setSize]);
99
+ }, [disableKeyboardMode, size, setSize]);
100
+ var decreasingSequence = function decreasingSequence(maxNumber, prevNumber) {
101
+ var nextNumber = prevNumber - 1;
102
+ if (prevNumber === 1) {
103
+ nextNumber = maxNumber;
104
+ }
105
+ return nextNumber;
106
+ };
107
+ var getMaxRow = function getMaxRow(prevSize, eventKey) {
108
+ switch (eventKey) {
109
+ case 'ArrowDown':
110
+ // Expand the grid size when last row selected
111
+ if (prevSize.maxRow < DEFAULT_MAX_TABLE_SELECTOR_ROWS && prevSize.row >= DEFAULT_TABLE_SELECTOR_ROWS - 1) {
112
+ return prevSize.maxRow + 1;
113
+ }
114
+ if (prevSize.row === DEFAULT_MAX_TABLE_SELECTOR_ROWS) {
115
+ return DEFAULT_TABLE_SELECTOR_ROWS;
116
+ }
117
+ return prevSize.maxRow;
118
+ case 'ArrowLeft':
119
+ var moveToPrevRow = prevSize.col === 1 && prevSize.row > 1;
120
+ var moveToLastRow = prevSize.row === 1 && prevSize.col === 1;
121
+ // Expand the popup to max size when selected row wraps around to last row
122
+ if (moveToLastRow) {
123
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
124
+ }
125
+ // Decrease the popup when decreased row selection
126
+ if (prevSize.maxRow > DEFAULT_TABLE_SELECTOR_ROWS && moveToPrevRow) {
127
+ return prevSize.row;
128
+ }
129
+ return prevSize.maxRow;
130
+ case 'ArrowUp':
131
+ // const moveToLastRow: boolean = prevSize.row === 1;
132
+ if (prevSize.row === 1) {
133
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
134
+ // Decrease the popup size when decreased row selection
135
+ } else if (prevSize.maxRow > DEFAULT_TABLE_SELECTOR_ROWS) {
136
+ return prevSize.row;
137
+ }
138
+ return prevSize.maxRow;
139
+ default:
140
+ return prevSize.maxRow;
141
+ }
142
+ };
143
+ var handleInitialButtonFocus = useCallback(function () {
144
+ if (isKeyboardMode.current !== true) {
145
+ enableKeyboardMode();
146
+ setSize(initialSizeState);
147
+ }
148
+ }, [enableKeyboardMode, setSize]);
149
+ var handleKeyDown = useCallback(function (event) {
150
+ if (event.key === 'ArrowDown') {
151
+ enableKeyboardMode();
152
+ setSize(function (prevSize) {
153
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
154
+ row: prevSize.row % prevSize.maxRow + 1,
155
+ maxRow: getMaxRow(prevSize, event.key)
156
+ });
157
+ });
158
+ }
159
+ if (event.key === 'ArrowRight') {
160
+ enableKeyboardMode();
161
+ setSize(function (prevSize) {
162
+ var moveToNextRow = prevSize.col === DEFAULT_TABLE_SELECTOR_COLS;
163
+ var increaseMaxRow = prevSize.maxRow < DEFAULT_MAX_TABLE_SELECTOR_ROWS && moveToNextRow && prevSize.row + 1 === prevSize.maxRow;
164
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
165
+ col: prevSize.col % DEFAULT_TABLE_SELECTOR_COLS + 1,
166
+ row: moveToNextRow ? prevSize.row % prevSize.maxRow + 1 : prevSize.row,
167
+ maxRow: increaseMaxRow ? prevSize.maxRow + 1 : prevSize.maxRow
168
+ });
169
+ });
170
+ }
171
+ if (event.key === 'ArrowLeft') {
172
+ enableKeyboardMode();
173
+ setSize(function (prevSize) {
174
+ var getRow = function getRow(prevRow, prevCol) {
175
+ var row = prevRow;
176
+ // Move to previous row for wrap around
177
+ if (prevSize.col === 1 && prevSize.row > 1) {
178
+ return prevRow - 1;
179
+ // Increase the selection to max size when selected row and column wraps around
180
+ } else if (prevRow === 1 && prevCol === 1) {
181
+ return DEFAULT_MAX_TABLE_SELECTOR_ROWS;
182
+ }
183
+ return row;
184
+ };
185
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
186
+ col: decreasingSequence(prevSize.maxCol, prevSize.col),
187
+ row: getRow(prevSize.row, prevSize.col),
188
+ maxRow: getMaxRow(prevSize, event.key)
189
+ });
190
+ });
191
+ }
192
+ if (event.key === 'ArrowUp') {
193
+ enableKeyboardMode();
194
+ setSize(function (prevSize) {
195
+ var moveToLastRow = prevSize.row === 1;
196
+ return _objectSpread(_objectSpread({}, prevSize), {}, {
197
+ row: moveToLastRow ? DEFAULT_MAX_TABLE_SELECTOR_ROWS : decreasingSequence(prevSize.maxRow, prevSize.row),
198
+ maxRow: getMaxRow(prevSize, event.key)
199
+ });
200
+ });
201
+ }
202
+ }, [enableKeyboardMode, setSize]);
83
203
  useEffect(function () {
84
204
  var unbind = bind(window, {
85
205
  type: 'mousemove',
@@ -105,7 +225,10 @@ export var TableSelectorPopup = function TableSelectorPopup(props) {
105
225
  maxRows: size.maxRow,
106
226
  onSelection: props.onSelection,
107
227
  selectedCol: size.col,
108
- selectedRow: size.row
228
+ selectedRow: size.row,
229
+ onKeyDown: handleKeyDown,
230
+ isFocused: isKeyboardMode.current,
231
+ handleInitialButtonFocus: handleInitialButtonFocus
109
232
  })));
110
233
  };
111
234
  export default TableSelectorPopup;
@@ -1,9 +1,10 @@
1
1
  /** @jsx jsx */
2
- import { useMemo } from 'react';
2
+ import { useEffect, useMemo, useRef } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
4
  import { injectIntl } from 'react-intl-next';
5
5
  import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import { Stack } from '@atlaskit/primitives';
7
+ import { B100 } from '@atlaskit/theme/colors';
7
8
  export var TABLE_SELECTOR_BUTTON_GAP = 2;
8
9
  export var TABLE_SELECTOR_BUTTON_SIZE = 17;
9
10
  var selectedButtonStyles = css({
@@ -18,9 +19,10 @@ var buttonStyles = css({
18
19
  borderRadius: '3px',
19
20
  cursor: 'pointer',
20
21
  display: 'block',
21
- '&:hover': {
22
- backgroundColor: "var(--ds-background-accent-blue-subtlest, #579DFF)",
23
- border: "1px solid ".concat("var(--ds-background-accent-blue-subtle, #579DFF)")
22
+ '&:focus': {
23
+ outline: 'none',
24
+ border: "1px solid ".concat("var(--ds-border-focused, ".concat(B100, ")")),
25
+ boxShadow: "0 0 0 0.5px ".concat("var(--ds-border-focused, ".concat(B100, ")"))
24
26
  }
25
27
  });
26
28
  var selectionSizeTextStyles = css({
@@ -35,13 +37,32 @@ var TableSelectorButton = function TableSelectorButton(_ref) {
35
37
  col = _ref.col,
36
38
  isActive = _ref.isActive,
37
39
  _onClick = _ref.onClick,
38
- label = _ref.label;
40
+ label = _ref.label,
41
+ onKeyDown = _ref.onKeyDown,
42
+ isFocused = _ref.isFocused,
43
+ handleInitialButtonFocus = _ref.handleInitialButtonFocus;
44
+ var btnRef = useRef(null);
45
+ useEffect(function () {
46
+ if (btnRef.current) {
47
+ if (isFocused) {
48
+ btnRef.current.focus();
49
+ } else {
50
+ btnRef.current.blur();
51
+ }
52
+ }
53
+ }, [isFocused, btnRef]);
54
+ var handleFocus = col === 1 && row === 1 ? function () {
55
+ return handleInitialButtonFocus();
56
+ } : undefined;
39
57
  return jsx("button", {
40
58
  css: [buttonStyles, isActive ? selectedButtonStyles : undefined],
41
59
  onClick: function onClick() {
42
60
  return _onClick(row, col);
43
61
  },
44
- "aria-label": label
62
+ "aria-label": label,
63
+ onKeyDown: onKeyDown,
64
+ ref: btnRef,
65
+ onFocus: handleFocus
45
66
  });
46
67
  };
47
68
  var createArray = function createArray(maxCols, maxRows) {
@@ -72,6 +93,9 @@ var TableSelectorPopup = function TableSelectorPopup(_ref3) {
72
93
  onSelection = _ref3.onSelection,
73
94
  selectedCol = _ref3.selectedCol,
74
95
  selectedRow = _ref3.selectedRow,
96
+ onKeyDown = _ref3.onKeyDown,
97
+ isFocused = _ref3.isFocused,
98
+ handleInitialButtonFocus = _ref3.handleInitialButtonFocus,
75
99
  formatMessage = _ref3.intl.formatMessage;
76
100
  var buttons = useMemo(function () {
77
101
  return createArray(maxCols, maxRows);
@@ -87,6 +111,7 @@ var TableSelectorPopup = function TableSelectorPopup(_ref3) {
87
111
  }, buttons.map(function (_ref4, index) {
88
112
  var col = _ref4.col,
89
113
  row = _ref4.row;
114
+ var isCurrentFocused = isFocused && selectedCol === col && selectedRow === row;
90
115
  var isActive = selectedCol >= col && selectedRow >= row ? true : false;
91
116
  return jsx(TableSelectorButton, {
92
117
  key: index,
@@ -94,7 +119,10 @@ var TableSelectorPopup = function TableSelectorPopup(_ref3) {
94
119
  col: col,
95
120
  row: row,
96
121
  onClick: onSelection,
97
- label: "".concat(formatMessage(messages.tableSizeSelectorButton), " ").concat(row, " x ").concat(col)
122
+ label: "".concat(formatMessage(messages.tableSizeSelectorButton), " ").concat(row, " x ").concat(col),
123
+ onKeyDown: onKeyDown,
124
+ isFocused: isCurrentFocused,
125
+ handleInitialButtonFocus: handleInitialButtonFocus
98
126
  });
99
127
  })), jsx("span", {
100
128
  css: selectionSizeTextStyles,
@@ -33,6 +33,7 @@ export declare class ToolbarInsertBlock extends React.PureComponent<Props & Wrap
33
33
  render(): jsx.JSX.Element | null;
34
34
  private handleClick;
35
35
  private handleOpenByKeyboard;
36
+ private handleTableSelectorOpenByKeyboard;
36
37
  private toggleLinkPanel;
37
38
  private insertMention;
38
39
  private insertTable;
@@ -10,6 +10,7 @@ export interface TableSelectorPopupProps {
10
10
  popupsScrollableElement?: HTMLElement;
11
11
  handleClickOutside?: SimpleEventHandler<MouseEvent>;
12
12
  handleEscapeKeydown?: SimpleEventHandler<KeyboardEvent>;
13
+ isOpenedByKeyboard: boolean;
13
14
  }
14
15
  export declare const TableSelectorPopup: (props: TableSelectorPopupProps) => jsx.JSX.Element;
15
16
  export default TableSelectorPopup;
@@ -1,4 +1,4 @@
1
- import type { SyntheticEvent } from 'react';
1
+ import type { KeyboardEventHandler, SyntheticEvent } from 'react';
2
2
  import type { WrappedComponentProps } from 'react-intl-next';
3
3
  export declare const TABLE_SELECTOR_BUTTON_GAP = 2;
4
4
  export declare const TABLE_SELECTOR_BUTTON_SIZE = 17;
@@ -8,6 +8,9 @@ export interface TableSelectorButtonProps {
8
8
  isActive: boolean;
9
9
  onClick: OnTableSizeSelection;
10
10
  label: string;
11
+ onKeyDown: KeyboardEventHandler<HTMLButtonElement>;
12
+ isFocused: boolean;
13
+ handleInitialButtonFocus: () => void;
11
14
  }
12
15
  export interface OnTableSizeSelection {
13
16
  (rowsCount: number, colsCount: number, event?: SyntheticEvent): void;
@@ -18,6 +21,9 @@ interface TableSelectorPopupProps {
18
21
  onSelection: OnTableSizeSelection;
19
22
  selectedCol: number;
20
23
  selectedRow: number;
24
+ onKeyDown: KeyboardEventHandler<HTMLButtonElement>;
25
+ isFocused: boolean;
26
+ handleInitialButtonFocus: () => void;
21
27
  }
22
28
  declare const _default: import("react").FC<import("react-intl-next").WithIntlProps<TableSelectorPopupProps & WrappedComponentProps<"intl">>> & {
23
29
  WrappedComponent: import("react").ComponentType<TableSelectorPopupProps & WrappedComponentProps<"intl">>;
@@ -58,4 +58,5 @@ export interface State {
58
58
  dropdownItems: BlockMenuItem[];
59
59
  isOpenedByKeyboard: boolean;
60
60
  isTableSelectorOpen: boolean;
61
+ isTableSelectorOpenedByKeyboard: boolean;
61
62
  }
@@ -33,6 +33,7 @@ export declare class ToolbarInsertBlock extends React.PureComponent<Props & Wrap
33
33
  render(): jsx.JSX.Element | null;
34
34
  private handleClick;
35
35
  private handleOpenByKeyboard;
36
+ private handleTableSelectorOpenByKeyboard;
36
37
  private toggleLinkPanel;
37
38
  private insertMention;
38
39
  private insertTable;
@@ -10,6 +10,7 @@ export interface TableSelectorPopupProps {
10
10
  popupsScrollableElement?: HTMLElement;
11
11
  handleClickOutside?: SimpleEventHandler<MouseEvent>;
12
12
  handleEscapeKeydown?: SimpleEventHandler<KeyboardEvent>;
13
+ isOpenedByKeyboard: boolean;
13
14
  }
14
15
  export declare const TableSelectorPopup: (props: TableSelectorPopupProps) => jsx.JSX.Element;
15
16
  export default TableSelectorPopup;
@@ -1,4 +1,4 @@
1
- import type { SyntheticEvent } from 'react';
1
+ import type { KeyboardEventHandler, SyntheticEvent } from 'react';
2
2
  import type { WrappedComponentProps } from 'react-intl-next';
3
3
  export declare const TABLE_SELECTOR_BUTTON_GAP = 2;
4
4
  export declare const TABLE_SELECTOR_BUTTON_SIZE = 17;
@@ -8,6 +8,9 @@ export interface TableSelectorButtonProps {
8
8
  isActive: boolean;
9
9
  onClick: OnTableSizeSelection;
10
10
  label: string;
11
+ onKeyDown: KeyboardEventHandler<HTMLButtonElement>;
12
+ isFocused: boolean;
13
+ handleInitialButtonFocus: () => void;
11
14
  }
12
15
  export interface OnTableSizeSelection {
13
16
  (rowsCount: number, colsCount: number, event?: SyntheticEvent): void;
@@ -18,6 +21,9 @@ interface TableSelectorPopupProps {
18
21
  onSelection: OnTableSizeSelection;
19
22
  selectedCol: number;
20
23
  selectedRow: number;
24
+ onKeyDown: KeyboardEventHandler<HTMLButtonElement>;
25
+ isFocused: boolean;
26
+ handleInitialButtonFocus: () => void;
21
27
  }
22
28
  declare const _default: import("react").FC<import("react-intl-next").WithIntlProps<TableSelectorPopupProps & WrappedComponentProps<"intl">>> & {
23
29
  WrappedComponent: import("react").ComponentType<TableSelectorPopupProps & WrappedComponentProps<"intl">>;
@@ -58,4 +58,5 @@ export interface State {
58
58
  dropdownItems: BlockMenuItem[];
59
59
  isOpenedByKeyboard: boolean;
60
60
  isTableSelectorOpen: boolean;
61
+ isTableSelectorOpenedByKeyboard: boolean;
61
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-insert-block",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Insert block plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -40,7 +40,7 @@
40
40
  "@atlaskit/editor-plugin-date": "^0.3.0",
41
41
  "@atlaskit/editor-plugin-emoji": "^1.1.0",
42
42
  "@atlaskit/editor-plugin-expand": "^0.4.0",
43
- "@atlaskit/editor-plugin-extension": "^0.6.0",
43
+ "@atlaskit/editor-plugin-extension": "^0.7.0",
44
44
  "@atlaskit/editor-plugin-feature-flags": "^1.0.0",
45
45
  "@atlaskit/editor-plugin-hyperlink": "^0.8.0",
46
46
  "@atlaskit/editor-plugin-image-upload": "^0.2.0",
@@ -59,7 +59,7 @@
59
59
  "@atlaskit/editor-shared-styles": "^2.9.0",
60
60
  "@atlaskit/emoji": "^67.6.0",
61
61
  "@atlaskit/icon": "^22.0.0",
62
- "@atlaskit/primitives": "^1.20.0",
62
+ "@atlaskit/primitives": "^2.0.0",
63
63
  "@atlaskit/theme": "^12.6.0",
64
64
  "@atlaskit/tokens": "^1.35.0",
65
65
  "@babel/runtime": "^7.0.0",