@atlaskit/editor-plugin-table 7.10.1 → 7.11.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 (62) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/commands/insert.js +4 -7
  3. package/dist/cjs/commands/misc.js +10 -3
  4. package/dist/cjs/nodeviews/TableComponent.js +23 -2
  5. package/dist/cjs/plugin.js +7 -1
  6. package/dist/cjs/pm-plugins/analytics/plugin.js +17 -22
  7. package/dist/cjs/pm-plugins/view-mode-sort/consts.js +9 -0
  8. package/dist/cjs/pm-plugins/view-mode-sort/index.js +304 -0
  9. package/dist/cjs/pm-plugins/view-mode-sort/plugin-key.js +8 -0
  10. package/dist/cjs/pm-plugins/view-mode-sort/types.js +5 -0
  11. package/dist/cjs/pm-plugins/view-mode-sort/utils.js +106 -0
  12. package/dist/cjs/ui/common-styles.js +22 -15
  13. package/dist/es2019/commands/insert.js +4 -7
  14. package/dist/es2019/commands/misc.js +10 -3
  15. package/dist/es2019/nodeviews/TableComponent.js +24 -2
  16. package/dist/es2019/plugin.js +7 -1
  17. package/dist/es2019/pm-plugins/analytics/plugin.js +21 -26
  18. package/dist/es2019/pm-plugins/view-mode-sort/consts.js +3 -0
  19. package/dist/es2019/pm-plugins/view-mode-sort/index.js +243 -0
  20. package/dist/es2019/pm-plugins/view-mode-sort/plugin-key.js +2 -0
  21. package/dist/es2019/pm-plugins/view-mode-sort/types.js +1 -0
  22. package/dist/es2019/pm-plugins/view-mode-sort/utils.js +98 -0
  23. package/dist/es2019/ui/common-styles.js +35 -0
  24. package/dist/esm/commands/insert.js +4 -7
  25. package/dist/esm/commands/misc.js +10 -3
  26. package/dist/esm/nodeviews/TableComponent.js +23 -2
  27. package/dist/esm/plugin.js +7 -1
  28. package/dist/esm/pm-plugins/analytics/plugin.js +17 -22
  29. package/dist/esm/pm-plugins/view-mode-sort/consts.js +3 -0
  30. package/dist/esm/pm-plugins/view-mode-sort/index.js +299 -0
  31. package/dist/esm/pm-plugins/view-mode-sort/plugin-key.js +2 -0
  32. package/dist/esm/pm-plugins/view-mode-sort/types.js +1 -0
  33. package/dist/esm/pm-plugins/view-mode-sort/utils.js +99 -0
  34. package/dist/esm/ui/common-styles.js +15 -8
  35. package/dist/types/pm-plugins/view-mode-sort/consts.d.ts +3 -0
  36. package/dist/types/pm-plugins/view-mode-sort/index.d.ts +10 -0
  37. package/dist/types/pm-plugins/view-mode-sort/plugin-key.d.ts +3 -0
  38. package/dist/types/pm-plugins/view-mode-sort/types.d.ts +17 -0
  39. package/dist/types/pm-plugins/view-mode-sort/utils.d.ts +15 -0
  40. package/dist/types/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +2 -2
  41. package/dist/types/ui/TableFloatingControls/CornerControls/DragCornerControls.d.ts +4 -4
  42. package/dist/types/ui/TableFloatingControls/index.d.ts +2 -2
  43. package/dist/types-ts4.5/pm-plugins/view-mode-sort/consts.d.ts +3 -0
  44. package/dist/types-ts4.5/pm-plugins/view-mode-sort/index.d.ts +10 -0
  45. package/dist/types-ts4.5/pm-plugins/view-mode-sort/plugin-key.d.ts +3 -0
  46. package/dist/types-ts4.5/pm-plugins/view-mode-sort/types.d.ts +21 -0
  47. package/dist/types-ts4.5/pm-plugins/view-mode-sort/utils.d.ts +15 -0
  48. package/dist/types-ts4.5/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +2 -2
  49. package/dist/types-ts4.5/ui/TableFloatingControls/CornerControls/DragCornerControls.d.ts +4 -4
  50. package/dist/types-ts4.5/ui/TableFloatingControls/index.d.ts +2 -2
  51. package/package.json +8 -8
  52. package/src/commands/insert.ts +7 -13
  53. package/src/commands/misc.ts +14 -8
  54. package/src/nodeviews/TableComponent.tsx +22 -0
  55. package/src/plugin.tsx +12 -3
  56. package/src/pm-plugins/analytics/plugin.ts +24 -33
  57. package/src/pm-plugins/view-mode-sort/consts.ts +3 -0
  58. package/src/pm-plugins/view-mode-sort/index.ts +257 -0
  59. package/src/pm-plugins/view-mode-sort/plugin-key.ts +6 -0
  60. package/src/pm-plugins/view-mode-sort/types.ts +23 -0
  61. package/src/pm-plugins/view-mode-sort/utils.ts +120 -0
  62. package/src/ui/common-styles.ts +36 -0
@@ -0,0 +1,243 @@
1
+ /**
2
+ * This plugin allows sorting of table nodes in the Editor without modifying the underlying ProseMirror document.
3
+ * Instead of making changes to the ProseMirror document, the plugin sorts the table rows in the DOM. This allows the sorting to be
4
+ * visible to the user without affecting the document's content.
5
+ */
6
+
7
+ import { createElement } from 'react';
8
+ import ReactDOM from 'react-dom';
9
+ import { RawIntlProvider } from 'react-intl-next';
10
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
11
+ import { SortingIcon } from '@atlaskit/editor-common/table';
12
+ import { SortOrder } from '@atlaskit/editor-common/types';
13
+ import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
14
+ import { TableMap } from '@atlaskit/editor-tables/table-map';
15
+ import { getPluginState } from '../plugin-factory';
16
+ import { IS_DISABLED_CLASS_NAME, SORT_INDEX_DATA_ATTRIBUTE, SORTING_ICON_CLASS_NAME } from './consts';
17
+ import { tableViewModeSortPluginKey as key } from './plugin-key';
18
+ import { getTableElements, toggleSort } from './utils';
19
+ export const createPlugin = editorViewModeAPI => {
20
+ return new SafePlugin({
21
+ state: {
22
+ init: () => ({
23
+ decorations: DecorationSet.empty,
24
+ sort: {},
25
+ allTables: []
26
+ }),
27
+ apply(tr, pluginState, oldState) {
28
+ // TODO - move this mode check to plugin creation if possible. Right now it's here because the initial state
29
+ // does not appear correct when the plugin is created.
30
+ const {
31
+ mode
32
+ } = (editorViewModeAPI === null || editorViewModeAPI === void 0 ? void 0 : editorViewModeAPI.sharedState.currentState()) || {};
33
+ if (mode !== 'view') {
34
+ return pluginState;
35
+ }
36
+ let {
37
+ decorations,
38
+ sort,
39
+ allTables
40
+ } = pluginState;
41
+ const sortMeta = tr.getMeta('tableSortMeta');
42
+ let hoverTableMeta = tr.getMeta('mouseEnterTable');
43
+ let removeTableMeta = tr.getMeta('removeTable');
44
+ let tableId = '';
45
+
46
+ // Remove the table from the state
47
+ if (removeTableMeta) {
48
+ allTables = allTables.filter(([id]) => id !== removeTableMeta);
49
+ } else {
50
+ tableId = hoverTableMeta === null || hoverTableMeta === void 0 ? void 0 : hoverTableMeta[0];
51
+ }
52
+ sort = {
53
+ ...sort,
54
+ ...sortMeta
55
+ };
56
+ const isTableInState = allTables.some(([id]) => id === tableId);
57
+
58
+ // Update the table in the state
59
+ if (hoverTableMeta) {
60
+ allTables = allTables.filter(([id]) => id !== hoverTableMeta[0]);
61
+ allTables.push(hoverTableMeta);
62
+ }
63
+
64
+ /**
65
+ * Create decorations for the sorting icons
66
+ */
67
+ const decs = [];
68
+
69
+ // TODO - add support for keyboard only users
70
+ if (hoverTableMeta && !isTableInState || sortMeta) {
71
+ allTables.forEach(table => {
72
+ const [tableId, _node, pos] = table;
73
+ const tableNode = tr.doc.nodeAt(tr.mapping.map(pos));
74
+ if (!tableNode || tableNode.type.name !== 'table') {
75
+ return pluginState;
76
+ }
77
+ const map = TableMap.get(tableNode);
78
+ const hasMergedCells = new Set(map.map).size !== map.map.length;
79
+ map.mapByRow[0].forEach((cell, index) => {
80
+ // return pluginState;
81
+ decs.push(Decoration.widget(cell + pos + 2, () => {
82
+ var _sort$tableId;
83
+ const element = document.createElement('div');
84
+ element.setAttribute(SORT_INDEX_DATA_ATTRIBUTE, `${index}`);
85
+ element.classList.add(SORTING_ICON_CLASS_NAME);
86
+ if (hasMergedCells) {
87
+ element.classList.add(IS_DISABLED_CLASS_NAME);
88
+ }
89
+ let sortOrdered;
90
+ if (index === ((_sort$tableId = sort[tableId]) === null || _sort$tableId === void 0 ? void 0 : _sort$tableId.index)) {
91
+ var _sort$tableId2;
92
+ sortOrdered = (_sort$tableId2 = sort[tableId]) === null || _sort$tableId2 === void 0 ? void 0 : _sort$tableId2.direction;
93
+ } else {
94
+ sortOrdered = SortOrder.NO_ORDER;
95
+ }
96
+ const {
97
+ getIntl
98
+ } = getPluginState(oldState);
99
+ ReactDOM.render( /*#__PURE__*/createElement(RawIntlProvider, {
100
+ value: getIntl()
101
+ }, /*#__PURE__*/createElement(SortingIcon, {
102
+ isSortingAllowed: !hasMergedCells,
103
+ sortOrdered,
104
+ onClick: () => {},
105
+ onKeyDown: () => {}
106
+ })), element);
107
+ return element;
108
+ }));
109
+ });
110
+ });
111
+ decorations = DecorationSet.create(tr.doc, decs);
112
+ }
113
+
114
+ /**
115
+ * Map the decorations to the new document if there are changes
116
+ */
117
+ if (tr.docChanged) {
118
+ decorations = decorations.map(tr.mapping, tr.doc);
119
+ allTables = allTables.map(table => {
120
+ return [table[0], table[1], tr.mapping.map(table[2])];
121
+ });
122
+ }
123
+ return {
124
+ decorations,
125
+ sort,
126
+ allTables
127
+ };
128
+ }
129
+ },
130
+ key,
131
+ appendTransaction: (trs, oldState, newState) => {
132
+ var _key$getState;
133
+ // return newState.tr;
134
+ const {
135
+ mode
136
+ } = (editorViewModeAPI === null || editorViewModeAPI === void 0 ? void 0 : editorViewModeAPI.sharedState.currentState()) || {};
137
+ if (mode !== 'view') {
138
+ return newState.tr;
139
+ }
140
+ let allTables = ((_key$getState = key.getState(newState)) === null || _key$getState === void 0 ? void 0 : _key$getState.allTables) || [];
141
+
142
+ /**
143
+ * If incoming changes have affected a table node, remove the sorting. This prevents the
144
+ * table from breaking if changes like merged cells are incoming.
145
+ */
146
+ for (const tr of trs) {
147
+ const hoverTableMeta = tr.getMeta('mouseEnterTable');
148
+ if (hoverTableMeta) {
149
+ allTables = allTables.filter(([id]) => id !== hoverTableMeta[0]);
150
+ allTables.push(hoverTableMeta);
151
+ }
152
+ const isRemote = tr.getMeta('isRemote');
153
+ const isDocChanged = tr.docChanged;
154
+ const isChangesIncoming = isRemote && isDocChanged;
155
+ const oldPluginState = key.getState(oldState);
156
+ const newPluginState = key.getState(newState);
157
+ for (const table of allTables) {
158
+ var _oldPluginState$sort, _newPluginState$sort;
159
+ const [tableId, node, pos] = table;
160
+ const {
161
+ order: oldOrder,
162
+ direction: oldDirection,
163
+ index: oldIndex
164
+ } = (oldPluginState === null || oldPluginState === void 0 ? void 0 : (_oldPluginState$sort = oldPluginState.sort) === null || _oldPluginState$sort === void 0 ? void 0 : _oldPluginState$sort[tableId]) || {};
165
+ if (isChangesIncoming) {
166
+ var _maybeTableNode$attrs;
167
+ const maybeTableNode = tr.doc.nodeAt(pos);
168
+ const isTableNodeChanged = (maybeTableNode === null || maybeTableNode === void 0 ? void 0 : (_maybeTableNode$attrs = maybeTableNode.attrs) === null || _maybeTableNode$attrs === void 0 ? void 0 : _maybeTableNode$attrs.localId) !== tableId || !node.eq(maybeTableNode);
169
+ if (isTableNodeChanged) {
170
+ const newtr = newState.tr;
171
+ newtr.setMeta('tableSortMeta', {
172
+ [tableId]: {}
173
+ });
174
+ newtr.setMeta('removeTable', tableId);
175
+
176
+ // Unsort the table here
177
+ if (oldOrder !== undefined) {
178
+ const {
179
+ rows,
180
+ tbody
181
+ } = getTableElements(tableId);
182
+ if (!rows || !tbody) {
183
+ return newtr;
184
+ }
185
+ const sortedOrder = [...oldOrder].sort((a, b) => a.value - b.value);
186
+ sortedOrder.forEach((index, i) => {
187
+ tbody.appendChild(rows[index.index + 1]);
188
+ });
189
+ return newtr;
190
+ }
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Sort the table if the sort order has changed
196
+ */
197
+ const {
198
+ order: newOrder,
199
+ direction: newDirection,
200
+ index: newIndex
201
+ } = (newPluginState === null || newPluginState === void 0 ? void 0 : (_newPluginState$sort = newPluginState.sort) === null || _newPluginState$sort === void 0 ? void 0 : _newPluginState$sort[tableId]) || {};
202
+ const orderChanged = oldDirection !== newDirection || oldIndex !== newIndex;
203
+ if (orderChanged) {
204
+ if (!isRemote && newDirection !== SortOrder.NO_ORDER) {
205
+ const {
206
+ rows,
207
+ tbody
208
+ } = getTableElements(tableId);
209
+ if (rows && newOrder) {
210
+ newOrder.forEach((index, i) => {
211
+ tbody === null || tbody === void 0 ? void 0 : tbody.appendChild(rows[index.value + 1]);
212
+ });
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ return newState.tr;
219
+ },
220
+ props: {
221
+ handleDOMEvents: {
222
+ keydown: (view, event) => {
223
+ // TODO - fix the focus issue here, where toggling sort with a keypress loses focus
224
+ if (event.key === 'Enter' || event.key === ' ') {
225
+ var _key$getState2;
226
+ const pluginState = ((_key$getState2 = key.getState(view.state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.sort) || {};
227
+ toggleSort(view, event, pluginState);
228
+ }
229
+ },
230
+ click: (view, event) => {
231
+ var _key$getState3;
232
+ const pluginState = ((_key$getState3 = key.getState(view.state)) === null || _key$getState3 === void 0 ? void 0 : _key$getState3.sort) || {};
233
+ toggleSort(view, event, pluginState);
234
+ }
235
+ },
236
+ decorations(state) {
237
+ var _key$getState4;
238
+ const decs = ((_key$getState4 = key.getState(state)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.decorations) || DecorationSet.empty;
239
+ return decs;
240
+ }
241
+ }
242
+ });
243
+ };
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export const tableViewModeSortPluginKey = new PluginKey('tableViewModeSortPlugin');
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,98 @@
1
+ import { SortOrder } from '@atlaskit/editor-common/types';
2
+ import { IS_DISABLED_CLASS_NAME, SORT_INDEX_DATA_ATTRIBUTE, SORTING_ICON_CLASS_NAME } from './consts';
3
+ export const unsort = (oldOrder, tableElement) => {
4
+ const rows = tableElement.querySelectorAll('tr');
5
+ const tbody = tableElement.querySelector('tbody');
6
+ const sortedOrder = [...oldOrder].sort((a, b) => a.value - b.value);
7
+ sortedOrder.forEach(item => {
8
+ tbody === null || tbody === void 0 ? void 0 : tbody.appendChild(rows[item.index + 1]);
9
+ });
10
+ };
11
+
12
+ // TODO - reuse sort logic from the Renderer and support switching between ASC, DESC and NO_ORDER
13
+ export const getSortOrderFromTable = (tableElement, sortIndex, direction) => {
14
+ const sortOrder = direction === SortOrder.DESC ? -1 : 1;
15
+ const strings = [];
16
+ tableElement.querySelectorAll('tr:not([data-header-row="true"])').forEach(tr => {
17
+ var _tr$querySelectorAll$;
18
+ strings.push(((_tr$querySelectorAll$ = tr.querySelectorAll('td')[sortIndex]) === null || _tr$querySelectorAll$ === void 0 ? void 0 : _tr$querySelectorAll$.textContent) || '');
19
+ });
20
+ const order = Array.from(strings.keys()).sort((a, b) => {
21
+ const string = strings[a] || '';
22
+ return string.localeCompare(strings[b] || '') * sortOrder;
23
+ }).map((value, index) => ({
24
+ value,
25
+ index
26
+ }));
27
+ // TODO - improve this. right now this is a workaround to ensure the first tr is always first in the order
28
+ return [{
29
+ value: -1,
30
+ index: -1
31
+ }, ...order];
32
+ };
33
+ export const toggleSort = (view, event, pluginState) => {
34
+ var _target$closest;
35
+ const target = event.target;
36
+ const widget = target.closest(`.${SORTING_ICON_CLASS_NAME}`);
37
+ if (widget !== null && widget !== void 0 && widget.classList.contains(IS_DISABLED_CLASS_NAME) || !widget) {
38
+ return;
39
+ }
40
+ let datasetortIndex = target === null || target === void 0 ? void 0 : (_target$closest = target.closest('.ProseMirror-widget')) === null || _target$closest === void 0 ? void 0 : _target$closest.getAttribute(SORT_INDEX_DATA_ATTRIBUTE);
41
+ const tr = view.state.tr;
42
+ const tableElement = target.closest('table');
43
+ if (!tableElement || !datasetortIndex) {
44
+ return;
45
+ }
46
+ const tableId = tableElement.getAttribute('data-table-local-id') || '';
47
+ let {
48
+ index,
49
+ direction,
50
+ order: oldOrder
51
+ } = (pluginState === null || pluginState === void 0 ? void 0 : pluginState[tableId]) || {};
52
+
53
+ // Unsort if there was already a sort
54
+ if (direction !== SortOrder.NO_ORDER && oldOrder !== undefined) {
55
+ unsort(oldOrder, tableElement);
56
+ }
57
+ const sortIndex = parseInt(datasetortIndex);
58
+ if (sortIndex === index) {
59
+ switch (direction) {
60
+ case SortOrder.NO_ORDER:
61
+ direction = SortOrder.ASC;
62
+ break;
63
+ case SortOrder.ASC:
64
+ direction = SortOrder.DESC;
65
+ break;
66
+ case SortOrder.DESC:
67
+ direction = SortOrder.NO_ORDER;
68
+ break;
69
+ }
70
+ } else {
71
+ direction = SortOrder.ASC; // default direction when a new index is clicked
72
+ }
73
+ const order = getSortOrderFromTable(tableElement, sortIndex, direction);
74
+ if (direction === SortOrder.NO_ORDER) {
75
+ tr.setMeta('tableSortMeta', {
76
+ [tableId]: {}
77
+ });
78
+ } else {
79
+ tr.setMeta('tableSortMeta', {
80
+ [tableId]: {
81
+ index: sortIndex,
82
+ direction,
83
+ order,
84
+ tableElement
85
+ }
86
+ });
87
+ }
88
+ view.dispatch(tr);
89
+ };
90
+ export const getTableElements = tableId => {
91
+ const tableElement = document.querySelector(`table[data-table-local-id="${tableId}"]`);
92
+ const tbody = tableElement === null || tableElement === void 0 ? void 0 : tableElement.querySelector('tbody');
93
+ const rows = tableElement === null || tableElement === void 0 ? void 0 : tableElement.querySelectorAll('tr');
94
+ return {
95
+ tbody,
96
+ rows
97
+ };
98
+ };
@@ -2,12 +2,14 @@
2
2
 
3
3
  import { css } from '@emotion/react';
4
4
  import { tableMarginTop, tableSharedStyle } from '@atlaskit/editor-common/styles';
5
+ import { SORTABLE_COLUMN_ICON_CLASSNAME } from '@atlaskit/editor-common/table';
5
6
  import { browser } from '@atlaskit/editor-common/utils';
6
7
  import { akEditorSelectedNodeClassName, akEditorSmallZIndex, akEditorStickyHeaderZIndex, akEditorTableCellOnStickyHeaderZIndex, akEditorTableNumberColumnWidth, akEditorTableToolbarSize, akEditorUnitZIndex, getSelectionStyles, MAX_BROWSER_SCROLLBAR_HEIGHT, relativeFontSizeToBase16, SelectionStyle } from '@atlaskit/editor-shared-styles';
7
8
  import { scrollbarStyles } from '@atlaskit/editor-shared-styles/scrollbar';
8
9
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
9
10
  import { N0, N40A, R500 } from '@atlaskit/theme/colors';
10
11
  import { fontSize } from '@atlaskit/theme/constants';
12
+ import { SORTING_ICON_CLASS_NAME } from '../pm-plugins/view-mode-sort/consts';
11
13
  import { TableCssClassName as ClassName } from '../types';
12
14
  import { columnControlsDecorationHeight, resizeHandlerAreaWidth, resizeHandlerZIndex, resizeLineWidth, rowControlsZIndex, stickyHeaderBorderBottomWidth, stickyRowOffsetTop, tableBorderColor, tableBorderDeleteColor, tableBorderRadiusSize, tableBorderSelectedColor, tableCellBackgroundColor, tableCellDeleteColor, tableCellSelectedColor, tableControlsSpacing, tableHeaderCellBackgroundColor, tableInsertColumnButtonSize, tableOverflowShadowWidth, tablePadding, tableScrollbarOffset, tableTextColor, tableToolbarDeleteColor, tableToolbarSelectedColor, tableToolbarSize } from './consts';
13
15
  import { columnControlsDecoration, columnControlsLineMarker, DeleteButton, dragCornerControlButton, dragInsertButtonWrapper, floatingColumnControls, HeaderButton, HeaderButtonDanger, HeaderButtonHover, hoveredCell, hoveredDeleteButton, hoveredWarningCell, insertColumnButtonWrapper, insertLine, InsertMarker, insertRowButtonWrapper, OverflowShadow, resizeHandle, rowControlsWrapperDotStyle } from './ui-styles';
@@ -123,6 +125,38 @@ const breakoutWidthStyling = () => {
123
125
  }
124
126
  `;
125
127
  };
128
+ const viewModeSortStyles = () => {
129
+ if (getBooleanFF('platform.editor.table.live-pages-sorting_4malx')) {
130
+ return css`
131
+ th {
132
+ .${SORTING_ICON_CLASS_NAME} {
133
+ + p {
134
+ margin-top: 0 !important;
135
+ }
136
+ }
137
+
138
+ &:has(.is-active) {
139
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
140
+ opacity: 1;
141
+ }
142
+ }
143
+
144
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
145
+ opacity: 0;
146
+ &:focus {
147
+ opacity: 1;
148
+ }
149
+ }
150
+
151
+ &:hover {
152
+ .${SORTABLE_COLUMN_ICON_CLASSNAME} {
153
+ opacity: 1;
154
+ }
155
+ }
156
+ }
157
+ `;
158
+ }
159
+ };
126
160
  const tableBorderStyles = () => {
127
161
  if (getBooleanFF('platform.editor.table.column-controls-styles-updated')) {
128
162
  return `border-color: ${tableBorderDeleteColor}`;
@@ -190,6 +224,7 @@ export const baseTableStyles = props => {
190
224
  ${((_props$featureFlags = props.featureFlags) === null || _props$featureFlags === void 0 ? void 0 : _props$featureFlags.tableDragAndDrop) && insertLine()};
191
225
  ${resizeHandle((_props$featureFlags2 = props.featureFlags) === null || _props$featureFlags2 === void 0 ? void 0 : _props$featureFlags2.tableDragAndDrop)};
192
226
  ${rangeSelectionStyles};
227
+ ${viewModeSortStyles()};
193
228
 
194
229
  .${ClassName.LAST_ITEM_IN_CELL} {
195
230
  margin-bottom: 0;
@@ -5,7 +5,6 @@ import { Selection } from '@atlaskit/editor-prosemirror/state';
5
5
  import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
6
6
  import { TableMap } from '@atlaskit/editor-tables/table-map';
7
7
  import { addColumnAt as addColumnAtPMUtils, addRowAt, findTable, selectedRect } from '@atlaskit/editor-tables/utils';
8
- import { getBooleanFF } from '@atlaskit/platform-feature-flags';
9
8
  import { updateRowOrColumnMovedTransform } from '../pm-plugins/analytics/commands';
10
9
  import { META_KEYS } from '../pm-plugins/table-analytics';
11
10
  import { rescaleColumns } from '../transforms/column-width';
@@ -37,7 +36,7 @@ export function addColumnAt() {
37
36
  // [ED-8288] Update colwidths manually to avoid multiple dispatch in TableComponent
38
37
  updatedTr = rescaleColumns(isTableScalingEnabled)(table, view)(updatedTr);
39
38
  }
40
- if (getBooleanFF('platform.editor.table.analytics-plugin-moved-event') && view) {
39
+ if (view) {
41
40
  updatedTr = updateRowOrColumnMovedTransform({
42
41
  type: 'column'
43
42
  }, 'addRowOrColumn')(view.state, updatedTr);
@@ -125,11 +124,9 @@ export var insertRow = function insertRow(row, moveCursorToTheNewRow) {
125
124
  } else {
126
125
  tr.setSelection(selection.map(tr.doc, tr.mapping));
127
126
  }
128
- if (getBooleanFF('platform.editor.table.analytics-plugin-moved-event')) {
129
- updateRowOrColumnMovedTransform({
130
- type: 'row'
131
- }, 'addRowOrColumn')(state, tr);
132
- }
127
+ updateRowOrColumnMovedTransform({
128
+ type: 'row'
129
+ }, 'addRowOrColumn')(state, tr);
133
130
  dispatch(tr);
134
131
  }
135
132
  return true;
@@ -188,9 +188,16 @@ export var getTableElementMoveTypeBySlice = function getTableElementMoveTypeBySl
188
188
  if (slice.content.childCount === 1 && slice.content.firstChild.type === tableRow) {
189
189
  return 'row';
190
190
  }
191
- var map = TableMap.get(currentTable.node);
192
- var slicedMap = TableMap.get(slice.content.firstChild);
193
- return map.width === slicedMap.width ? 'row' : map.height === slicedMap.height ? 'column' : undefined;
191
+
192
+ // `TableMap.get` can throw if the content is invalid - in which case we should just
193
+ // return undefined
194
+ try {
195
+ var map = TableMap.get(currentTable.node);
196
+ var slicedMap = TableMap.get(slice.content.firstChild);
197
+ return map.width === slicedMap.width ? 'row' : map.height === slicedMap.height ? 'column' : undefined;
198
+ } catch (e) {
199
+ return undefined;
200
+ }
194
201
  };
195
202
  export var isInsideFirstCellOfRowOrColumn = function isInsideFirstCellOfRowOrColumn(selection, type) {
196
203
  var table = findTable(selection);
@@ -66,6 +66,14 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
66
66
  scroll: 0,
67
67
  parentWidth: undefined
68
68
  }, _defineProperty(_defineProperty2, ShadowEvent.SHOW_BEFORE_SHADOW, false), _defineProperty(_defineProperty2, ShadowEvent.SHOW_AFTER_SHADOW, false), _defineProperty(_defineProperty2, "tableWrapperWidth", undefined), _defineProperty(_defineProperty2, "tableWrapperHeight", undefined), _defineProperty2));
69
+ _defineProperty(_assertThisInitialized(_this), "handleMouseEnter", function () {
70
+ var node = _this.props.getNode();
71
+ var pos = _this.props.getPos();
72
+ var tr = _this.props.view.state.tr;
73
+ var tableId = node.attrs.localId;
74
+ tr.setMeta('mouseEnterTable', [tableId, node, pos]);
75
+ _this.props.view.dispatch(tr);
76
+ });
69
77
  _defineProperty(_assertThisInitialized(_this), "updateShadowState", function (shadowKey, value) {
70
78
  if (_this.state[shadowKey] === value) {
71
79
  return;
@@ -331,6 +339,15 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
331
339
  getNode = _this$props7.getNode,
332
340
  getEditorFeatureFlags = _this$props7.getEditorFeatureFlags,
333
341
  isTableScalingEnabled = _this$props7.isTableScalingEnabled;
342
+ if (getBooleanFF('platform.editor.table.live-pages-sorting_4malx')) {
343
+ var _this$props$pluginInj;
344
+ var _ref = ((_this$props$pluginInj = this.props.pluginInjectionApi) === null || _this$props$pluginInj === void 0 || (_this$props$pluginInj = _this$props$pluginInj.editorViewMode) === null || _this$props$pluginInj === void 0 ? void 0 : _this$props$pluginInj.sharedState.currentState()) || {},
345
+ mode = _ref.mode;
346
+ if (mode === 'view') {
347
+ var _this$table;
348
+ this === null || this === void 0 || (_this$table = this.table) === null || _this$table === void 0 || _this$table.addEventListener('mouseenter', this.handleMouseEnter);
349
+ }
350
+ }
334
351
  if (isTableScalingEnabled) {
335
352
  this.handleColgroupUpdates(true);
336
353
  }
@@ -406,6 +423,10 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
406
423
  if (!(options !== null && options !== void 0 && options.isTableResizingEnabled) && allowColumnResizing) {
407
424
  window.removeEventListener('resize', this.handleWindowResizeDebounced);
408
425
  }
426
+ if (getBooleanFF('platform.editor.table.live-pages-sorting_4malx')) {
427
+ var _this$table2;
428
+ this === null || this === void 0 || (_this$table2 = this.table) === null || _this$table2 === void 0 || _this$table2.removeEventListener('mouseenter', this.handleMouseEnter);
429
+ }
409
430
  if (this.overflowShadowsObserver) {
410
431
  this.overflowShadowsObserver.dispose();
411
432
  }
@@ -520,8 +541,8 @@ var TableComponent = /*#__PURE__*/function (_React$Component) {
520
541
  var isNoOfColumnsChanged = tablesHaveDifferentNoOfColumns(currentTable, previousTable);
521
542
  var isNoOfRowsChanged = tablesHaveDifferentNoOfRows(currentTable, previousTable);
522
543
  if (isNoOfColumnsChanged || isNoOfRowsChanged) {
523
- var _this$props$pluginInj;
524
- (_this$props$pluginInj = this.props.pluginInjectionApi) === null || _this$props$pluginInj === void 0 || (_this$props$pluginInj = _this$props$pluginInj.accessibilityUtils) === null || _this$props$pluginInj === void 0 || _this$props$pluginInj.actions.ariaNotify(getAssistiveMessage(previousTable, currentTable, this.props.intl), {
544
+ var _this$props$pluginInj2;
545
+ (_this$props$pluginInj2 = this.props.pluginInjectionApi) === null || _this$props$pluginInj2 === void 0 || (_this$props$pluginInj2 = _this$props$pluginInj2.accessibilityUtils) === null || _this$props$pluginInj2 === void 0 || _this$props$pluginInj2.actions.ariaNotify(getAssistiveMessage(previousTable, currentTable, this.props.intl), {
525
546
  priority: 'important'
526
547
  });
527
548
  }
@@ -27,6 +27,7 @@ import { createPlugin as createTableLocalIdPlugin } from './pm-plugins/table-loc
27
27
  import { createPlugin as createFlexiResizingPlugin, getPluginState as getFlexiResizingPlugin, pluginKey as tableResizingPluginKey } from './pm-plugins/table-resizing';
28
28
  import { tableSelectionKeymapPlugin } from './pm-plugins/table-selection-keymap';
29
29
  import { createPlugin as createTableWidthPlugin, pluginKey as tableWidthPluginKey } from './pm-plugins/table-width';
30
+ import { createPlugin as createViewModeSortPlugin } from './pm-plugins/view-mode-sort';
30
31
  import { getToolbarConfig } from './toolbar';
31
32
  import FloatingContextualButton from './ui/FloatingContextualButton';
32
33
  import FloatingContextualMenu from './ui/FloatingContextualMenu';
@@ -219,6 +220,11 @@ var tablesPlugin = function tablesPlugin(_ref) {
219
220
  var dispatch = _ref11.dispatch;
220
221
  return options !== null && options !== void 0 && options.dragAndDropEnabled ? createDragAndDropPlugin(dispatch, editorAnalyticsAPI) : undefined;
221
222
  }
223
+ }, {
224
+ name: 'tableViewModeSort',
225
+ plugin: function plugin() {
226
+ return getBooleanFF('platform.editor.table.live-pages-sorting_4malx') && api !== null && api !== void 0 && api.editorViewMode ? createViewModeSortPlugin(api.editorViewMode) : undefined;
227
+ }
222
228
  }, {
223
229
  name: 'tableLocalId',
224
230
  plugin: function plugin(_ref12) {
@@ -248,7 +254,7 @@ var tablesPlugin = function tablesPlugin(_ref) {
248
254
  plugin: function plugin(_ref15) {
249
255
  var dispatch = _ref15.dispatch,
250
256
  dispatchAnalyticsEvent = _ref15.dispatchAnalyticsEvent;
251
- return getBooleanFF('platform.editor.table.analytics-plugin-moved-event') ? createTableAnalyticsPlugin(dispatch, dispatchAnalyticsEvent) : undefined;
257
+ return createTableAnalyticsPlugin(dispatch, dispatchAnalyticsEvent);
252
258
  }
253
259
  }, {
254
260
  name: 'tableGetEditorViewReferencePlugin',
@@ -1,6 +1,5 @@
1
1
  import { ACTION_SUBJECT, EVENT_TYPE, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
2
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
- import { getBooleanFF } from '@atlaskit/platform-feature-flags';
4
3
  import { countCellsInSlice, getTableElementMoveTypeBySlice, getTableSelectionType, isInsideFirstCellOfRowOrColumn } from '../../commands/misc';
5
4
  import { resetRowOrColumnMovedTransform, updateRowOrColumnMoved } from './commands';
6
5
  import { createPluginState } from './plugin-factory';
@@ -34,33 +33,29 @@ export var createPlugin = function createPlugin(dispatch, dispatchAnalyticsEvent
34
33
  handlePaste: function handlePaste(_ref, event, slice) {
35
34
  var state = _ref.state,
36
35
  dispatch = _ref.dispatch;
37
- if (getBooleanFF('platform.editor.table.analytics-plugin-moved-event')) {
38
- var schema = state.schema;
39
- var type = getTableElementMoveTypeBySlice(slice, state);
36
+ var schema = state.schema;
37
+ var type = getTableElementMoveTypeBySlice(slice, state);
40
38
 
41
- // if the selection wasn't in the first cell of a row or column, don't count it
42
- if (!type || !isInsideFirstCellOfRowOrColumn(state.selection, type)) {
43
- return;
44
- }
45
- var count = countCellsInSlice(slice, schema, type);
46
- updateRowOrColumnMoved({
47
- numberOfCells: count,
48
- type: type
49
- }, 'pasted')(state, dispatch);
39
+ // if the selection wasn't in the first cell of a row or column, don't count it
40
+ if (!type || !isInsideFirstCellOfRowOrColumn(state.selection, type)) {
41
+ return;
50
42
  }
43
+ var count = countCellsInSlice(slice, schema, type);
44
+ updateRowOrColumnMoved({
45
+ numberOfCells: count,
46
+ type: type
47
+ }, 'pasted')(state, dispatch);
51
48
  },
52
49
  transformCopied: function transformCopied(slice, _ref2) {
53
50
  var state = _ref2.state,
54
51
  dispatch = _ref2.dispatch;
55
- if (getBooleanFF('platform.editor.table.analytics-plugin-moved-event')) {
56
- var schema = state.schema;
57
- var type = getTableSelectionType(state.selection);
58
- var count = countCellsInSlice(slice, schema, type);
59
- updateRowOrColumnMoved({
60
- numberOfCells: count,
61
- type: type
62
- }, 'copyOrCut')(state, dispatch);
63
- }
52
+ var schema = state.schema;
53
+ var type = getTableSelectionType(state.selection);
54
+ var count = countCellsInSlice(slice, schema, type);
55
+ updateRowOrColumnMoved({
56
+ numberOfCells: count,
57
+ type: type
58
+ }, 'copyOrCut')(state, dispatch);
64
59
  return slice;
65
60
  }
66
61
  }
@@ -0,0 +1,3 @@
1
+ export var SORTING_ICON_CLASS_NAME = 'view-mode-sorting-icon';
2
+ export var IS_DISABLED_CLASS_NAME = 'is-disabled';
3
+ export var SORT_INDEX_DATA_ATTRIBUTE = 'data-sort-index';