@atlaskit/editor-plugin-table 0.0.6 → 0.0.8

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 (90) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/plugins/table/event-handlers.js +7 -6
  3. package/dist/cjs/plugins/table/nodeviews/table.js +4 -2
  4. package/dist/cjs/plugins/table/nodeviews/tableCell.js +4 -4
  5. package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
  6. package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
  7. package/dist/cjs/plugins/table/toolbar.js +0 -1
  8. package/dist/cjs/plugins/table/ui/TableFloatingControls/CornerControls/index.js +23 -10
  9. package/dist/cjs/plugins/table/ui/TableFloatingControls/RowControls/index.js +23 -10
  10. package/dist/cjs/plugins/table/ui/TableFloatingControls/index.js +4 -4
  11. package/dist/cjs/plugins/table/utils/column-controls.js +1 -1
  12. package/dist/cjs/version.json +1 -1
  13. package/dist/es2019/plugins/table/event-handlers.js +8 -7
  14. package/dist/es2019/plugins/table/nodeviews/table.js +4 -2
  15. package/dist/es2019/plugins/table/nodeviews/tableCell.js +3 -4
  16. package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
  17. package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
  18. package/dist/es2019/plugins/table/toolbar.js +1 -2
  19. package/dist/es2019/plugins/table/ui/TableFloatingControls/CornerControls/index.js +18 -3
  20. package/dist/es2019/plugins/table/ui/TableFloatingControls/RowControls/index.js +18 -3
  21. package/dist/es2019/plugins/table/ui/TableFloatingControls/index.js +2 -2
  22. package/dist/es2019/plugins/table/utils/column-controls.js +1 -1
  23. package/dist/es2019/version.json +1 -1
  24. package/dist/esm/plugins/table/event-handlers.js +8 -7
  25. package/dist/esm/plugins/table/nodeviews/table.js +4 -2
  26. package/dist/esm/plugins/table/nodeviews/tableCell.js +3 -4
  27. package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
  28. package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
  29. package/dist/esm/plugins/table/toolbar.js +1 -2
  30. package/dist/esm/plugins/table/ui/TableFloatingControls/CornerControls/index.js +19 -9
  31. package/dist/esm/plugins/table/ui/TableFloatingControls/RowControls/index.js +19 -9
  32. package/dist/esm/plugins/table/ui/TableFloatingControls/index.js +2 -2
  33. package/dist/esm/plugins/table/utils/column-controls.js +1 -1
  34. package/dist/esm/version.json +1 -1
  35. package/dist/types/plugins/table/nodeviews/types.d.ts +1 -0
  36. package/dist/types/plugins/table/ui/TableFloatingControls/CornerControls/index.d.ts +5 -8
  37. package/dist/types/plugins/table/ui/TableFloatingControls/RowControls/index.d.ts +5 -5
  38. package/dist/types-ts4.0/plugins/table/nodeviews/types.d.ts +1 -0
  39. package/dist/types-ts4.0/plugins/table/ui/TableFloatingControls/CornerControls/index.d.ts +5 -8
  40. package/dist/types-ts4.0/plugins/table/ui/TableFloatingControls/RowControls/index.d.ts +5 -5
  41. package/package.json +10 -3
  42. package/src/__tests__/unit/analytics.ts +737 -0
  43. package/src/__tests__/unit/collab.ts +76 -0
  44. package/src/__tests__/unit/commands/sort.ts +230 -0
  45. package/src/__tests__/unit/copy-paste.ts +686 -0
  46. package/src/__tests__/unit/event-handlers/index.ts +106 -0
  47. package/src/__tests__/unit/event-handlers.ts +202 -0
  48. package/src/__tests__/unit/fix-tables.ts +156 -0
  49. package/src/__tests__/unit/floating-toolbar.ts +95 -0
  50. package/src/__tests__/unit/handlers.ts +81 -0
  51. package/src/__tests__/unit/hover-selection.ts +277 -0
  52. package/src/__tests__/unit/index-with-fake-timers.ts +107 -0
  53. package/src/__tests__/unit/index.ts +986 -0
  54. package/src/__tests__/unit/keymap.ts +602 -0
  55. package/src/__tests__/unit/layout.ts +196 -0
  56. package/src/__tests__/unit/nodeviews/cell.ts +167 -0
  57. package/src/__tests__/unit/pm-plugins/table-resizing/utils/resize-state.ts +33 -0
  58. package/src/__tests__/unit/sort-column.ts +512 -0
  59. package/src/__tests__/unit/transforms/delete-columns.ts +499 -0
  60. package/src/__tests__/unit/transforms/delete-rows.ts +557 -0
  61. package/src/__tests__/unit/transforms/merging.ts +374 -0
  62. package/src/__tests__/unit/ui/CornerControls.tsx +80 -0
  63. package/src/__tests__/unit/ui/FloatingContextualButton.tsx +95 -0
  64. package/src/__tests__/unit/ui/FloatingDeleteButton.tsx +175 -0
  65. package/src/__tests__/unit/ui/FloatingInsertButton.tsx +266 -0
  66. package/src/__tests__/unit/ui/RowControls.tsx +301 -0
  67. package/src/__tests__/unit/ui/TableFloatingControls.tsx +93 -0
  68. package/src/__tests__/unit/undo-redo.ts +202 -0
  69. package/src/__tests__/unit/utils/dom.ts +286 -0
  70. package/src/__tests__/unit/utils/nodes.ts +59 -0
  71. package/src/__tests__/unit/utils/row-controls.ts +176 -0
  72. package/src/__tests__/unit/utils/table.ts +93 -0
  73. package/src/__tests__/unit/utils.ts +652 -0
  74. package/src/plugins/table/__tests__/unit/commands/insert.ts +2 -2
  75. package/src/plugins/table/__tests__/unit/commands.ts +2 -2
  76. package/src/plugins/table/__tests__/unit/nodeviews/TableComponent.tsx +2 -2
  77. package/src/plugins/table/__tests__/unit/nodeviews/table.ts +1 -0
  78. package/src/plugins/table/event-handlers.ts +5 -6
  79. package/src/plugins/table/nodeviews/table.tsx +7 -0
  80. package/src/plugins/table/nodeviews/tableCell.tsx +5 -4
  81. package/src/plugins/table/nodeviews/types.ts +1 -0
  82. package/src/plugins/table/pm-plugins/table-resizing/utils/column-state.ts +1 -1
  83. package/src/plugins/table/pm-plugins/table-resizing/utils/resize-logic.ts +6 -2
  84. package/src/plugins/table/toolbar.ts +0 -1
  85. package/src/plugins/table/ui/FloatingContextualMenu/__tests__/ContextualMenu.tsx +1 -1
  86. package/src/plugins/table/ui/FloatingContextualMenu/__tests__/FloatingContextualMenu.tsx +1 -1
  87. package/src/plugins/table/ui/TableFloatingControls/CornerControls/index.tsx +19 -1
  88. package/src/plugins/table/ui/TableFloatingControls/RowControls/index.tsx +16 -1
  89. package/src/plugins/table/ui/TableFloatingControls/index.tsx +2 -2
  90. package/src/plugins/table/utils/column-controls.ts +1 -1
@@ -0,0 +1,277 @@
1
+ import { EditorView } from 'prosemirror-view';
2
+ import {
3
+ getCellsInColumn,
4
+ getCellsInRow,
5
+ getCellsInTable,
6
+ } from '@atlaskit/editor-tables/utils';
7
+ import {
8
+ createProsemirrorEditorFactory,
9
+ Preset,
10
+ LightEditorPlugin,
11
+ } from '@atlaskit/editor-test-helpers/create-prosemirror-editor';
12
+ import {
13
+ doc,
14
+ p,
15
+ table,
16
+ tr,
17
+ tdEmpty,
18
+ tdCursor,
19
+ DocBuilder,
20
+ } from '@atlaskit/editor-test-helpers/doc-builder';
21
+ import { selectColumns } from '@atlaskit/editor-test-helpers/table';
22
+
23
+ import {
24
+ clearHoverSelection,
25
+ hoverColumns,
26
+ hoverRows,
27
+ hoverTable,
28
+ } from '../../plugins/table/commands';
29
+ import {
30
+ TableDecorations,
31
+ TableCssClassName as ClassName,
32
+ TablePluginState,
33
+ } from '../../plugins/table/types';
34
+ import { pluginKey } from '../../plugins/table/pm-plugins/plugin-key';
35
+ import { getDecorations } from '../../plugins/table/pm-plugins/decorations/plugin';
36
+ import tablePlugin from '../../plugins/table-plugin';
37
+ import { PluginKey } from 'prosemirror-state';
38
+
39
+ describe('table hover selection plugin', () => {
40
+ const createEditor = createProsemirrorEditorFactory();
41
+ const preset = new Preset<LightEditorPlugin>().add(tablePlugin);
42
+
43
+ const editor = (doc: DocBuilder) =>
44
+ createEditor<TablePluginState, PluginKey>({
45
+ doc,
46
+ preset,
47
+ pluginKey,
48
+ });
49
+
50
+ const getTableDecorations = (
51
+ editorView: EditorView,
52
+ cells: Array<{ pos: number }>,
53
+ key?: TableDecorations,
54
+ ) => {
55
+ const decorationSet = getDecorations(editorView.state);
56
+
57
+ if (key) {
58
+ return decorationSet.find(
59
+ cells[0].pos,
60
+ cells[cells.length - 1].pos,
61
+ (spec) => spec.key.indexOf(key) > -1,
62
+ );
63
+ }
64
+
65
+ return decorationSet.find(cells[0].pos, cells[cells.length - 1].pos);
66
+ };
67
+
68
+ describe('when table has 3 columns/2 rows', () => {
69
+ let editorView: EditorView;
70
+ beforeEach(() => {
71
+ const mountedEditor = editor(
72
+ doc(
73
+ p('text'),
74
+ table()(
75
+ tr(tdCursor, tdEmpty, tdEmpty),
76
+ tr(tdEmpty, tdEmpty, tdEmpty),
77
+ ),
78
+ ),
79
+ );
80
+
81
+ editorView = mountedEditor.editorView;
82
+ });
83
+
84
+ describe('selectColumn(1)', () => {
85
+ const column = 1;
86
+ beforeEach(() => {
87
+ selectColumns([column])(editorView.state, editorView.dispatch);
88
+ });
89
+
90
+ it('should add decoration', () => {
91
+ const cells = getCellsInColumn(column)(editorView.state.selection)!;
92
+
93
+ const decor = getTableDecorations(
94
+ editorView,
95
+ cells,
96
+ TableDecorations.COLUMN_SELECTED,
97
+ );
98
+
99
+ expect(decor).toHaveLength(2);
100
+ });
101
+ });
102
+
103
+ describe('hoverColumn(number)', () => {
104
+ it('can create a hover selection over multiple columns', () => {
105
+ hoverColumns([0, 1])(editorView.state, editorView.dispatch);
106
+ const cells = getCellsInColumn(0)(editorView.state.selection)!.concat(
107
+ getCellsInColumn(1)(editorView.state.selection)!,
108
+ );
109
+
110
+ expect(
111
+ getTableDecorations(
112
+ editorView,
113
+ cells,
114
+ TableDecorations.ALL_CONTROLS_HOVER,
115
+ ),
116
+ ).toHaveLength(4);
117
+ });
118
+
119
+ describe.each([0, 1, 2])(
120
+ 'when called hoverColumns with [%d]',
121
+ (column) => {
122
+ it('should create a hover selection of column', () => {
123
+ hoverColumns([column])(editorView.state, editorView.dispatch);
124
+ const decos = getTableDecorations(
125
+ editorView,
126
+ getCellsInColumn(column)(editorView.state.selection)!,
127
+ TableDecorations.ALL_CONTROLS_HOVER,
128
+ );
129
+
130
+ // selection spans 2 cells in the selected column (because we have 2 rows in the table)
131
+ expect(decos).toHaveLength(2);
132
+ });
133
+
134
+ it('should apply the hovered column class', () => {
135
+ hoverColumns([column])(editorView.state, editorView.dispatch);
136
+
137
+ const decos = getTableDecorations(
138
+ editorView,
139
+ getCellsInColumn(column)(editorView.state.selection)!,
140
+ TableDecorations.ALL_CONTROLS_HOVER,
141
+ );
142
+
143
+ decos.forEach((deco) => {
144
+ expect(deco).toEqual(
145
+ expect.objectContaining({
146
+ type: expect.objectContaining({
147
+ attrs: expect.objectContaining({
148
+ class: expect.stringContaining(ClassName.HOVERED_COLUMN),
149
+ }),
150
+ }),
151
+ }),
152
+ );
153
+ });
154
+ });
155
+
156
+ it('can apply the danger class to the decoration', () => {
157
+ hoverColumns([column], true)(editorView.state, editorView.dispatch);
158
+
159
+ const decos = getTableDecorations(
160
+ editorView,
161
+ getCellsInColumn(column)(editorView.state.selection)!,
162
+ TableDecorations.ALL_CONTROLS_HOVER,
163
+ );
164
+
165
+ expect(decos).toHaveLength(2);
166
+ const expected = [
167
+ ClassName.HOVERED_CELL_IN_DANGER,
168
+ ClassName.HOVERED_COLUMN,
169
+ ];
170
+
171
+ decos.forEach((deco) => {
172
+ // @ts-ignore
173
+ expect(deco.type.attrs.class.split(' ')).toEqual(
174
+ expect.arrayContaining(expected),
175
+ );
176
+ });
177
+ });
178
+ },
179
+ );
180
+ });
181
+ });
182
+
183
+ describe('hoverRow(number)', () => {
184
+ describe('when table has 3 rows', () => {
185
+ let editorView: EditorView;
186
+ beforeEach(() => {
187
+ const mountedEditor = editor(
188
+ doc(
189
+ p('text'),
190
+ table()(
191
+ tr(tdCursor, tdEmpty),
192
+ tr(tdEmpty, tdEmpty),
193
+ tr(tdEmpty, tdEmpty),
194
+ ),
195
+ ),
196
+ );
197
+
198
+ editorView = mountedEditor.editorView;
199
+ });
200
+
201
+ it('can create a hover selection over multiple rows', () => {
202
+ hoverRows([0, 1])(editorView.state, editorView.dispatch);
203
+ const cells = getCellsInRow(0)(editorView.state.selection)!.concat(
204
+ getCellsInRow(1)(editorView.state.selection)!,
205
+ );
206
+
207
+ expect(
208
+ getTableDecorations(
209
+ editorView,
210
+ cells,
211
+ TableDecorations.ALL_CONTROLS_HOVER,
212
+ ),
213
+ ).toHaveLength(4);
214
+ });
215
+
216
+ describe.each([0, 1, 2])('when called hoverRows with [%d]', (row) => {
217
+ it('should create a hover selection of row', () => {
218
+ hoverRows([row])(editorView.state, editorView.dispatch);
219
+ expect(
220
+ getTableDecorations(
221
+ editorView,
222
+ getCellsInRow(row)(editorView.state.selection)!,
223
+ TableDecorations.ALL_CONTROLS_HOVER,
224
+ ),
225
+ ).toHaveLength(2);
226
+ });
227
+
228
+ it('can apply the danger class to the decoration', () => {
229
+ hoverRows([row], true)(editorView.state, editorView.dispatch);
230
+ const cells = getCellsInRow(row)(editorView.state.selection)!;
231
+ const decos = getTableDecorations(
232
+ editorView,
233
+ cells,
234
+ TableDecorations.ALL_CONTROLS_HOVER,
235
+ );
236
+
237
+ expect(decos).toHaveLength(2);
238
+ decos.forEach((deco) => {
239
+ // @ts-ignore
240
+ expect(deco.type.attrs.class.split(' ')).toContain('danger');
241
+ });
242
+ });
243
+ });
244
+ });
245
+ });
246
+
247
+ describe('hovertable()', () => {
248
+ describe('when table has 3 rows', () => {
249
+ it('should create a hover selection of the whole table', () => {
250
+ const { editorView } = editor(
251
+ doc(
252
+ p('text'),
253
+ table()(
254
+ tr(tdCursor, tdEmpty),
255
+ tr(tdEmpty, tdEmpty),
256
+ tr(tdEmpty, tdEmpty),
257
+ ),
258
+ ),
259
+ );
260
+
261
+ hoverTable()(editorView.state, editorView.dispatch);
262
+
263
+ // selection should span all 6 cells
264
+ expect(
265
+ getTableDecorations(
266
+ editorView,
267
+ getCellsInTable(editorView.state.selection)!,
268
+ TableDecorations.ALL_CONTROLS_HOVER,
269
+ ),
270
+ ).toHaveLength(6);
271
+
272
+ // reset hover selection plugin to an empty DecorationSet
273
+ clearHoverSelection()(editorView.state, editorView.dispatch);
274
+ });
275
+ });
276
+ });
277
+ });
@@ -0,0 +1,107 @@
1
+ // TODO: ensure this works as I have removed sinon here
2
+ import { defaultSchema } from '@atlaskit/adf-schema/schema-default';
3
+ import { createEditorFactory } from '@atlaskit/editor-test-helpers/create-editor';
4
+ import {
5
+ doc,
6
+ p,
7
+ table,
8
+ tr,
9
+ tdEmpty,
10
+ tdCursor,
11
+ DocBuilder,
12
+ } from '@atlaskit/editor-test-helpers/doc-builder';
13
+ import TableView from '../../plugins/table/nodeviews/table';
14
+ import { TablePluginState, PluginConfig } from '../../plugins/table/types';
15
+ import { pluginKey } from '../../plugins/table/pm-plugins/plugin-key';
16
+ import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
17
+
18
+ // TODO: this doesn't work
19
+ describe.skip('TableView', () => {
20
+ const createEditor = createEditorFactory<TablePluginState>();
21
+ const getEditorContainerWidth = () => ({ width: 500 });
22
+ const fakeGetEditorFeatureFlags = () => ({});
23
+ const originalHandleRef = (TableView.prototype as any).handleRef;
24
+ const handleRefInnerMock = jest.fn(originalHandleRef);
25
+ let handleRefMock: jest.SpyInstance;
26
+
27
+ const editor = (doc: DocBuilder) => {
28
+ const tableOptions = {
29
+ allowNumberColumn: true,
30
+ allowHeaderRow: true,
31
+ allowHeaderColumn: true,
32
+ permittedLayouts: 'all',
33
+ } as PluginConfig;
34
+ return createEditor({
35
+ doc,
36
+ editorProps: {
37
+ allowTables: tableOptions,
38
+ media: {
39
+ allowMediaSingle: true,
40
+ },
41
+ },
42
+ pluginKey,
43
+ });
44
+ };
45
+
46
+ // beforeEach(() => {
47
+ // handleRefMock = jest
48
+ // .spyOn(Object.getPrototypeOf(TableView), 'handleRef')
49
+ // .mockImplementation(() => {
50
+ // console.log('getting called?');
51
+ // // window.setTimeout(() => handleRefInnerMock.call(this, ref), 0);
52
+ // });
53
+ // });
54
+ // previous regression involved PM trying to render child DOM elements,
55
+ // but the NodeView had an undefined contentDOM after the React render finishes
56
+ // (since render is not synchronous)
57
+ it('always provides a content DOM', function (this: any) {
58
+ jest.useFakeTimers();
59
+
60
+ // in the tests, handleRef gets called immediately (due to event loop ordering)
61
+ // however, the ref callback function can be called async from React after
62
+ // calling render, which can often occur in the browser
63
+ //
64
+ // to simulate this, we add a callback to force it to run out-of-order
65
+ // const handleRefMock = sinon
66
+ // // @ts-ignore
67
+ // .stub(TableView.prototype, '_handleRef')
68
+ // .callsFake((ref: HTMLElement) => {
69
+ // window.setTimeout(() => handleRefInnerMock.call(this, ref), 0);
70
+ // });
71
+
72
+ // create the NodeView
73
+ const node = table()(tr(tdCursor, tdEmpty, tdEmpty))(defaultSchema);
74
+ const { editorView, portalProviderAPI } = editor(doc(p()));
75
+ const eventDispatcher = ({ on: () => {} } as unknown) as EventDispatcher;
76
+ const tableView = new TableView({
77
+ node,
78
+ allowColumnResizing: false,
79
+ view: editorView,
80
+ portalProviderAPI,
81
+ eventDispatcher,
82
+ getPos: () => 1,
83
+ getEditorContainerWidth,
84
+ getEditorFeatureFlags: fakeGetEditorFeatureFlags,
85
+ hasIntlContext: true,
86
+ }).init();
87
+
88
+ // we expect to have a contentDOM after instanciating the NodeView so that
89
+ // ProseMirror will render the node's children into the element
90
+ expect(tableView.contentDOM).toBeDefined();
91
+
92
+ // we shouldn't have called the mock yet, since it's behind the window.setTimeout
93
+ expect(handleRefInnerMock).not.toBeCalled();
94
+
95
+ // run the timers through
96
+ jest.runAllTimers();
97
+
98
+ // the timer should have expired now
99
+ expect(handleRefInnerMock).toBeCalled();
100
+
101
+ // ensure we still have a contentDOM
102
+ expect(tableView.contentDOM).toBeDefined();
103
+
104
+ // reset the mock
105
+ handleRefMock.mockClear();
106
+ });
107
+ });