@atlaskit/editor-plugin-table 5.2.1 → 5.3.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 (79) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/plugins/table/commands/selection.js +20 -1
  3. package/dist/cjs/plugins/table/nodeviews/TableComponent.js +20 -2
  4. package/dist/cjs/plugins/table/nodeviews/table.js +1 -0
  5. package/dist/cjs/plugins/table/pm-plugins/drag-and-drop/handlers.js +24 -0
  6. package/dist/cjs/plugins/table/pm-plugins/drag-and-drop/plugin-factory.js +29 -4
  7. package/dist/cjs/plugins/table/pm-plugins/drag-and-drop/plugin.js +17 -5
  8. package/dist/cjs/plugins/table/pm-plugins/table-selection-keymap.js +4 -0
  9. package/dist/cjs/plugins/table/toolbar.js +2 -2
  10. package/dist/cjs/plugins/table/types.js +4 -0
  11. package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/ColumnDropTargets/index.js +106 -0
  12. package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/index.js +90 -0
  13. package/dist/cjs/plugins/table/ui/common-styles.js +1 -1
  14. package/dist/cjs/plugins/table/ui/ui-styles.js +12 -9
  15. package/dist/es2019/plugins/table/commands/selection.js +18 -1
  16. package/dist/es2019/plugins/table/nodeviews/TableComponent.js +20 -2
  17. package/dist/es2019/plugins/table/nodeviews/table.js +1 -0
  18. package/dist/es2019/plugins/table/pm-plugins/drag-and-drop/handlers.js +10 -0
  19. package/dist/es2019/plugins/table/pm-plugins/drag-and-drop/plugin-factory.js +28 -4
  20. package/dist/es2019/plugins/table/pm-plugins/drag-and-drop/plugin.js +14 -3
  21. package/dist/es2019/plugins/table/pm-plugins/table-selection-keymap.js +6 -2
  22. package/dist/es2019/plugins/table/toolbar.js +1 -1
  23. package/dist/es2019/plugins/table/types.js +4 -0
  24. package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/ColumnDropTargets/index.js +101 -0
  25. package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/index.js +60 -0
  26. package/dist/es2019/plugins/table/ui/common-styles.js +13 -1
  27. package/dist/es2019/plugins/table/ui/ui-styles.js +13 -0
  28. package/dist/esm/plugins/table/commands/selection.js +19 -0
  29. package/dist/esm/plugins/table/nodeviews/TableComponent.js +20 -2
  30. package/dist/esm/plugins/table/nodeviews/table.js +1 -0
  31. package/dist/esm/plugins/table/pm-plugins/drag-and-drop/handlers.js +18 -0
  32. package/dist/esm/plugins/table/pm-plugins/drag-and-drop/plugin-factory.js +28 -3
  33. package/dist/esm/plugins/table/pm-plugins/drag-and-drop/plugin.js +18 -6
  34. package/dist/esm/plugins/table/pm-plugins/table-selection-keymap.js +6 -2
  35. package/dist/esm/plugins/table/toolbar.js +1 -1
  36. package/dist/esm/plugins/table/types.js +4 -0
  37. package/dist/esm/plugins/table/ui/TableFloatingColumnControls/ColumnDropTargets/index.js +97 -0
  38. package/dist/esm/plugins/table/ui/TableFloatingColumnControls/index.js +80 -0
  39. package/dist/esm/plugins/table/ui/common-styles.js +2 -2
  40. package/dist/esm/plugins/table/ui/ui-styles.js +11 -8
  41. package/dist/types/plugins/table/commands/selection.d.ts +1 -0
  42. package/dist/types/plugins/table/index.d.ts +1 -1
  43. package/dist/types/plugins/table/nodeviews/TableComponent.d.ts +1 -0
  44. package/dist/types/plugins/table/pm-plugins/drag-and-drop/handlers.d.ts +3 -0
  45. package/dist/types/plugins/table/pm-plugins/drag-and-drop/plugin-factory.d.ts +1 -2
  46. package/dist/types/plugins/table/pm-plugins/drag-and-drop/types.d.ts +2 -0
  47. package/dist/types/plugins/table/toolbar.d.ts +1 -0
  48. package/dist/types/plugins/table/types.d.ts +4 -0
  49. package/dist/types/plugins/table/ui/TableFloatingColumnControls/ColumnDropTargets/index.d.ts +11 -0
  50. package/dist/types/plugins/table/ui/TableFloatingColumnControls/index.d.ts +20 -0
  51. package/dist/types/plugins/table/ui/ui-styles.d.ts +1 -0
  52. package/dist/types-ts4.5/plugins/table/commands/selection.d.ts +1 -0
  53. package/dist/types-ts4.5/plugins/table/index.d.ts +1 -1
  54. package/dist/types-ts4.5/plugins/table/nodeviews/TableComponent.d.ts +1 -0
  55. package/dist/types-ts4.5/plugins/table/pm-plugins/drag-and-drop/handlers.d.ts +3 -0
  56. package/dist/types-ts4.5/plugins/table/pm-plugins/drag-and-drop/plugin-factory.d.ts +1 -2
  57. package/dist/types-ts4.5/plugins/table/pm-plugins/drag-and-drop/types.d.ts +2 -0
  58. package/dist/types-ts4.5/plugins/table/toolbar.d.ts +1 -0
  59. package/dist/types-ts4.5/plugins/table/types.d.ts +4 -0
  60. package/dist/types-ts4.5/plugins/table/ui/TableFloatingColumnControls/ColumnDropTargets/index.d.ts +11 -0
  61. package/dist/types-ts4.5/plugins/table/ui/TableFloatingColumnControls/index.d.ts +20 -0
  62. package/dist/types-ts4.5/plugins/table/ui/ui-styles.d.ts +1 -0
  63. package/package.json +5 -2
  64. package/src/__tests__/unit/ui/TableFloatingColumnControls.tsx +139 -0
  65. package/src/plugins/table/commands/selection.ts +24 -0
  66. package/src/plugins/table/index.tsx +1 -1
  67. package/src/plugins/table/nodeviews/TableComponent.tsx +25 -0
  68. package/src/plugins/table/nodeviews/table.tsx +1 -0
  69. package/src/plugins/table/pm-plugins/drag-and-drop/handlers.ts +35 -0
  70. package/src/plugins/table/pm-plugins/drag-and-drop/plugin-factory.ts +27 -2
  71. package/src/plugins/table/pm-plugins/drag-and-drop/plugin.ts +12 -3
  72. package/src/plugins/table/pm-plugins/drag-and-drop/types.ts +3 -0
  73. package/src/plugins/table/pm-plugins/table-selection-keymap.ts +15 -1
  74. package/src/plugins/table/toolbar.tsx +3 -1
  75. package/src/plugins/table/types.ts +5 -0
  76. package/src/plugins/table/ui/TableFloatingColumnControls/ColumnDropTargets/index.tsx +128 -0
  77. package/src/plugins/table/ui/TableFloatingColumnControls/index.tsx +101 -0
  78. package/src/plugins/table/ui/common-styles.ts +13 -0
  79. package/src/plugins/table/ui/ui-styles.ts +14 -0
@@ -2,12 +2,18 @@ import {
2
2
  bindKeymapWithCommand,
3
3
  moveLeft,
4
4
  moveRight,
5
+ shiftArrowUp,
5
6
  } from '@atlaskit/editor-common/keymaps';
6
7
  import type { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
7
8
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
8
9
  import { keymap } from '@atlaskit/editor-prosemirror/keymap';
10
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
9
11
 
10
- import { arrowLeftFromTable, arrowRightFromTable } from '../commands/selection';
12
+ import {
13
+ arrowLeftFromTable,
14
+ arrowRightFromTable,
15
+ shiftArrowUpFromTable,
16
+ } from '../commands/selection';
11
17
  import type tablePlugin from '../index';
12
18
 
13
19
  export function tableSelectionKeymapPlugin(
@@ -29,6 +35,14 @@ export function tableSelectionKeymapPlugin(
29
35
  list,
30
36
  );
31
37
 
38
+ if (getBooleanFF('platform.editor.table.shift-arrowup-fix')) {
39
+ bindKeymapWithCommand(
40
+ shiftArrowUp.common!,
41
+ shiftArrowUpFromTable(editorSelectionAPI)(),
42
+ list,
43
+ );
44
+ }
45
+
32
46
  return keymap(list) as SafePlugin;
33
47
  }
34
48
 
@@ -420,7 +420,9 @@ export const getToolbarCellOptionsConfig = (
420
420
  };
421
421
  };
422
422
 
423
- const getClosestSelectionRect = (state: EditorState): Rect | undefined => {
423
+ export const getClosestSelectionRect = (
424
+ state: EditorState,
425
+ ): Rect | undefined => {
424
426
  const selection = state.selection;
425
427
  return isSelectionType(selection, 'cell')
426
428
  ? getSelectionRect(selection)!
@@ -239,6 +239,7 @@ export enum TableDecorations {
239
239
  CELL_CONTROLS_HOVER = 'CELL_CONTROLS_HOVER',
240
240
 
241
241
  COLUMN_CONTROLS_DECORATIONS = 'COLUMN_CONTROLS_DECORATIONS',
242
+ COLUMN_DROP_TARGET_DECORATIONS = 'COLUMN_DROP_TARGET_DECORATIONS',
242
243
  COLUMN_SELECTED = 'COLUMN_SELECTED',
243
244
  COLUMN_RESIZING_HANDLE = 'COLUMN_RESIZING_HANDLE',
244
245
  COLUMN_RESIZING_HANDLE_WIDGET = 'COLUMN_RESIZING_HANDLE_WIDGET',
@@ -254,6 +255,10 @@ export const TableCssClassName = {
254
255
  COLUMN_CONTROLS_DECORATIONS: `${tablePrefixSelector}-column-controls-decoration`,
255
256
  COLUMN_SELECTED: `${tablePrefixSelector}-column__selected`,
256
257
 
258
+ COLUMN_CONTROLS_WRAPPER: `${tablePrefixSelector}-col-controls-wrapper`,
259
+ COLUMN_DROP_TARGET_CONTROLS: `${tablePrefixSelector}-col-drop-target-controls`,
260
+ COLUMN_CONTROLS_INNER: `${tablePrefixSelector}-col-controls__inner`,
261
+
257
262
  ROW_CONTROLS_WRAPPER: `${tablePrefixSelector}-row-controls-wrapper`,
258
263
  ROW_CONTROLS: `${tablePrefixSelector}-row-controls`,
259
264
  ROW_CONTROLS_INNER: `${tablePrefixSelector}-row-controls__inner`,
@@ -0,0 +1,128 @@
1
+ import React, { useEffect, useMemo, useRef } from 'react';
2
+
3
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
4
+ import { attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/addon/closest-edge';
5
+ import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
6
+
7
+ import type { DraggableSourceData } from '../../../types';
8
+ import { TableCssClassName as ClassName } from '../../../types';
9
+ import { getColumnsWidths, getRowHeights } from '../../../utils';
10
+
11
+ export interface Props {
12
+ editorView: EditorView;
13
+ tableRef: HTMLTableElement;
14
+ stickyTop?: number;
15
+ tableHeight?: number;
16
+ localId?: string;
17
+ }
18
+
19
+ export const ColumnDropTargets: React.FC<Props> = ({
20
+ editorView,
21
+ tableRef,
22
+ tableHeight,
23
+ stickyTop,
24
+ localId,
25
+ }) => {
26
+ const colWidths = getColumnsWidths(editorView);
27
+ const rowHeights = useMemo(() => {
28
+ // NOTE: we don't care so much as to what tableHeight is, we only care that it changed and is a sane value.
29
+ if (tableRef && !!tableHeight) {
30
+ return getRowHeights(tableRef);
31
+ }
32
+ return [0];
33
+ }, [tableRef, tableHeight]);
34
+
35
+ if (!tableRef) {
36
+ return null;
37
+ }
38
+
39
+ const firstRow = tableRef.querySelector('tr');
40
+ const hasHeaderRow = firstRow
41
+ ? firstRow.getAttribute('data-header-row')
42
+ : false;
43
+
44
+ const marginTop =
45
+ hasHeaderRow && stickyTop !== undefined ? rowHeights?.[0] ?? 0 : 0;
46
+
47
+ return (
48
+ <div className={ClassName.COLUMN_DROP_TARGET_CONTROLS}>
49
+ <div
50
+ className={ClassName.COLUMN_CONTROLS_INNER}
51
+ data-testid="table-floating-column-controls-drop-targets"
52
+ >
53
+ {colWidths.map((width, index) => {
54
+ return (
55
+ <ColumnDropTarget
56
+ key={index}
57
+ index={index}
58
+ localId={localId}
59
+ width={width}
60
+ height={tableHeight}
61
+ marginTop={marginTop}
62
+ />
63
+ );
64
+ })}
65
+ </div>
66
+ </div>
67
+ );
68
+ };
69
+
70
+ export default ColumnDropTargets;
71
+
72
+ const ColumnDropTarget: React.FC<{
73
+ index: number;
74
+ localId?: string;
75
+ width?: number;
76
+ height?: number;
77
+ marginTop?: number;
78
+ }> = ({ index, localId, width, height, marginTop }) => {
79
+ const dropTargetRef = useRef<HTMLDivElement | null>(null);
80
+
81
+ useEffect(() => {
82
+ if (!dropTargetRef.current) {
83
+ return;
84
+ }
85
+
86
+ return dropTargetForElements({
87
+ element: dropTargetRef.current,
88
+ canDrop({ source }) {
89
+ const data = source.data as DraggableSourceData;
90
+ return (
91
+ // Only draggables of row type can be dropped on this target
92
+ data.type === 'table-column' &&
93
+ // Only draggables which came from the same table can be dropped on this target
94
+ data.localId === localId &&
95
+ // Only draggables which DO NOT include this drop targets index can be dropped
96
+ !!data.indexes?.length &&
97
+ data.indexes?.indexOf(index) === -1
98
+ );
99
+ },
100
+ getData({ input, element }) {
101
+ const data = {
102
+ localId,
103
+ type: 'table-column',
104
+ targetIndex: index,
105
+ };
106
+ return attachClosestEdge(data, {
107
+ input,
108
+ element,
109
+ allowedEdges: ['left', 'right'],
110
+ });
111
+ },
112
+ });
113
+ }, [index, localId]);
114
+
115
+ return (
116
+ <div
117
+ ref={dropTargetRef}
118
+ style={{
119
+ width: width && `${width - 1}px`,
120
+ height: height && `${height}px`,
121
+ marginTop: marginTop && `${marginTop}px`,
122
+ }}
123
+ data-drop-target-index={index}
124
+ data-drop-target-localid={localId}
125
+ data-testid="table-floating-column-controls-drop-target"
126
+ ></div>
127
+ );
128
+ };
@@ -0,0 +1,101 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+
3
+ import type { TableColumnOrdering } from '@atlaskit/custom-steps';
4
+ import type { GetEditorFeatureFlags } from '@atlaskit/editor-common/types';
5
+ import type { Selection } from '@atlaskit/editor-prosemirror/state';
6
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
7
+ import { findTable } from '@atlaskit/editor-tables';
8
+
9
+ import type { RowStickyState } from '../../pm-plugins/sticky-headers';
10
+
11
+ import { ColumnDropTargets } from './ColumnDropTargets';
12
+
13
+ export interface Props {
14
+ editorView: EditorView;
15
+ getEditorFeatureFlags: GetEditorFeatureFlags;
16
+ selection?: Selection;
17
+ tableRef?: HTMLTableElement;
18
+ tableActive?: boolean;
19
+ hasHeaderRow?: boolean;
20
+ headerRowHeight?: number;
21
+ hoveredRows?: number[];
22
+ ordering?: TableColumnOrdering;
23
+ stickyHeader?: RowStickyState;
24
+ }
25
+
26
+ export const TableFloatingColumnControls: React.FC<Props> = ({
27
+ editorView,
28
+ tableRef,
29
+ tableActive,
30
+ hasHeaderRow,
31
+ stickyHeader,
32
+ selection,
33
+ }) => {
34
+ const [tableRect, setTableRect] = useState<{ width: number; height: number }>(
35
+ { width: 0, height: 0 },
36
+ );
37
+
38
+ useEffect(() => {
39
+ if (tableRef && window?.ResizeObserver) {
40
+ const resizeObserver = new ResizeObserver((entries) => {
41
+ for (let entry of entries) {
42
+ setTableRect((prev) => {
43
+ if (
44
+ prev.width !== entry.contentRect.width ||
45
+ prev.height !== entry.contentRect.height
46
+ ) {
47
+ return entry.contentRect;
48
+ }
49
+ return prev;
50
+ });
51
+ }
52
+ });
53
+ resizeObserver.observe(tableRef);
54
+
55
+ return () => {
56
+ resizeObserver.disconnect();
57
+ };
58
+ }
59
+ }, [tableRef]);
60
+
61
+ const selectedLocalId = useMemo(() => {
62
+ if (!selection) {
63
+ return undefined;
64
+ }
65
+
66
+ const tableNode = findTable(selection);
67
+ if (!tableNode) {
68
+ return undefined;
69
+ }
70
+
71
+ return tableNode.node.attrs.localId;
72
+ }, [selection]);
73
+
74
+ if (!tableRef) {
75
+ return null;
76
+ }
77
+
78
+ const stickyTop =
79
+ stickyHeader && stickyHeader.sticky && hasHeaderRow
80
+ ? stickyHeader.top
81
+ : undefined;
82
+
83
+ return (
84
+ <div
85
+ onMouseDown={(e) => e.preventDefault()}
86
+ data-testid="table-floating-column-controls-wrapper"
87
+ >
88
+ {tableActive && (
89
+ <ColumnDropTargets
90
+ editorView={editorView}
91
+ tableRef={tableRef}
92
+ stickyTop={tableActive ? stickyTop : undefined}
93
+ tableHeight={tableRect.height}
94
+ localId={selectedLocalId}
95
+ />
96
+ )}
97
+ </div>
98
+ );
99
+ };
100
+
101
+ export default TableFloatingColumnControls;
@@ -55,6 +55,7 @@ import {
55
55
  columnControlsDecoration,
56
56
  columnControlsLineMarker,
57
57
  DeleteButton,
58
+ floatingColumnControls,
58
59
  HeaderButton,
59
60
  HeaderButtonDanger,
60
61
  HeaderButtonHover,
@@ -515,6 +516,10 @@ export const tableStyles = (
515
516
  }
516
517
  }
517
518
 
519
+ .${ClassName.COLUMN_CONTROLS_WRAPPER} {
520
+ padding: 0 ${tablePadding}px;
521
+ }
522
+
518
523
  &.${ClassName.TABLE_CONTAINER}[data-number-column='true'] {
519
524
  padding-left: ${akEditorTableNumberColumnWidth + tablePadding - 1}px;
520
525
  }
@@ -670,6 +675,8 @@ export const tableStyles = (
670
675
  )}
671
676
  }
672
677
 
678
+ ${floatingColumnControls(props)}
679
+
673
680
  :not(.${ClassName.IS_RESIZING}) .${ClassName.ROW_CONTROLS} {
674
681
  ${HeaderButtonHover(props)}
675
682
  ${HeaderButtonDanger(props)}
@@ -855,6 +862,12 @@ export const tableStyles = (
855
862
  .${ClassName.ROW_CONTROLS_WRAPPER} {
856
863
  left: -${tableToolbarSize}px;
857
864
  }
865
+
866
+ .${ClassName.COLUMN_CONTROLS_WRAPPER} {
867
+ position: absolute;
868
+ top: ${tableMarginTop + 1}px;
869
+ }
870
+
858
871
  ${tableWrapperStyles()}
859
872
  }
860
873
 
@@ -374,6 +374,20 @@ const getFloatingDotOverrides = (props: ThemeProps) => {
374
374
  : '';
375
375
  };
376
376
 
377
+ export const floatingColumnControls = (props: ThemeProps) => {
378
+ return css`
379
+ .${ClassName.COLUMN_DROP_TARGET_CONTROLS} {
380
+ box-sizing: border-box;
381
+ position: absolute;
382
+
383
+ .${ClassName.COLUMN_CONTROLS_INNER} {
384
+ display: flex;
385
+ flex-direction: row;
386
+ }
387
+ }
388
+ `;
389
+ };
390
+
377
391
  export const columnControlsDecoration = (props: ThemeProps) => {
378
392
  if (getBooleanFF('platform.editor.table.column-controls-styles-updated')) {
379
393
  return css`