@atlaskit/editor-plugin-table 0.2.6 → 1.0.1
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 +40 -0
- package/dist/cjs/plugins/table/commands/index.js +9 -1
- package/dist/cjs/plugins/table/commands/referentiality.js +23 -0
- package/dist/cjs/plugins/table/event-handlers.js +5 -1
- package/dist/cjs/plugins/table/nodeviews/table.js +10 -1
- package/dist/cjs/plugins/table/nodeviews/tableCell.js +5 -1
- package/dist/cjs/plugins/table/pm-plugins/decorations/plugin.js +1 -0
- package/dist/cjs/plugins/table/pm-plugins/decorations/utils/column-controls.js +1 -3
- package/dist/cjs/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +15 -12
- package/dist/cjs/plugins/table/toolbar.js +78 -35
- package/dist/cjs/plugins/table/ui/common-styles.js +6 -3
- package/dist/cjs/plugins/table/ui/messages.js +17 -2
- package/dist/cjs/plugins/table/ui/ui-styles.js +2 -7
- package/dist/cjs/plugins/table/utils/decoration.js +19 -12
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/plugins/table/commands/index.js +2 -1
- package/dist/es2019/plugins/table/commands/referentiality.js +10 -0
- package/dist/es2019/plugins/table/event-handlers.js +3 -1
- package/dist/es2019/plugins/table/nodeviews/table.js +13 -1
- package/dist/es2019/plugins/table/nodeviews/tableCell.js +5 -1
- package/dist/es2019/plugins/table/pm-plugins/decorations/plugin.js +1 -0
- package/dist/es2019/plugins/table/pm-plugins/decorations/utils/column-controls.js +1 -2
- package/dist/es2019/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +16 -11
- package/dist/es2019/plugins/table/toolbar.js +65 -29
- package/dist/es2019/plugins/table/ui/common-styles.js +15 -5
- package/dist/es2019/plugins/table/ui/messages.js +17 -2
- package/dist/es2019/plugins/table/ui/ui-styles.js +24 -16
- package/dist/es2019/plugins/table/utils/decoration.js +22 -13
- package/dist/es2019/version.json +1 -1
- package/dist/esm/plugins/table/commands/index.js +2 -1
- package/dist/esm/plugins/table/commands/referentiality.js +12 -0
- package/dist/esm/plugins/table/event-handlers.js +5 -1
- package/dist/esm/plugins/table/nodeviews/table.js +10 -1
- package/dist/esm/plugins/table/nodeviews/tableCell.js +5 -1
- package/dist/esm/plugins/table/pm-plugins/decorations/plugin.js +1 -0
- package/dist/esm/plugins/table/pm-plugins/decorations/utils/column-controls.js +1 -2
- package/dist/esm/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +15 -12
- package/dist/esm/plugins/table/toolbar.js +74 -29
- package/dist/esm/plugins/table/ui/common-styles.js +6 -3
- package/dist/esm/plugins/table/ui/messages.js +17 -2
- package/dist/esm/plugins/table/ui/ui-styles.js +2 -6
- package/dist/esm/plugins/table/utils/decoration.js +19 -12
- package/dist/esm/version.json +1 -1
- package/dist/types/plugins/table/commands/index.d.ts +1 -0
- package/dist/types/plugins/table/commands/referentiality.d.ts +2 -0
- package/dist/types/plugins/table/index.d.ts +2 -3
- package/dist/types/plugins/table/nodeviews/table.d.ts +4 -1
- package/dist/types/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.d.ts +0 -1
- package/dist/types/plugins/table/ui/common-styles.d.ts +4 -1
- package/dist/types/plugins/table/ui/messages.d.ts +15 -0
- package/package.json +6 -6
- package/report.api.md +6 -6
- package/src/__tests__/integration/__fixtures__/table-and-paragraph-adf.json +130 -0
- package/src/__tests__/integration/floating-toolbar.ts +54 -0
- package/src/__tests__/integration/meta-arrowup-cursor-in-first-row.ts +37 -0
- package/src/__tests__/unit/color-picker.ts +100 -0
- package/src/__tests__/unit/get-toolbar-config.ts +1 -4
- package/src/__tests__/unit/keymap.ts +1 -1
- package/src/__tests__/unit/nodeviews/cell.ts +52 -57
- package/src/__tests__/unit/pm-plugins/sticky-headers/tableRow.tsx +90 -8
- package/src/__tests__/unit/transforms/delete-columns.ts +1 -1
- package/src/__tests__/unit/transforms/delete-rows.ts +1 -1
- package/src/__tests__/unit/utils/collapse.ts +2 -2
- package/src/__tests__/visual-regression/__image_snapshots__/cell-options-menu-ts-table-cell-options-menu-delete-row-menu-item-should-remove-the-table-row-on-click-1-snap.png +2 -2
- package/src/plugins/table/commands/index.ts +1 -0
- package/src/plugins/table/commands/referentiality.ts +14 -0
- package/src/plugins/table/event-handlers.ts +7 -1
- package/src/plugins/table/index.tsx +6 -1
- package/src/plugins/table/nodeviews/table.tsx +16 -1
- package/src/plugins/table/nodeviews/tableCell.tsx +3 -1
- package/src/plugins/table/pm-plugins/decorations/plugin.ts +1 -0
- package/src/plugins/table/pm-plugins/decorations/utils/column-controls.ts +1 -1
- package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.ts +12 -10
- package/src/plugins/table/toolbar.tsx +84 -28
- package/src/plugins/table/ui/common-styles.ts +20 -4
- package/src/plugins/table/ui/messages.ts +18 -3
- package/src/plugins/table/ui/ui-styles.ts +23 -14
- package/src/plugins/table/utils/decoration.ts +36 -20
- package/dist/cjs/plugins/table/utils/referentiality.js +0 -29
- package/dist/es2019/plugins/table/utils/referentiality.js +0 -18
- package/dist/esm/plugins/table/utils/referentiality.js +0 -20
- package/dist/types/plugins/table/utils/referentiality.d.ts +0 -2
- package/src/plugins/table/utils/referentiality.ts +0 -24
|
@@ -54,9 +54,10 @@ describe('TableRowNodeView', () => {
|
|
|
54
54
|
return createEditor({
|
|
55
55
|
doc,
|
|
56
56
|
preset: new Preset<LightEditorPlugin>()
|
|
57
|
-
.add(
|
|
57
|
+
.add(tablePlugin)
|
|
58
58
|
.add([featureFlagsPlugin, featureFlags]),
|
|
59
59
|
pluginKey,
|
|
60
|
+
attachTo: document.body,
|
|
60
61
|
});
|
|
61
62
|
};
|
|
62
63
|
let editorView: EditorView;
|
|
@@ -81,7 +82,7 @@ describe('TableRowNodeView', () => {
|
|
|
81
82
|
const editorWithTableSticky = (doc: DocBuilder) =>
|
|
82
83
|
createEditor({
|
|
83
84
|
doc,
|
|
84
|
-
preset: new Preset<LightEditorPlugin>().add(
|
|
85
|
+
preset: new Preset<LightEditorPlugin>().add(tablePlugin),
|
|
85
86
|
pluginKey,
|
|
86
87
|
});
|
|
87
88
|
const editorData = editorWithTableSticky(
|
|
@@ -349,44 +350,42 @@ describe('TableRowNodeView', () => {
|
|
|
349
350
|
tableRowNodeView.dom = tableRowDom;
|
|
350
351
|
});
|
|
351
352
|
|
|
353
|
+
afterEach(() => {
|
|
354
|
+
jest.clearAllMocks();
|
|
355
|
+
});
|
|
356
|
+
|
|
352
357
|
function getTableElements(tableRowDom: HTMLTableRowElement) {
|
|
353
358
|
const tableWrapper = tableRowDom.closest(
|
|
354
359
|
`.${TableCssClassName.NODEVIEW_WRAPPER}`,
|
|
355
360
|
);
|
|
356
361
|
const tableElement = tableRowDom.closest('table');
|
|
357
362
|
const tableParent = tableElement?.parentElement;
|
|
358
|
-
|
|
359
363
|
const scrollContainer = tableWrapper?.parentElement;
|
|
360
364
|
return { tableWrapper, tableElement, tableParent, scrollContainer };
|
|
361
365
|
}
|
|
362
|
-
|
|
363
366
|
function mockScrollPositions(tableRowDom: HTMLTableRowElement) {
|
|
364
367
|
const { tableWrapper, tableParent, scrollContainer } =
|
|
365
368
|
getTableElements(tableRowDom);
|
|
366
369
|
(findOverflowScrollParent as unknown as jest.SpyInstance).mockReturnValue(
|
|
367
370
|
scrollContainer,
|
|
368
371
|
);
|
|
369
|
-
|
|
370
372
|
jest
|
|
371
373
|
.spyOn(scrollContainer as HTMLElement, 'getBoundingClientRect')
|
|
372
374
|
.mockImplementationOnce(() => ({
|
|
373
375
|
...baseBoundingRect,
|
|
374
376
|
top: -50,
|
|
375
377
|
}));
|
|
376
|
-
|
|
377
378
|
jest
|
|
378
379
|
.spyOn(tableParent as HTMLElement, 'getBoundingClientRect')
|
|
379
380
|
.mockImplementationOnce(() => ({
|
|
380
381
|
...baseBoundingRect,
|
|
381
382
|
}));
|
|
382
|
-
|
|
383
383
|
jest
|
|
384
384
|
.spyOn(tableWrapper as HTMLElement, 'getBoundingClientRect')
|
|
385
385
|
.mockImplementationOnce(() => ({
|
|
386
386
|
...baseBoundingRect,
|
|
387
387
|
top: -100,
|
|
388
388
|
}));
|
|
389
|
-
|
|
390
389
|
return scrollContainer;
|
|
391
390
|
}
|
|
392
391
|
|
|
@@ -580,4 +579,87 @@ describe('TableRowNodeView', () => {
|
|
|
580
579
|
expect(sentinelBottom.dataset.isObserved).toBeUndefined();
|
|
581
580
|
});
|
|
582
581
|
});
|
|
582
|
+
|
|
583
|
+
describe('makeRowHeaderNotSticky', () => {
|
|
584
|
+
let makeRowHeaderNotStickySpy: jest.SpyInstance;
|
|
585
|
+
let tableRef: HTMLElement;
|
|
586
|
+
beforeEach(() => {
|
|
587
|
+
const editorData = editor(
|
|
588
|
+
doc(table()(tr(thEmpty, thEmpty), tr(tdEmpty, tdEmpty))),
|
|
589
|
+
true, // toggle to enable optimization
|
|
590
|
+
);
|
|
591
|
+
editorView = editorData.editorView;
|
|
592
|
+
eventDispatcher = editorData.eventDispatcher;
|
|
593
|
+
tableRowNode = editorView.state.doc.firstChild!.firstChild!;
|
|
594
|
+
tableRowDom = editorView.dom.getElementsByTagName('tr')[0];
|
|
595
|
+
|
|
596
|
+
tableRowNodeView = new TableRowNodeView(
|
|
597
|
+
tableRowNode,
|
|
598
|
+
editorView,
|
|
599
|
+
jest.fn(),
|
|
600
|
+
eventDispatcher,
|
|
601
|
+
fakeGetEditorFeatureFlags,
|
|
602
|
+
);
|
|
603
|
+
tableRowNodeView.dom = tableRowDom;
|
|
604
|
+
|
|
605
|
+
// Initialize with sticky off
|
|
606
|
+
tableRowNodeView.isSticky = false;
|
|
607
|
+
tableRowNodeView.top = 0;
|
|
608
|
+
tableRowNodeView.padding = 0;
|
|
609
|
+
|
|
610
|
+
makeRowHeaderNotStickySpy = jest.spyOn(
|
|
611
|
+
tableRowNodeView as any,
|
|
612
|
+
'makeRowHeaderNotSticky',
|
|
613
|
+
);
|
|
614
|
+
tableRef = document.querySelector(
|
|
615
|
+
'.ProseMirror table',
|
|
616
|
+
) as HTMLTableElement;
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
afterEach(() => {
|
|
620
|
+
jest.clearAllMocks();
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it('should not be called if table is not selected', () => {
|
|
624
|
+
eventDispatcher.emit((pluginKey as any).key, {
|
|
625
|
+
isHeaderRowEnabled: false,
|
|
626
|
+
tableRef: null,
|
|
627
|
+
});
|
|
628
|
+
expect(makeRowHeaderNotStickySpy).not.toHaveBeenCalled();
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('should not be called if header row is enabled', () => {
|
|
632
|
+
eventDispatcher.emit((pluginKey as any).key, {
|
|
633
|
+
isHeaderRowEnabled: true,
|
|
634
|
+
tableRef,
|
|
635
|
+
});
|
|
636
|
+
expect(makeRowHeaderNotStickySpy).not.toHaveBeenCalled();
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it('should be called if header row is disabled and table is selected', () => {
|
|
640
|
+
eventDispatcher.emit((pluginKey as any).key, {
|
|
641
|
+
isHeaderRowEnabled: false,
|
|
642
|
+
tableRef,
|
|
643
|
+
});
|
|
644
|
+
expect(makeRowHeaderNotStickySpy).toHaveBeenCalled();
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('should cause isSticky state to be set to false when called', () => {
|
|
648
|
+
// Begin test with stickyheaders state on
|
|
649
|
+
tableRowNodeView.isSticky = true;
|
|
650
|
+
tableRowNodeView.top = 1;
|
|
651
|
+
tableRowNodeView.padding = 1;
|
|
652
|
+
|
|
653
|
+
tableRowNodeView.makeRowHeaderNotSticky(tableRef);
|
|
654
|
+
|
|
655
|
+
expect(updateStickyState).toHaveBeenCalledWith(
|
|
656
|
+
expect.objectContaining({
|
|
657
|
+
sticky: false,
|
|
658
|
+
}),
|
|
659
|
+
);
|
|
660
|
+
expect(tableRowNodeView.isSticky).toBe(false);
|
|
661
|
+
expect(tableRowNodeView.top).toBe(0);
|
|
662
|
+
expect(tableRowNodeView.padding).toBe(0);
|
|
663
|
+
});
|
|
664
|
+
});
|
|
583
665
|
});
|
|
@@ -41,7 +41,7 @@ describe('table plugin -> transforms -> delete columns', () => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
const createEditor = createProsemirrorEditorFactory();
|
|
44
|
-
const preset = new Preset<LightEditorPlugin>().add(
|
|
44
|
+
const preset = new Preset<LightEditorPlugin>().add(tablePlugin);
|
|
45
45
|
|
|
46
46
|
const editor = (doc: DocBuilder) =>
|
|
47
47
|
createEditor<TablePluginState, PluginKey>({
|
|
@@ -41,7 +41,7 @@ describe('table plugin -> transforms -> delete rows', () => {
|
|
|
41
41
|
uuid.setStatic(false);
|
|
42
42
|
});
|
|
43
43
|
const createEditor = createProsemirrorEditorFactory();
|
|
44
|
-
const preset = new Preset<LightEditorPlugin>().add(
|
|
44
|
+
const preset = new Preset<LightEditorPlugin>().add(tablePlugin);
|
|
45
45
|
|
|
46
46
|
const editor = (doc: DocBuilder) =>
|
|
47
47
|
createEditor<TablePluginState, PluginKey>({
|
|
@@ -23,9 +23,9 @@ describe('collapse', () => {
|
|
|
23
23
|
const createEditor = createProsemirrorEditorFactory();
|
|
24
24
|
|
|
25
25
|
const editor = (doc: DocBuilder, expandInPlugins?: boolean) => {
|
|
26
|
-
const preset = new Preset<LightEditorPlugin>().add(
|
|
26
|
+
const preset = new Preset<LightEditorPlugin>().add(tablePlugin);
|
|
27
27
|
|
|
28
|
-
const finalPreset = expandInPlugins ? preset.add(
|
|
28
|
+
const finalPreset = expandInPlugins ? preset.add(expandPlugin) : preset;
|
|
29
29
|
|
|
30
30
|
return createEditor({ doc, preset: finalPreset });
|
|
31
31
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
version https://git-lfs.github.com/spec/v1
|
|
2
|
-
oid sha256:
|
|
3
|
-
size
|
|
2
|
+
oid sha256:185a432916fe30487eec362617c510dd132f2a37a56bfceeca674da4c6512dc9
|
|
3
|
+
size 13986
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createCommand } from '../pm-plugins/plugin-factory';
|
|
2
|
+
import { Node as PMNode } from 'prosemirror-model';
|
|
3
|
+
import { removeConnectedNodes } from '@atlaskit/editor-common/utils';
|
|
4
|
+
|
|
5
|
+
export const removeDescendantNodes = (sourceNode: PMNode) =>
|
|
6
|
+
createCommand(
|
|
7
|
+
{
|
|
8
|
+
type: 'UPDATE_STATE',
|
|
9
|
+
data: { element: undefined },
|
|
10
|
+
},
|
|
11
|
+
(tr, state) => {
|
|
12
|
+
return sourceNode ? removeConnectedNodes(state, sourceNode) : tr;
|
|
13
|
+
},
|
|
14
|
+
);
|
|
@@ -78,6 +78,11 @@ const isFocusingModal = (event: Event) =>
|
|
|
78
78
|
event.relatedTarget instanceof HTMLElement &&
|
|
79
79
|
event.relatedTarget.closest('[role="dialog"]');
|
|
80
80
|
|
|
81
|
+
const isFocusingFloatingToolbar = (event: Event) =>
|
|
82
|
+
event instanceof FocusEvent &&
|
|
83
|
+
event.relatedTarget instanceof HTMLElement &&
|
|
84
|
+
event.relatedTarget.closest('[role="toolbar"]');
|
|
85
|
+
|
|
81
86
|
export const handleBlur = (view: EditorView, event: Event): boolean => {
|
|
82
87
|
const { state, dispatch } = view;
|
|
83
88
|
// IE version check for ED-4665
|
|
@@ -85,7 +90,8 @@ export const handleBlur = (view: EditorView, event: Event): boolean => {
|
|
|
85
90
|
if (
|
|
86
91
|
browser.ie_version !== 11 &&
|
|
87
92
|
!isFocusingCalendar(event) &&
|
|
88
|
-
!isFocusingModal(event)
|
|
93
|
+
!isFocusingModal(event) &&
|
|
94
|
+
!isFocusingFloatingToolbar(event)
|
|
89
95
|
) {
|
|
90
96
|
setEditorFocus(false)(state, dispatch);
|
|
91
97
|
}
|
|
@@ -59,6 +59,7 @@ import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
|
|
|
59
59
|
import type {
|
|
60
60
|
GetEditorContainerWidth,
|
|
61
61
|
GetEditorFeatureFlags,
|
|
62
|
+
NextEditorPlugin,
|
|
62
63
|
} from '@atlaskit/editor-common/types';
|
|
63
64
|
import { EditorState, Transaction } from 'prosemirror-state';
|
|
64
65
|
|
|
@@ -76,7 +77,11 @@ interface TablePluginOptions {
|
|
|
76
77
|
|
|
77
78
|
const defaultGetEditorFeatureFlags = () => ({});
|
|
78
79
|
|
|
79
|
-
const tablesPlugin
|
|
80
|
+
const tablesPlugin: NextEditorPlugin<
|
|
81
|
+
'table',
|
|
82
|
+
never,
|
|
83
|
+
TablePluginOptions | undefined
|
|
84
|
+
> = (options?: TablePluginOptions) => {
|
|
80
85
|
const editorViewRef: Record<'current', EditorView | null> = { current: null };
|
|
81
86
|
const defaultGetEditorContainerWidth: GetEditorContainerWidth = () => {
|
|
82
87
|
if (!editorViewRef.current) {
|
|
@@ -209,7 +209,22 @@ export default class TableView extends ReactNodeView<Props> {
|
|
|
209
209
|
return super.viewShouldUpdate(nextNode);
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
ignoreMutation(
|
|
212
|
+
ignoreMutation(
|
|
213
|
+
mutation: MutationRecord | { type: 'selection'; target: Element },
|
|
214
|
+
) {
|
|
215
|
+
const {
|
|
216
|
+
type,
|
|
217
|
+
target: { nodeName, firstChild },
|
|
218
|
+
} = mutation;
|
|
219
|
+
|
|
220
|
+
if (
|
|
221
|
+
type === 'selection' &&
|
|
222
|
+
nodeName?.toUpperCase() === 'DIV' &&
|
|
223
|
+
firstChild?.nodeName.toUpperCase() === 'TABLE'
|
|
224
|
+
) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
|
|
213
228
|
return true;
|
|
214
229
|
}
|
|
215
230
|
|
|
@@ -83,5 +83,5 @@ export const buildColumnControlsDecorations: DecorationTransformer = ({
|
|
|
83
83
|
removeControlsHoverDecoration,
|
|
84
84
|
maybeUpdateColumnSelectedDecoration,
|
|
85
85
|
maybeUpdateColumnControlsDecoration,
|
|
86
|
-
])({ decorationSet
|
|
86
|
+
])({ decorationSet, tr });
|
|
87
87
|
};
|
|
@@ -97,7 +97,6 @@ export class TableRowNodeView implements NodeView {
|
|
|
97
97
|
focused = false;
|
|
98
98
|
topPosEditorElement = 0;
|
|
99
99
|
isSticky: boolean;
|
|
100
|
-
isTableInit: boolean;
|
|
101
100
|
lastTimePainted: number;
|
|
102
101
|
|
|
103
102
|
private intersectionObserver?: IntersectionObserver;
|
|
@@ -134,7 +133,6 @@ export class TableRowNodeView implements NodeView {
|
|
|
134
133
|
this.lastTimePainted = 0;
|
|
135
134
|
this.isHeaderRow = supportedHeaderRow(node);
|
|
136
135
|
this.isSticky = false;
|
|
137
|
-
this.isTableInit = false;
|
|
138
136
|
|
|
139
137
|
if (this.isHeaderRow) {
|
|
140
138
|
this.dom.setAttribute('data-header-row', 'true');
|
|
@@ -486,14 +484,6 @@ export class TableRowNodeView implements NodeView {
|
|
|
486
484
|
return;
|
|
487
485
|
}
|
|
488
486
|
|
|
489
|
-
// make it non-sticky initially to avoid making it look separated
|
|
490
|
-
if (!this.isTableInit) {
|
|
491
|
-
if (this.tree) {
|
|
492
|
-
this.makeRowHeaderNotSticky(this.tree.table);
|
|
493
|
-
this.isTableInit = true;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
487
|
// when header rows are toggled off - mark sentinels as unobserved
|
|
498
488
|
if (!state.isHeaderRowEnabled) {
|
|
499
489
|
[this.sentinels.top, this.sentinels.bottom].forEach((el) => {
|
|
@@ -504,6 +494,11 @@ export class TableRowNodeView implements NodeView {
|
|
|
504
494
|
}
|
|
505
495
|
|
|
506
496
|
const isCurrentTableSelected = tableRef === tree.table;
|
|
497
|
+
|
|
498
|
+
// If current table selected and header row is toggled off, turn off sticky header
|
|
499
|
+
if (isCurrentTableSelected && !state.isHeaderRowEnabled && this.tree) {
|
|
500
|
+
this.makeRowHeaderNotSticky(this.tree.table);
|
|
501
|
+
}
|
|
507
502
|
if (isCurrentTableSelected !== this.focused) {
|
|
508
503
|
focusChanged = true;
|
|
509
504
|
}
|
|
@@ -598,6 +593,13 @@ export class TableRowNodeView implements NodeView {
|
|
|
598
593
|
|
|
599
594
|
const { table } = tree;
|
|
600
595
|
|
|
596
|
+
// ED-16035 Make sure sticky header is only applied to first row
|
|
597
|
+
const tbody = this.dom.parentElement;
|
|
598
|
+
const isFirstHeader = tbody?.firstChild?.isEqualNode(this.dom);
|
|
599
|
+
if (!isFirstHeader) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
|
|
601
603
|
const currentTableTop = this.getCurrentTableTop(tree);
|
|
602
604
|
const domTop =
|
|
603
605
|
currentTableTop > 0
|
|
@@ -7,6 +7,7 @@ import commonMessages from '@atlaskit/editor-common/messages';
|
|
|
7
7
|
import type {
|
|
8
8
|
Command,
|
|
9
9
|
CommandDispatch,
|
|
10
|
+
ConfirmDialogOptions,
|
|
10
11
|
DropdownOptionT,
|
|
11
12
|
FloatingToolbarDropdown,
|
|
12
13
|
FloatingToolbarHandler,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
hoverTable,
|
|
22
23
|
hoverColumns,
|
|
23
24
|
hoverRows,
|
|
25
|
+
removeDescendantNodes,
|
|
24
26
|
} from './commands';
|
|
25
27
|
import {
|
|
26
28
|
deleteTableWithAnalytics,
|
|
@@ -54,7 +56,12 @@ import {
|
|
|
54
56
|
getSelectedColumnIndexes,
|
|
55
57
|
getSelectedRowIndexes,
|
|
56
58
|
} from './utils';
|
|
57
|
-
import {
|
|
59
|
+
import {
|
|
60
|
+
isReferencedSource,
|
|
61
|
+
getChildrenInfo,
|
|
62
|
+
getNodeName,
|
|
63
|
+
} from '@atlaskit/editor-common/utils';
|
|
64
|
+
|
|
58
65
|
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
59
66
|
import {
|
|
60
67
|
findCellRectClosestToPos,
|
|
@@ -72,6 +79,7 @@ import type { GetEditorContainerWidth } from '@atlaskit/editor-common/types';
|
|
|
72
79
|
import { Rect } from '@atlaskit/editor-tables/table-map';
|
|
73
80
|
import { findParentDomRefOfType } from 'prosemirror-utils';
|
|
74
81
|
import { EditorView } from 'prosemirror-view';
|
|
82
|
+
import { Node as PMNode } from 'prosemirror-model';
|
|
75
83
|
import { closestElement } from '@atlaskit/editor-common/utils';
|
|
76
84
|
import {
|
|
77
85
|
addColumnAfter,
|
|
@@ -157,6 +165,7 @@ export const getToolbarMenuConfig = (
|
|
|
157
165
|
return {
|
|
158
166
|
id: 'editor.table.tableOptions',
|
|
159
167
|
type: 'dropdown',
|
|
168
|
+
testId: 'table_options',
|
|
160
169
|
title: formatMessage(messages.tableOptions),
|
|
161
170
|
hidden: options.every((option) => option.hidden),
|
|
162
171
|
options,
|
|
@@ -239,17 +248,9 @@ export const getToolbarCellOptionsConfig = (
|
|
|
239
248
|
}
|
|
240
249
|
return true;
|
|
241
250
|
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
hoverColumns(getSelectedColumnIndexes(selectionRect), true)(
|
|
246
|
-
state,
|
|
247
|
-
dispatch,
|
|
248
|
-
);
|
|
249
|
-
return true;
|
|
250
|
-
}
|
|
251
|
-
return false;
|
|
252
|
-
},
|
|
251
|
+
onFocus: highlightColumnsHandler,
|
|
252
|
+
onBlur: clearHoverSelection(),
|
|
253
|
+
onMouseOver: highlightColumnsHandler,
|
|
253
254
|
onMouseLeave: clearHoverSelection(),
|
|
254
255
|
selected: false,
|
|
255
256
|
disabled: false,
|
|
@@ -270,17 +271,9 @@ export const getToolbarCellOptionsConfig = (
|
|
|
270
271
|
}
|
|
271
272
|
return true;
|
|
272
273
|
},
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
hoverRows(getSelectedRowIndexes(selectionRect), true)(
|
|
277
|
-
state,
|
|
278
|
-
dispatch,
|
|
279
|
-
);
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
return false;
|
|
283
|
-
},
|
|
274
|
+
onFocus: highlightRowsHandler,
|
|
275
|
+
onBlur: clearHoverSelection(),
|
|
276
|
+
onMouseOver: highlightRowsHandler,
|
|
284
277
|
onMouseLeave: clearHoverSelection(),
|
|
285
278
|
selected: false,
|
|
286
279
|
disabled: false,
|
|
@@ -396,6 +389,7 @@ export const getToolbarCellOptionsConfig = (
|
|
|
396
389
|
|
|
397
390
|
return {
|
|
398
391
|
id: 'editor.table.cellOptions',
|
|
392
|
+
testId: 'cell_options',
|
|
399
393
|
type: 'dropdown',
|
|
400
394
|
title: formatMessage(tableMessages.cellOptions),
|
|
401
395
|
options,
|
|
@@ -456,17 +450,28 @@ export const getToolbarConfig =
|
|
|
456
450
|
|
|
457
451
|
// Check if we need to show confirm dialog for delete button
|
|
458
452
|
let confirmDialog;
|
|
459
|
-
const localId: string | undefined = tableObject.node.attrs.localId;
|
|
460
453
|
|
|
461
|
-
if (
|
|
462
|
-
confirmDialog = {
|
|
454
|
+
if (isReferencedSource(state, tableObject.node)) {
|
|
455
|
+
confirmDialog = (): ConfirmDialogOptions => ({
|
|
456
|
+
title: intl.formatMessage(tableMessages.deleteElementTitle),
|
|
463
457
|
okButtonLabel: intl.formatMessage(
|
|
464
458
|
tableMessages.confirmDeleteLinkedModalOKButton,
|
|
465
459
|
),
|
|
466
460
|
message: intl.formatMessage(
|
|
467
461
|
tableMessages.confirmDeleteLinkedModalMessage,
|
|
462
|
+
{ nodeName: getNodeName(state, tableObject.node) },
|
|
463
|
+
),
|
|
464
|
+
messagePrefix: intl.formatMessage(
|
|
465
|
+
tableMessages.confirmDeleteLinkedModalMessagePrefix,
|
|
468
466
|
),
|
|
469
|
-
|
|
467
|
+
isReferentialityDialog: true,
|
|
468
|
+
getChildrenInfo: () => getChildrenInfo(state, tableObject.node),
|
|
469
|
+
checkboxLabel: intl.formatMessage(
|
|
470
|
+
tableMessages.confirmModalCheckboxLabel,
|
|
471
|
+
),
|
|
472
|
+
onConfirm: (isChecked = false) =>
|
|
473
|
+
clickWithCheckboxHandler(isChecked, tableObject.node),
|
|
474
|
+
});
|
|
470
475
|
}
|
|
471
476
|
|
|
472
477
|
const getDomRef = (editorView: EditorView) => {
|
|
@@ -516,6 +521,8 @@ export const getToolbarConfig =
|
|
|
516
521
|
nodeType,
|
|
517
522
|
onMouseEnter: hoverTable(false, true),
|
|
518
523
|
onMouseLeave: clearHoverSelection(),
|
|
524
|
+
onFocus: hoverTable(false, true),
|
|
525
|
+
onBlur: clearHoverSelection(),
|
|
519
526
|
},
|
|
520
527
|
{ type: 'separator' },
|
|
521
528
|
],
|
|
@@ -528,8 +535,11 @@ export const getToolbarConfig =
|
|
|
528
535
|
onClick: deleteTableWithAnalytics(editorAnalyticsAPI),
|
|
529
536
|
disabled: !!resizeState && !!resizeState.dragging,
|
|
530
537
|
onMouseEnter: hoverTable(true),
|
|
538
|
+
onFocus: hoverTable(true),
|
|
539
|
+
onBlur: clearHoverSelection(),
|
|
531
540
|
onMouseLeave: clearHoverSelection(),
|
|
532
541
|
title: intl.formatMessage(commonMessages.remove),
|
|
542
|
+
focusEditoronEnter: true,
|
|
533
543
|
confirmDialog,
|
|
534
544
|
},
|
|
535
545
|
],
|
|
@@ -604,7 +614,7 @@ const getColorPicker = (
|
|
|
604
614
|
|
|
605
615
|
return [
|
|
606
616
|
{
|
|
607
|
-
id: 'editor.
|
|
617
|
+
id: 'editor.table.colorPicker',
|
|
608
618
|
title: formatMessage(ContextualMenuMessages.cellBackground),
|
|
609
619
|
type: 'select',
|
|
610
620
|
selectType: 'color',
|
|
@@ -620,3 +630,49 @@ const getColorPicker = (
|
|
|
620
630
|
separator(menu.hidden),
|
|
621
631
|
];
|
|
622
632
|
};
|
|
633
|
+
|
|
634
|
+
const clickWithCheckboxHandler =
|
|
635
|
+
(
|
|
636
|
+
isChecked: boolean,
|
|
637
|
+
node?: PMNode,
|
|
638
|
+
editorAnalyticsAPI?: EditorAnalyticsAPI | undefined | null,
|
|
639
|
+
): Command =>
|
|
640
|
+
(state, dispatch) => {
|
|
641
|
+
if (!node) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (!isChecked) {
|
|
646
|
+
return deleteTableWithAnalytics(editorAnalyticsAPI)(state, dispatch);
|
|
647
|
+
} else {
|
|
648
|
+
removeDescendantNodes(node)(state, dispatch);
|
|
649
|
+
}
|
|
650
|
+
return true;
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
const highlightRowsHandler = (
|
|
654
|
+
state: EditorState,
|
|
655
|
+
dispatch?: CommandDispatch,
|
|
656
|
+
) => {
|
|
657
|
+
const selectionRect = getClosestSelectionRect(state);
|
|
658
|
+
if (selectionRect) {
|
|
659
|
+
hoverRows(getSelectedRowIndexes(selectionRect), true)(state, dispatch);
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
return false;
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
const highlightColumnsHandler = (
|
|
666
|
+
state: EditorState,
|
|
667
|
+
dispatch?: CommandDispatch,
|
|
668
|
+
) => {
|
|
669
|
+
const selectionRect = getClosestSelectionRect(state);
|
|
670
|
+
if (selectionRect) {
|
|
671
|
+
hoverColumns(getSelectedColumnIndexes(selectionRect), true)(
|
|
672
|
+
state,
|
|
673
|
+
dispatch,
|
|
674
|
+
);
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
return false;
|
|
678
|
+
};
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
tableMarginTop,
|
|
5
5
|
tableSharedStyle,
|
|
6
6
|
} from '@atlaskit/editor-common/styles';
|
|
7
|
+
import type { FeatureFlags } from '@atlaskit/editor-common/types';
|
|
7
8
|
import { fontSize } from '@atlaskit/theme/constants';
|
|
8
9
|
import { N40A, B300, N300, N20A, N0, R500 } from '@atlaskit/theme/colors';
|
|
9
10
|
import {
|
|
@@ -112,8 +113,18 @@ const sentinelStyles = `.${ClassName.TABLE_CONTAINER} {
|
|
|
112
113
|
}
|
|
113
114
|
}`;
|
|
114
115
|
|
|
116
|
+
// previous styles to add spacing to numbered lists with
|
|
117
|
+
// large item markers (e.g. 101, 102, ...) when nested inside tables
|
|
118
|
+
const listLargeNumericMarkersOldStyles = `
|
|
119
|
+
.ProseMirror .pm-table-cell-content-wrap ol[data-child-count='100+'] {
|
|
120
|
+
padding-left: revert;
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
|
|
115
124
|
// TODO: https://product-fabric.atlassian.net/browse/DSP-4139
|
|
116
|
-
export const tableStyles = (
|
|
125
|
+
export const tableStyles = (
|
|
126
|
+
props: ThemeProps & { featureFlags?: FeatureFlags },
|
|
127
|
+
) => css`
|
|
117
128
|
.${ClassName.LAYOUT_BUTTON} button {
|
|
118
129
|
background: ${token('color.background.neutral', N20A)};
|
|
119
130
|
color: ${token('color.icon', N300)};
|
|
@@ -713,9 +724,14 @@ export const tableStyles = (props: ThemeProps) => css`
|
|
|
713
724
|
cursor: col-resize;
|
|
714
725
|
}
|
|
715
726
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
727
|
+
/*
|
|
728
|
+
ED-15882: When custom start numbers is enabled for lists, we have
|
|
729
|
+
styles that handle this generally (in editor-common) so we can
|
|
730
|
+
throw away the older table-specific styles here.
|
|
731
|
+
*/
|
|
732
|
+
${props?.featureFlags?.restartNumberedLists
|
|
733
|
+
? ``
|
|
734
|
+
: listLargeNumericMarkersOldStyles}
|
|
719
735
|
`;
|
|
720
736
|
|
|
721
737
|
export const tableFullPageEditorStyles = css`
|
|
@@ -29,15 +29,30 @@ export default defineMessages({
|
|
|
29
29
|
|
|
30
30
|
confirmDeleteLinkedModalOKButton: {
|
|
31
31
|
id: 'fabric.editor.tables.confirmDeleteLinkedModalOKButton',
|
|
32
|
-
defaultMessage: '
|
|
32
|
+
defaultMessage: 'Delete',
|
|
33
33
|
description:
|
|
34
34
|
'Action button label for confirm modal when deleting a table linked to an extension.',
|
|
35
35
|
},
|
|
36
36
|
confirmDeleteLinkedModalMessage: {
|
|
37
37
|
id: 'fabric.editor.tables.confirmDeleteLinkedModalMessage',
|
|
38
|
-
defaultMessage:
|
|
39
|
-
'Removing this table will break all the charts connected to it.',
|
|
38
|
+
defaultMessage: 'Deleting {nodeName} will break anything connected to it.',
|
|
40
39
|
description:
|
|
41
40
|
'Message for confirm modal when deleting a table linked to an extension.',
|
|
42
41
|
},
|
|
42
|
+
confirmDeleteLinkedModalMessagePrefix: {
|
|
43
|
+
id: 'fabric.editor.extension.confirmDeleteLinkedModalMessagePrefix',
|
|
44
|
+
defaultMessage: 'Deleting',
|
|
45
|
+
description: 'prefix for confirmation dialog text',
|
|
46
|
+
},
|
|
47
|
+
confirmModalCheckboxLabel: {
|
|
48
|
+
id: 'fabric.editor.floatingToolbar.confirmModalCheckboxLabel',
|
|
49
|
+
defaultMessage: 'Also delete connected elements',
|
|
50
|
+
description: 'checkbox label text',
|
|
51
|
+
},
|
|
52
|
+
deleteElementTitle: {
|
|
53
|
+
id: 'fabric.editor.extension.deleteElementTitle',
|
|
54
|
+
defaultMessage: 'Delete element',
|
|
55
|
+
description:
|
|
56
|
+
'Title text for confirm modal when deleting an extension linked to a data consumer.',
|
|
57
|
+
},
|
|
43
58
|
});
|