@atlaskit/editor-plugin-table 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/cjs/plugins/table/commands-with-analytics.js +6 -0
- package/dist/cjs/plugins/table/event-handlers.js +7 -6
- package/dist/cjs/plugins/table/nodeviews/tableCell.js +4 -4
- package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
- package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
- package/dist/cjs/plugins/table/utils/column-controls.js +1 -1
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/plugins/table/commands-with-analytics.js +6 -0
- package/dist/es2019/plugins/table/event-handlers.js +8 -7
- package/dist/es2019/plugins/table/nodeviews/tableCell.js +3 -4
- package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
- package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
- package/dist/es2019/plugins/table/utils/column-controls.js +1 -1
- package/dist/es2019/version.json +1 -1
- package/dist/esm/plugins/table/commands-with-analytics.js +6 -0
- package/dist/esm/plugins/table/event-handlers.js +8 -7
- package/dist/esm/plugins/table/nodeviews/tableCell.js +3 -4
- package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
- package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
- package/dist/esm/plugins/table/utils/column-controls.js +1 -1
- package/dist/esm/version.json +1 -1
- package/package.json +9 -7
- package/report.api.md +13 -6
- package/src/__tests__/unit/analytics.ts +737 -0
- package/src/__tests__/unit/collab.ts +76 -0
- package/src/__tests__/unit/commands/sort.ts +230 -0
- package/src/__tests__/unit/copy-paste.ts +686 -0
- package/src/__tests__/unit/event-handlers/index.ts +106 -0
- package/src/__tests__/unit/event-handlers.ts +202 -0
- package/src/__tests__/unit/fix-tables.ts +156 -0
- package/src/__tests__/unit/floating-toolbar.ts +95 -0
- package/src/__tests__/unit/handlers.ts +81 -0
- package/src/__tests__/unit/hover-selection.ts +277 -0
- package/src/__tests__/unit/index-with-fake-timers.ts +106 -0
- package/src/__tests__/unit/index.ts +986 -0
- package/src/__tests__/unit/keymap.ts +602 -0
- package/src/__tests__/unit/layout.ts +196 -0
- package/src/__tests__/unit/nodeviews/cell.ts +167 -0
- package/src/__tests__/unit/pm-plugins/table-resizing/utils/resize-state.ts +33 -0
- package/src/__tests__/unit/sort-column.ts +512 -0
- package/src/__tests__/unit/transforms/delete-columns.ts +499 -0
- package/src/__tests__/unit/transforms/delete-rows.ts +557 -0
- package/src/__tests__/unit/transforms/merging.ts +374 -0
- package/src/__tests__/unit/ui/CornerControls.tsx +80 -0
- package/src/__tests__/unit/ui/FloatingContextualButton.tsx +95 -0
- package/src/__tests__/unit/ui/FloatingDeleteButton.tsx +175 -0
- package/src/__tests__/unit/ui/FloatingInsertButton.tsx +266 -0
- package/src/__tests__/unit/ui/RowControls.tsx +301 -0
- package/src/__tests__/unit/ui/TableFloatingControls.tsx +93 -0
- package/src/__tests__/unit/undo-redo.ts +202 -0
- package/src/__tests__/unit/utils/dom.ts +286 -0
- package/src/__tests__/unit/utils/nodes.ts +59 -0
- package/src/__tests__/unit/utils/row-controls.ts +176 -0
- package/src/__tests__/unit/utils/table.ts +93 -0
- package/src/__tests__/unit/utils.ts +652 -0
- package/src/plugins/table/commands-with-analytics.ts +3 -0
- package/src/plugins/table/event-handlers.ts +5 -6
- package/src/plugins/table/nodeviews/tableCell.tsx +5 -4
- package/src/plugins/table/pm-plugins/table-resizing/utils/column-state.ts +1 -1
- package/src/plugins/table/pm-plugins/table-resizing/utils/resize-logic.ts +6 -2
- package/src/plugins/table/utils/column-controls.ts +1 -1
- package/tmp/api-report-tmp.d.ts +91 -0
|
@@ -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
|
+
test('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,106 @@
|
|
|
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
|
+
}).init();
|
|
86
|
+
|
|
87
|
+
// we expect to have a contentDOM after instanciating the NodeView so that
|
|
88
|
+
// ProseMirror will render the node's children into the element
|
|
89
|
+
expect(tableView.contentDOM).toBeDefined();
|
|
90
|
+
|
|
91
|
+
// we shouldn't have called the mock yet, since it's behind the window.setTimeout
|
|
92
|
+
expect(handleRefInnerMock).not.toBeCalled();
|
|
93
|
+
|
|
94
|
+
// run the timers through
|
|
95
|
+
jest.runAllTimers();
|
|
96
|
+
|
|
97
|
+
// the timer should have expired now
|
|
98
|
+
expect(handleRefInnerMock).toBeCalled();
|
|
99
|
+
|
|
100
|
+
// ensure we still have a contentDOM
|
|
101
|
+
expect(tableView.contentDOM).toBeDefined();
|
|
102
|
+
|
|
103
|
+
// reset the mock
|
|
104
|
+
handleRefMock.mockClear();
|
|
105
|
+
});
|
|
106
|
+
});
|