@atlaskit/editor-plugin-table 5.4.24 → 5.5.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.
@@ -81,7 +81,10 @@ class TableComponent extends React.Component {
81
81
  if (!this.wrapper || event.target !== this.wrapper) {
82
82
  return;
83
83
  }
84
- if (getBooleanFF('platform.editor.table-sticky-scrollbar')) {
84
+ const {
85
+ stickyScrollbar
86
+ } = this.props.getEditorFeatureFlags();
87
+ if (stickyScrollbar) {
85
88
  if (this.stickyScrollbar) {
86
89
  this.stickyScrollbar.scrollLeft(this.wrapper.scrollLeft);
87
90
  }
@@ -306,13 +309,17 @@ class TableComponent extends React.Component {
306
309
  eventDispatcher,
307
310
  options,
308
311
  isDragAndDropEnabled,
309
- getNode
312
+ getNode,
313
+ getEditorFeatureFlags
310
314
  } = this.props;
311
315
  if (allowColumnResizing && this.wrapper && !isIE11) {
312
316
  this.wrapper.addEventListener('scroll', this.handleScrollDebounced, {
313
317
  passive: true
314
318
  });
315
- if (getBooleanFF('platform.editor.table-sticky-scrollbar')) {
319
+ const {
320
+ stickyScrollbar
321
+ } = getEditorFeatureFlags();
322
+ if (stickyScrollbar) {
316
323
  if (this.table) {
317
324
  this.stickyScrollbar = new TableStickyScrollbar(this.wrapper, this.props.view);
318
325
  }
@@ -398,7 +405,8 @@ class TableComponent extends React.Component {
398
405
  allowColumnResizing,
399
406
  eventDispatcher,
400
407
  options,
401
- isDragAndDropEnabled
408
+ isDragAndDropEnabled,
409
+ getEditorFeatureFlags
402
410
  } = this.props;
403
411
  if (this.wrapper && !isIE11) {
404
412
  this.wrapper.removeEventListener('scroll', this.handleScrollDebounced);
@@ -406,7 +414,10 @@ class TableComponent extends React.Component {
406
414
  if (isDragAndDropEnabled && this.dragAndDropCleanupFn) {
407
415
  this.dragAndDropCleanupFn();
408
416
  }
409
- if (getBooleanFF('platform.editor.table-sticky-scrollbar')) {
417
+ const {
418
+ stickyScrollbar
419
+ } = getEditorFeatureFlags();
420
+ if (stickyScrollbar) {
410
421
  if (this.stickyScrollbar) {
411
422
  this.stickyScrollbar.dispose();
412
423
  }
@@ -518,7 +529,8 @@ class TableComponent extends React.Component {
518
529
  getPos,
519
530
  pluginInjectionApi,
520
531
  isDragAndDropEnabled,
521
- canDrag
532
+ canDrag,
533
+ getEditorFeatureFlags
522
534
  } = this.props;
523
535
  const {
524
536
  showBeforeShadow,
@@ -575,8 +587,8 @@ class TableComponent extends React.Component {
575
587
  selection: view.state.selection,
576
588
  headerRowHeight: headerRow ? headerRow.offsetHeight : undefined,
577
589
  stickyHeader: this.state.stickyHeader,
578
- getEditorFeatureFlags: this.props.getEditorFeatureFlags,
579
- canDrag: canDrag
590
+ canDrag: canDrag,
591
+ getEditorFeatureFlags: getEditorFeatureFlags
580
592
  }) : null;
581
593
  const shadowPadding = allowControls && tableActive ? -tableToolbarSize : tableMarginSides;
582
594
  const shadowStyle = memoizeOne(visible => ({
@@ -596,6 +608,9 @@ class TableComponent extends React.Component {
596
608
  }
597
609
  const isNested = isTableNested(view.state, tablePos);
598
610
  const topStickyShadowPosition = isDragAndDropEnabled ? this.state.stickyHeader && this.state.stickyHeader.top + this.state.stickyHeader.padding + 2 : this.state.stickyHeader && this.state.stickyHeader.top + this.state.stickyHeader.padding + shadowPadding + 2;
611
+ const {
612
+ stickyScrollbar
613
+ } = getEditorFeatureFlags();
599
614
  return /*#__PURE__*/React.createElement(TableContainer, {
600
615
  className: classnames(ClassName.TABLE_CONTAINER, {
601
616
  [ClassName.WITH_CONTROLS]: allowControls && tableActive,
@@ -616,7 +631,7 @@ class TableComponent extends React.Component {
616
631
  }, /*#__PURE__*/React.createElement("div", {
617
632
  className: ClassName.TABLE_STICKY_SENTINEL_TOP,
618
633
  "data-testid": "sticky-sentinel-top"
619
- }), getBooleanFF('platform.editor.table-sticky-scrollbar') && /*#__PURE__*/React.createElement("div", {
634
+ }), stickyScrollbar && /*#__PURE__*/React.createElement("div", {
620
635
  className: ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP,
621
636
  "data-testid": "sticky-scrollbar-sentinel-top"
622
637
  }), allowControls && rowControls, isDragAndDropEnabled && /*#__PURE__*/React.createElement(ExternalDropTargets, {
@@ -653,11 +668,13 @@ class TableComponent extends React.Component {
653
668
  }
654
669
  }
655
670
  }
656
- }, allowControls && colControls), getBooleanFF('platform.editor.table-sticky-scrollbar') && /*#__PURE__*/React.createElement("div", {
671
+ }, allowControls && colControls), stickyScrollbar && /*#__PURE__*/React.createElement("div", {
657
672
  className: ClassName.TABLE_STICKY_SCROLLBAR_CONTAINER,
658
673
  style: {
659
674
  height: MAX_BROWSER_SCROLLBAR_HEIGHT,
660
- display: 'none'
675
+ display: 'none',
676
+ // prevent unwanted scroll during table resize without removing scrollbar container from the dom
677
+ width: isResizing ? '0px' : '100%'
661
678
  }
662
679
  }, /*#__PURE__*/React.createElement("div", {
663
680
  style: {
@@ -682,7 +699,7 @@ class TableComponent extends React.Component {
682
699
  })), /*#__PURE__*/React.createElement("div", {
683
700
  className: ClassName.TABLE_STICKY_SENTINEL_BOTTOM,
684
701
  "data-testid": "sticky-sentinel-bottom"
685
- }), getBooleanFF('platform.editor.table-sticky-scrollbar') && /*#__PURE__*/React.createElement("div", {
702
+ }), stickyScrollbar && /*#__PURE__*/React.createElement("div", {
686
703
  className: ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM,
687
704
  "data-testid": "sticky-scrollbar-sentinel-bottom"
688
705
  }));
@@ -1,10 +1,13 @@
1
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
1
+ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
2
+ import debounce from 'lodash/debounce';
2
3
  import rafSchd from 'raf-schd';
3
4
  import { useIntl } from 'react-intl-next';
4
5
  import { TABLE_OVERFLOW_CHANGE_TRIGGER } from '@atlaskit/editor-common/analytics';
5
6
  import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
7
+ import { focusTableResizer, ToolTipContent } from '@atlaskit/editor-common/keymaps';
6
8
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
7
9
  import { ResizerNext } from '@atlaskit/editor-common/resizer';
10
+ import { browser } from '@atlaskit/editor-common/utils';
8
11
  import { findTable } from '@atlaskit/editor-tables/utils';
9
12
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
10
13
  import { getPluginState } from '../pm-plugins/plugin-factory';
@@ -15,6 +18,8 @@ import { TABLE_HIGHLIGHT_GAP, TABLE_HIGHLIGHT_TOLERANCE, TABLE_SNAP_GAP } from '
15
18
  import { generateResizedPayload, generateResizeFrameRatePayloads, useMeasureFramerate } from '../utils/analytics';
16
19
  import { defaultGuidelines } from '../utils/guidelines';
17
20
  import { defaultSnappingWidths, findClosestSnap } from '../utils/snapping';
21
+ const DEBOUNCE_TIME_FOR_SCREEN_READER_ANNOUNCER = 1000;
22
+ const RESIZE_STEP_VALUE = 10;
18
23
  const handles = {
19
24
  right: true
20
25
  };
@@ -83,10 +88,31 @@ export const TableResizer = ({
83
88
  const currentGap = useRef(0);
84
89
  // track resizing state - use ref over state to avoid re-render
85
90
  const isResizing = useRef(false);
91
+ const areResizeMetaKeysPressed = useRef(false);
92
+ const resizerRef = useRef(null);
93
+
94
+ // used to reposition tooltip when table is resizing via keyboard
95
+ const updateTooltip = React.useRef();
86
96
  const [snappingEnabled, setSnappingEnabled] = useState(false);
97
+
98
+ // we don't want to update aria-live region on each width change, it might provide bad experience for screen reader users
99
+ const [screenReaderResizeInformation, setScreenReaderResizeInformation] = useState({
100
+ type: 'none',
101
+ width
102
+ });
87
103
  const {
88
104
  formatMessage
89
105
  } = useIntl();
106
+ const screenReaderResizeAnnouncerMessages = {
107
+ increase: formatMessage(messages.tableSizeIncreaseScreenReaderInformation, {
108
+ newWidth: screenReaderResizeInformation.width
109
+ }),
110
+ decrease: formatMessage(messages.tableSizeDecreaseScreenReaderInformation, {
111
+ newWidth: screenReaderResizeInformation.width
112
+ }),
113
+ none: ''
114
+ };
115
+ const isTableSelected = ((_findTable = findTable((_editorView$state = editorView.state) === null || _editorView$state === void 0 ? void 0 : _editorView$state.selection)) === null || _findTable === void 0 ? void 0 : _findTable.pos) === getPos();
90
116
  const resizerMinWidth = getResizerMinWidth(node);
91
117
  const handleSize = getResizerHandleHeight(tableRef);
92
118
  const {
@@ -230,8 +256,109 @@ export const TableResizer = ({
230
256
  }
231
257
  return newWidth;
232
258
  }, [displayGapCursor, updateWidth, editorView, getPos, node, tableRef, scheduleResize, displayGuideline, attachAnalyticsEvent, endMeasure, onResizeStop]);
233
- const isTableSelected = ((_findTable = findTable((_editorView$state = editorView.state) === null || _editorView$state === void 0 ? void 0 : _editorView$state.selection)) === null || _findTable === void 0 ? void 0 : _findTable.pos) === getPos();
234
- return /*#__PURE__*/React.createElement(ResizerNext, {
259
+ const handleTableSizeChangeOnKeypress = useCallback(step => {
260
+ const newWidth = width + step;
261
+ if (newWidth > maxWidth || newWidth < resizerMinWidth) {
262
+ return;
263
+ }
264
+ handleResizeStop({
265
+ width: width,
266
+ x: 0,
267
+ y: 0,
268
+ height: 0
269
+ }, {
270
+ width: step,
271
+ height: 0
272
+ });
273
+ }, [width, handleResizeStop, maxWidth, resizerMinWidth]);
274
+ const handleEscape = useCallback(() => {
275
+ editorView === null || editorView === void 0 ? void 0 : editorView.focus();
276
+ }, [editorView]);
277
+ const handleKeyDown = useCallback(event => {
278
+ const isBracketKey = event.code === 'BracketRight' || event.code === 'BracketLeft';
279
+ const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
280
+ if (event.altKey || metaKey || event.shiftKey) {
281
+ areResizeMetaKeysPressed.current = true;
282
+ }
283
+ if (event.altKey && metaKey) {
284
+ if (isBracketKey) {
285
+ event.preventDefault();
286
+ handleTableSizeChangeOnKeypress(event.code === 'BracketRight' ? RESIZE_STEP_VALUE : -RESIZE_STEP_VALUE);
287
+ }
288
+ } else if (!areResizeMetaKeysPressed.current) {
289
+ handleEscape();
290
+ }
291
+ }, [handleEscape, handleTableSizeChangeOnKeypress]);
292
+ const handleKeyUp = useCallback(event => {
293
+ if (event.altKey || event.metaKey) {
294
+ areResizeMetaKeysPressed.current = false;
295
+ }
296
+ return;
297
+ }, [areResizeMetaKeysPressed]);
298
+ useLayoutEffect(() => {
299
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
300
+ if (!resizerRef.current) {
301
+ return;
302
+ }
303
+ const resizeHandleThumbEl = resizerRef.current.getResizerThumbEl();
304
+ const globalKeyDownHandler = event => {
305
+ const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
306
+ if (!isTableSelected) {
307
+ return;
308
+ }
309
+ if (event.altKey && event.shiftKey && metaKey && event.code === 'KeyR') {
310
+ event.preventDefault();
311
+ if (!resizeHandleThumbEl) {
312
+ return;
313
+ }
314
+ resizeHandleThumbEl.focus();
315
+ resizeHandleThumbEl.scrollIntoView({
316
+ behavior: 'smooth',
317
+ block: 'center',
318
+ inline: 'nearest'
319
+ });
320
+ }
321
+ };
322
+ const editorViewDom = editorView === null || editorView === void 0 ? void 0 : editorView.dom;
323
+ editorViewDom === null || editorViewDom === void 0 ? void 0 : editorViewDom.addEventListener('keydown', globalKeyDownHandler);
324
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.addEventListener('keydown', handleKeyDown);
325
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.addEventListener('keyup', handleKeyUp);
326
+ return () => {
327
+ editorViewDom === null || editorViewDom === void 0 ? void 0 : editorViewDom.removeEventListener('keydown', globalKeyDownHandler);
328
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.removeEventListener('keydown', handleKeyDown);
329
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.removeEventListener('keyup', handleKeyUp);
330
+ };
331
+ }
332
+ }, [resizerRef, editorView, handleResizeStop, isTableSelected, handleKeyDown, handleKeyUp]);
333
+ useLayoutEffect(() => {
334
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
335
+ var _updateTooltip$curren;
336
+ (_updateTooltip$curren = updateTooltip.current) === null || _updateTooltip$curren === void 0 ? void 0 : _updateTooltip$curren.call(updateTooltip);
337
+ }
338
+ }, [width]);
339
+ useEffect(() => {
340
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
341
+ const debouncedSetWidth = debounce(setScreenReaderResizeInformation, DEBOUNCE_TIME_FOR_SCREEN_READER_ANNOUNCER);
342
+ debouncedSetWidth(prevState => {
343
+ let type = 'none';
344
+ if (prevState.width > width) {
345
+ type = 'decrease';
346
+ }
347
+ if (prevState.width < width) {
348
+ type = 'increase';
349
+ }
350
+ return {
351
+ type,
352
+ width
353
+ };
354
+ });
355
+ return () => {
356
+ debouncedSetWidth.cancel();
357
+ };
358
+ }
359
+ }, [width]);
360
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ResizerNext, {
361
+ ref: resizerRef,
235
362
  enable: handles,
236
363
  width: width,
237
364
  handleAlignmentMethod: "sticky",
@@ -249,6 +376,17 @@ export const TableResizer = ({
249
376
  isHandleVisible: isTableSelected,
250
377
  appearance: isTableSelected && isWholeTableInDanger ? 'danger' : undefined,
251
378
  handleHighlight: "shadow",
252
- handleTooltipContent: formatMessage(messages.resizeTable)
253
- }, children);
379
+ handleTooltipContent: getBooleanFF('platform.editor.a11y-table-resizing_uapcv') ? ({
380
+ update
381
+ }) => {
382
+ updateTooltip.current = update;
383
+ return /*#__PURE__*/React.createElement(ToolTipContent, {
384
+ description: formatMessage(messages.resizeTable),
385
+ keymap: focusTableResizer
386
+ });
387
+ } : formatMessage(messages.resizeTable)
388
+ }, children), getBooleanFF('platform.editor.a11y-table-resizing_uapcv') && /*#__PURE__*/React.createElement("div", {
389
+ className: "assistive",
390
+ role: "status"
391
+ }, screenReaderResizeAnnouncerMessages[screenReaderResizeInformation.type]));
254
392
  };
@@ -11,7 +11,6 @@ import { akEditorFloatingPanelZIndex } from '@atlaskit/editor-shared-styles';
11
11
  import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
12
12
  import { findCellRectClosestToPos, findTable, getSelectionRect, isSelectionType, splitCell } from '@atlaskit/editor-tables/utils';
13
13
  import RemoveIcon from '@atlaskit/icon/glyph/editor/remove';
14
- import { getBooleanFF } from '@atlaskit/platform-feature-flags';
15
14
  import { clearHoverSelection, hoverColumns, hoverMergedCells, hoverRows, hoverTable, removeDescendantNodes } from './commands';
16
15
  import { deleteColumnsWithAnalytics, deleteRowsWithAnalytics, deleteTableWithAnalytics, distributeColumnsWidthsWithAnalytics, emptyMultipleCellsWithAnalytics, insertColumnWithAnalytics, insertRowWithAnalytics, mergeCellsWithAnalytics, setColorWithAnalytics, sortColumnWithAnalytics, splitCellWithAnalytics, toggleHeaderColumnWithAnalytics, toggleHeaderRowWithAnalytics, toggleNumberColumnWithAnalytics, wrapTableInExpandWithAnalytics } from './commands-with-analytics';
17
16
  import { getPluginState } from './pm-plugins/plugin-factory';
@@ -304,12 +303,15 @@ export const getToolbarConfig = (getEditorContainerWidth, editorAnalyticsAPI, ge
304
303
  }
305
304
  return element;
306
305
  };
306
+ const {
307
+ stickyScrollbar
308
+ } = getEditorFeatureFlags();
307
309
  return {
308
310
  title: 'Table floating controls',
309
311
  getDomRef,
310
312
  nodeType,
311
313
  offset: [0, 18],
312
- absoluteOffset: getBooleanFF('platform.editor.table-sticky-scrollbar') ? {
314
+ absoluteOffset: stickyScrollbar ? {
313
315
  top: -6
314
316
  } : {
315
317
  top: 0
@@ -77,8 +77,8 @@ const stickyScrollbarContainerStyles = `.${ClassName.TABLE_CONTAINER} {
77
77
  bottom: 0;
78
78
  }
79
79
  }`;
80
- const stickyScrollbarStyles = () => {
81
- return getBooleanFF('platform.editor.table-sticky-scrollbar') ? `${stickyScrollbarContainerStyles} ${stickyScrollbarSentinelStyles}` : '';
80
+ const stickyScrollbarStyles = featureFlags => {
81
+ return featureFlags !== null && featureFlags !== void 0 && featureFlags.stickyScrollbar ? `${stickyScrollbarContainerStyles} ${stickyScrollbarSentinelStyles}` : '';
82
82
  };
83
83
  const shadowSentinelStyles = `
84
84
  .${ClassName.TABLE_SHADOW_SENTINEL_LEFT},
@@ -437,7 +437,7 @@ export const tableStyles = props => {
437
437
 
438
438
  ${sentinelStyles}
439
439
  ${OverflowShadow(props)}
440
- ${stickyScrollbarStyles()}
440
+ ${stickyScrollbarStyles(props.featureFlags)}
441
441
 
442
442
  .${ClassName.TABLE_STICKY} .${ClassName.TABLE_STICKY_SHADOW} {
443
443
  height: 0; // stop overflow flash & set correct height in update-overflow-shadows.ts
@@ -92,7 +92,9 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
92
92
  if (!_this.wrapper || event.target !== _this.wrapper) {
93
93
  return;
94
94
  }
95
- if (getBooleanFF('platform.editor.table-sticky-scrollbar')) {
95
+ var _this$props$getEditor = _this.props.getEditorFeatureFlags(),
96
+ stickyScrollbar = _this$props$getEditor.stickyScrollbar;
97
+ if (stickyScrollbar) {
96
98
  if (_this.stickyScrollbar) {
97
99
  _this.stickyScrollbar.scrollLeft(_this.wrapper.scrollLeft);
98
100
  }
@@ -304,12 +306,15 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
304
306
  eventDispatcher = _this$props7.eventDispatcher,
305
307
  options = _this$props7.options,
306
308
  isDragAndDropEnabled = _this$props7.isDragAndDropEnabled,
307
- getNode = _this$props7.getNode;
309
+ getNode = _this$props7.getNode,
310
+ getEditorFeatureFlags = _this$props7.getEditorFeatureFlags;
308
311
  if (allowColumnResizing && this.wrapper && !isIE11) {
309
312
  this.wrapper.addEventListener('scroll', this.handleScrollDebounced, {
310
313
  passive: true
311
314
  });
312
- if (getBooleanFF('platform.editor.table-sticky-scrollbar')) {
315
+ var _getEditorFeatureFlag = getEditorFeatureFlags(),
316
+ stickyScrollbar = _getEditorFeatureFlag.stickyScrollbar;
317
+ if (stickyScrollbar) {
313
318
  if (this.table) {
314
319
  this.stickyScrollbar = new TableStickyScrollbar(this.wrapper, this.props.view);
315
320
  }
@@ -393,14 +398,17 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
393
398
  allowColumnResizing = _this$props8.allowColumnResizing,
394
399
  eventDispatcher = _this$props8.eventDispatcher,
395
400
  options = _this$props8.options,
396
- isDragAndDropEnabled = _this$props8.isDragAndDropEnabled;
401
+ isDragAndDropEnabled = _this$props8.isDragAndDropEnabled,
402
+ getEditorFeatureFlags = _this$props8.getEditorFeatureFlags;
397
403
  if (this.wrapper && !isIE11) {
398
404
  this.wrapper.removeEventListener('scroll', this.handleScrollDebounced);
399
405
  }
400
406
  if (isDragAndDropEnabled && this.dragAndDropCleanupFn) {
401
407
  this.dragAndDropCleanupFn();
402
408
  }
403
- if (getBooleanFF('platform.editor.table-sticky-scrollbar')) {
409
+ var _getEditorFeatureFlag2 = getEditorFeatureFlags(),
410
+ stickyScrollbar = _getEditorFeatureFlag2.stickyScrollbar;
411
+ if (stickyScrollbar) {
404
412
  if (this.stickyScrollbar) {
405
413
  this.stickyScrollbar.dispose();
406
414
  }
@@ -512,7 +520,8 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
512
520
  getPos = _this$props10.getPos,
513
521
  pluginInjectionApi = _this$props10.pluginInjectionApi,
514
522
  isDragAndDropEnabled = _this$props10.isDragAndDropEnabled,
515
- canDrag = _this$props10.canDrag;
523
+ canDrag = _this$props10.canDrag,
524
+ getEditorFeatureFlags = _this$props10.getEditorFeatureFlags;
516
525
  var _this$state3 = this.state,
517
526
  showBeforeShadow = _this$state3.showBeforeShadow,
518
527
  showAfterShadow = _this$state3.showAfterShadow;
@@ -566,8 +575,8 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
566
575
  selection: view.state.selection,
567
576
  headerRowHeight: headerRow ? headerRow.offsetHeight : undefined,
568
577
  stickyHeader: this.state.stickyHeader,
569
- getEditorFeatureFlags: this.props.getEditorFeatureFlags,
570
- canDrag: canDrag
578
+ canDrag: canDrag,
579
+ getEditorFeatureFlags: getEditorFeatureFlags
571
580
  }) : null;
572
581
  var shadowPadding = allowControls && tableActive ? -tableToolbarSize : tableMarginSides;
573
582
  var shadowStyle = memoizeOne(function (visible) {
@@ -589,6 +598,8 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
589
598
  }
590
599
  var isNested = isTableNested(view.state, tablePos);
591
600
  var topStickyShadowPosition = isDragAndDropEnabled ? this.state.stickyHeader && this.state.stickyHeader.top + this.state.stickyHeader.padding + 2 : this.state.stickyHeader && this.state.stickyHeader.top + this.state.stickyHeader.padding + shadowPadding + 2;
601
+ var _getEditorFeatureFlag3 = getEditorFeatureFlags(),
602
+ stickyScrollbar = _getEditorFeatureFlag3.stickyScrollbar;
592
603
  return /*#__PURE__*/React.createElement(TableContainer, {
593
604
  className: classnames(ClassName.TABLE_CONTAINER, (_classnames = {}, _defineProperty(_classnames, ClassName.WITH_CONTROLS, allowControls && tableActive), _defineProperty(_classnames, ClassName.TABLE_STICKY, this.state.stickyHeader && hasHeaderRow), _defineProperty(_classnames, ClassName.HOVERED_DELETE_BUTTON, isInDanger), _defineProperty(_classnames, ClassName.TABLE_SELECTED, isTableSelected(view.state.selection)), _classnames)),
594
605
  editorView: view,
@@ -604,7 +615,7 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
604
615
  }, /*#__PURE__*/React.createElement("div", {
605
616
  className: ClassName.TABLE_STICKY_SENTINEL_TOP,
606
617
  "data-testid": "sticky-sentinel-top"
607
- }), getBooleanFF('platform.editor.table-sticky-scrollbar') && /*#__PURE__*/React.createElement("div", {
618
+ }), stickyScrollbar && /*#__PURE__*/React.createElement("div", {
608
619
  className: ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP,
609
620
  "data-testid": "sticky-scrollbar-sentinel-top"
610
621
  }), allowControls && rowControls, isDragAndDropEnabled && /*#__PURE__*/React.createElement(ExternalDropTargets, {
@@ -641,11 +652,13 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
641
652
  }
642
653
  }
643
654
  }
644
- }, allowControls && colControls), getBooleanFF('platform.editor.table-sticky-scrollbar') && /*#__PURE__*/React.createElement("div", {
655
+ }, allowControls && colControls), stickyScrollbar && /*#__PURE__*/React.createElement("div", {
645
656
  className: ClassName.TABLE_STICKY_SCROLLBAR_CONTAINER,
646
657
  style: {
647
658
  height: MAX_BROWSER_SCROLLBAR_HEIGHT,
648
- display: 'none'
659
+ display: 'none',
660
+ // prevent unwanted scroll during table resize without removing scrollbar container from the dom
661
+ width: isResizing ? '0px' : '100%'
649
662
  }
650
663
  }, /*#__PURE__*/React.createElement("div", {
651
664
  style: {
@@ -670,7 +683,7 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
670
683
  })), /*#__PURE__*/React.createElement("div", {
671
684
  className: ClassName.TABLE_STICKY_SENTINEL_BOTTOM,
672
685
  "data-testid": "sticky-sentinel-bottom"
673
- }), getBooleanFF('platform.editor.table-sticky-scrollbar') && /*#__PURE__*/React.createElement("div", {
686
+ }), stickyScrollbar && /*#__PURE__*/React.createElement("div", {
674
687
  className: ClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM,
675
688
  "data-testid": "sticky-scrollbar-sentinel-bottom"
676
689
  }));
@@ -2,13 +2,16 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
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
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; }
5
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
6
+ import debounce from 'lodash/debounce';
6
7
  import rafSchd from 'raf-schd';
7
8
  import { useIntl } from 'react-intl-next';
8
9
  import { TABLE_OVERFLOW_CHANGE_TRIGGER } from '@atlaskit/editor-common/analytics';
9
10
  import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
11
+ import { focusTableResizer, ToolTipContent } from '@atlaskit/editor-common/keymaps';
10
12
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
11
13
  import { ResizerNext } from '@atlaskit/editor-common/resizer';
14
+ import { browser } from '@atlaskit/editor-common/utils';
12
15
  import { findTable } from '@atlaskit/editor-tables/utils';
13
16
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
14
17
  import { getPluginState } from '../pm-plugins/plugin-factory';
@@ -19,6 +22,8 @@ import { TABLE_HIGHLIGHT_GAP, TABLE_HIGHLIGHT_TOLERANCE, TABLE_SNAP_GAP } from '
19
22
  import { generateResizedPayload, generateResizeFrameRatePayloads, useMeasureFramerate } from '../utils/analytics';
20
23
  import { defaultGuidelines } from '../utils/guidelines';
21
24
  import { defaultSnappingWidths, findClosestSnap } from '../utils/snapping';
25
+ var DEBOUNCE_TIME_FOR_SCREEN_READER_ANNOUNCER = 1000;
26
+ var RESIZE_STEP_VALUE = 10;
22
27
  var handles = {
23
28
  right: true
24
29
  };
@@ -86,12 +91,36 @@ export var TableResizer = function TableResizer(_ref) {
86
91
  var currentGap = useRef(0);
87
92
  // track resizing state - use ref over state to avoid re-render
88
93
  var isResizing = useRef(false);
94
+ var areResizeMetaKeysPressed = useRef(false);
95
+ var resizerRef = useRef(null);
96
+
97
+ // used to reposition tooltip when table is resizing via keyboard
98
+ var updateTooltip = React.useRef();
89
99
  var _useState = useState(false),
90
100
  _useState2 = _slicedToArray(_useState, 2),
91
101
  snappingEnabled = _useState2[0],
92
102
  setSnappingEnabled = _useState2[1];
103
+
104
+ // we don't want to update aria-live region on each width change, it might provide bad experience for screen reader users
105
+ var _useState3 = useState({
106
+ type: 'none',
107
+ width: width
108
+ }),
109
+ _useState4 = _slicedToArray(_useState3, 2),
110
+ screenReaderResizeInformation = _useState4[0],
111
+ setScreenReaderResizeInformation = _useState4[1];
93
112
  var _useIntl = useIntl(),
94
113
  formatMessage = _useIntl.formatMessage;
114
+ var screenReaderResizeAnnouncerMessages = {
115
+ increase: formatMessage(messages.tableSizeIncreaseScreenReaderInformation, {
116
+ newWidth: screenReaderResizeInformation.width
117
+ }),
118
+ decrease: formatMessage(messages.tableSizeDecreaseScreenReaderInformation, {
119
+ newWidth: screenReaderResizeInformation.width
120
+ }),
121
+ none: ''
122
+ };
123
+ var isTableSelected = ((_findTable = findTable((_editorView$state = editorView.state) === null || _editorView$state === void 0 ? void 0 : _editorView$state.selection)) === null || _findTable === void 0 ? void 0 : _findTable.pos) === getPos();
95
124
  var resizerMinWidth = getResizerMinWidth(node);
96
125
  var handleSize = getResizerHandleHeight(tableRef);
97
126
  var _getPluginState = getPluginState(editorView.state),
@@ -225,8 +254,109 @@ export var TableResizer = function TableResizer(_ref) {
225
254
  }
226
255
  return newWidth;
227
256
  }, [displayGapCursor, updateWidth, editorView, getPos, node, tableRef, scheduleResize, displayGuideline, attachAnalyticsEvent, endMeasure, onResizeStop]);
228
- var isTableSelected = ((_findTable = findTable((_editorView$state = editorView.state) === null || _editorView$state === void 0 ? void 0 : _editorView$state.selection)) === null || _findTable === void 0 ? void 0 : _findTable.pos) === getPos();
229
- return /*#__PURE__*/React.createElement(ResizerNext, {
257
+ var handleTableSizeChangeOnKeypress = useCallback(function (step) {
258
+ var newWidth = width + step;
259
+ if (newWidth > maxWidth || newWidth < resizerMinWidth) {
260
+ return;
261
+ }
262
+ handleResizeStop({
263
+ width: width,
264
+ x: 0,
265
+ y: 0,
266
+ height: 0
267
+ }, {
268
+ width: step,
269
+ height: 0
270
+ });
271
+ }, [width, handleResizeStop, maxWidth, resizerMinWidth]);
272
+ var handleEscape = useCallback(function () {
273
+ editorView === null || editorView === void 0 || editorView.focus();
274
+ }, [editorView]);
275
+ var handleKeyDown = useCallback(function (event) {
276
+ var isBracketKey = event.code === 'BracketRight' || event.code === 'BracketLeft';
277
+ var metaKey = browser.mac ? event.metaKey : event.ctrlKey;
278
+ if (event.altKey || metaKey || event.shiftKey) {
279
+ areResizeMetaKeysPressed.current = true;
280
+ }
281
+ if (event.altKey && metaKey) {
282
+ if (isBracketKey) {
283
+ event.preventDefault();
284
+ handleTableSizeChangeOnKeypress(event.code === 'BracketRight' ? RESIZE_STEP_VALUE : -RESIZE_STEP_VALUE);
285
+ }
286
+ } else if (!areResizeMetaKeysPressed.current) {
287
+ handleEscape();
288
+ }
289
+ }, [handleEscape, handleTableSizeChangeOnKeypress]);
290
+ var handleKeyUp = useCallback(function (event) {
291
+ if (event.altKey || event.metaKey) {
292
+ areResizeMetaKeysPressed.current = false;
293
+ }
294
+ return;
295
+ }, [areResizeMetaKeysPressed]);
296
+ useLayoutEffect(function () {
297
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
298
+ if (!resizerRef.current) {
299
+ return;
300
+ }
301
+ var resizeHandleThumbEl = resizerRef.current.getResizerThumbEl();
302
+ var globalKeyDownHandler = function globalKeyDownHandler(event) {
303
+ var metaKey = browser.mac ? event.metaKey : event.ctrlKey;
304
+ if (!isTableSelected) {
305
+ return;
306
+ }
307
+ if (event.altKey && event.shiftKey && metaKey && event.code === 'KeyR') {
308
+ event.preventDefault();
309
+ if (!resizeHandleThumbEl) {
310
+ return;
311
+ }
312
+ resizeHandleThumbEl.focus();
313
+ resizeHandleThumbEl.scrollIntoView({
314
+ behavior: 'smooth',
315
+ block: 'center',
316
+ inline: 'nearest'
317
+ });
318
+ }
319
+ };
320
+ var editorViewDom = editorView === null || editorView === void 0 ? void 0 : editorView.dom;
321
+ editorViewDom === null || editorViewDom === void 0 || editorViewDom.addEventListener('keydown', globalKeyDownHandler);
322
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 || resizeHandleThumbEl.addEventListener('keydown', handleKeyDown);
323
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 || resizeHandleThumbEl.addEventListener('keyup', handleKeyUp);
324
+ return function () {
325
+ editorViewDom === null || editorViewDom === void 0 || editorViewDom.removeEventListener('keydown', globalKeyDownHandler);
326
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 || resizeHandleThumbEl.removeEventListener('keydown', handleKeyDown);
327
+ resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 || resizeHandleThumbEl.removeEventListener('keyup', handleKeyUp);
328
+ };
329
+ }
330
+ }, [resizerRef, editorView, handleResizeStop, isTableSelected, handleKeyDown, handleKeyUp]);
331
+ useLayoutEffect(function () {
332
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
333
+ var _updateTooltip$curren;
334
+ (_updateTooltip$curren = updateTooltip.current) === null || _updateTooltip$curren === void 0 || _updateTooltip$curren.call(updateTooltip);
335
+ }
336
+ }, [width]);
337
+ useEffect(function () {
338
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
339
+ var debouncedSetWidth = debounce(setScreenReaderResizeInformation, DEBOUNCE_TIME_FOR_SCREEN_READER_ANNOUNCER);
340
+ debouncedSetWidth(function (prevState) {
341
+ var type = 'none';
342
+ if (prevState.width > width) {
343
+ type = 'decrease';
344
+ }
345
+ if (prevState.width < width) {
346
+ type = 'increase';
347
+ }
348
+ return {
349
+ type: type,
350
+ width: width
351
+ };
352
+ });
353
+ return function () {
354
+ debouncedSetWidth.cancel();
355
+ };
356
+ }
357
+ }, [width]);
358
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ResizerNext, {
359
+ ref: resizerRef,
230
360
  enable: handles,
231
361
  width: width,
232
362
  handleAlignmentMethod: "sticky",
@@ -244,6 +374,16 @@ export var TableResizer = function TableResizer(_ref) {
244
374
  isHandleVisible: isTableSelected,
245
375
  appearance: isTableSelected && isWholeTableInDanger ? 'danger' : undefined,
246
376
  handleHighlight: "shadow",
247
- handleTooltipContent: formatMessage(messages.resizeTable)
248
- }, children);
377
+ handleTooltipContent: getBooleanFF('platform.editor.a11y-table-resizing_uapcv') ? function (_ref3) {
378
+ var update = _ref3.update;
379
+ updateTooltip.current = update;
380
+ return /*#__PURE__*/React.createElement(ToolTipContent, {
381
+ description: formatMessage(messages.resizeTable),
382
+ keymap: focusTableResizer
383
+ });
384
+ } : formatMessage(messages.resizeTable)
385
+ }, children), getBooleanFF('platform.editor.a11y-table-resizing_uapcv') && /*#__PURE__*/React.createElement("div", {
386
+ className: "assistive",
387
+ role: "status"
388
+ }, screenReaderResizeAnnouncerMessages[screenReaderResizeInformation.type]));
249
389
  };