@atlaskit/editor-plugin-layout 10.5.0 → 10.6.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 +17 -0
- package/dist/cjs/layoutPlugin.js +4 -1
- package/dist/cjs/pm-plugins/actions.js +87 -64
- package/dist/cjs/pm-plugins/main.js +4 -2
- package/dist/cjs/pm-plugins/utils/layout-column-selection.js +128 -0
- package/dist/cjs/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +7 -4
- package/dist/cjs/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +5 -6
- package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +9 -7
- package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +15 -6
- package/dist/cjs/ui/LayoutColumnMenu/index.js +17 -7
- package/dist/cjs/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +14 -0
- package/dist/es2019/layoutPlugin.js +4 -1
- package/dist/es2019/pm-plugins/actions.js +73 -58
- package/dist/es2019/pm-plugins/main.js +4 -2
- package/dist/es2019/pm-plugins/utils/layout-column-selection.js +118 -0
- package/dist/es2019/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +7 -4
- package/dist/es2019/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +5 -6
- package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +9 -6
- package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +15 -5
- package/dist/es2019/ui/LayoutColumnMenu/index.js +16 -6
- package/dist/es2019/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +6 -0
- package/dist/esm/layoutPlugin.js +5 -2
- package/dist/esm/pm-plugins/actions.js +87 -64
- package/dist/esm/pm-plugins/main.js +4 -2
- package/dist/esm/pm-plugins/utils/layout-column-selection.js +122 -0
- package/dist/esm/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +7 -4
- package/dist/esm/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +5 -6
- package/dist/esm/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +10 -8
- package/dist/esm/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +15 -6
- package/dist/esm/ui/LayoutColumnMenu/index.js +17 -7
- package/dist/esm/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +8 -0
- package/dist/types/layoutPluginType.d.ts +1 -1
- package/dist/types/pm-plugins/actions.d.ts +3 -2
- package/dist/types/pm-plugins/types.d.ts +1 -0
- package/dist/types/pm-plugins/utils/layout-column-selection.d.ts +18 -0
- package/dist/types/ui/LayoutColumnMenu/useSelectedLayoutColumns.d.ts +4 -0
- package/dist/types-ts4.5/layoutPluginType.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +3 -2
- package/dist/types-ts4.5/pm-plugins/types.d.ts +1 -0
- package/dist/types-ts4.5/pm-plugins/utils/layout-column-selection.d.ts +18 -0
- package/dist/types-ts4.5/ui/LayoutColumnMenu/useSelectedLayoutColumns.d.ts +4 -0
- package/package.json +6 -6
- package/dist/cjs/ui/LayoutColumnMenu/layoutColumnSelection.js +0 -21
- package/dist/cjs/ui/LayoutColumnMenu/useCurrentLayoutColumn.js +0 -20
- package/dist/es2019/ui/LayoutColumnMenu/layoutColumnSelection.js +0 -9
- package/dist/es2019/ui/LayoutColumnMenu/useCurrentLayoutColumn.js +0 -10
- package/dist/esm/ui/LayoutColumnMenu/layoutColumnSelection.js +0 -15
- package/dist/esm/ui/LayoutColumnMenu/useCurrentLayoutColumn.js +0 -14
- package/dist/types/ui/LayoutColumnMenu/layoutColumnSelection.d.ts +0 -7
- package/dist/types/ui/LayoutColumnMenu/useCurrentLayoutColumn.d.ts +0 -5
- package/dist/types-ts4.5/ui/LayoutColumnMenu/layoutColumnSelection.d.ts +0 -7
- package/dist/types-ts4.5/ui/LayoutColumnMenu/useCurrentLayoutColumn.d.ts +0 -5
|
@@ -357,7 +357,10 @@ export const layoutPlugin = ({
|
|
|
357
357
|
var _api$analytics5;
|
|
358
358
|
return insertLayoutColumn(side, api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions);
|
|
359
359
|
},
|
|
360
|
-
setLayoutColumnValign
|
|
360
|
+
setLayoutColumnValign: valign => {
|
|
361
|
+
var _api$analytics6;
|
|
362
|
+
return setLayoutColumnValign(valign, api === null || api === void 0 ? void 0 : (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 ? void 0 : _api$analytics6.actions);
|
|
363
|
+
},
|
|
361
364
|
toggleLayoutColumnMenu
|
|
362
365
|
}
|
|
363
366
|
};
|
|
@@ -9,6 +9,7 @@ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equ
|
|
|
9
9
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
10
10
|
import { EVEN_DISTRIBUTED_COL_WIDTHS, MAX_LAYOUT_COLUMNS, MAX_STANDARD_LAYOUT_COLUMNS, MIN_LAYOUT_COLUMN_WIDTH_PERCENT } from './consts';
|
|
11
11
|
import { pluginKey } from './plugin-key';
|
|
12
|
+
import { getSelectedLayoutColumns } from './utils/layout-column-selection';
|
|
12
13
|
import { redistributeAfterDeletion, redistributeProportionally } from './utils/redistribute-proportionally';
|
|
13
14
|
export const ONE_COL_LAYOUTS = ['single'];
|
|
14
15
|
export const TWO_COL_LAYOUTS = ['two_equal', 'two_left_sidebar', 'two_right_sidebar'];
|
|
@@ -533,50 +534,26 @@ const formatLayoutName = layout => {
|
|
|
533
534
|
export function getEffectiveMaxLayoutColumns() {
|
|
534
535
|
return editorExperiment('advanced_layouts', true) ? MAX_LAYOUT_COLUMNS : MAX_STANDARD_LAYOUT_COLUMNS;
|
|
535
536
|
}
|
|
536
|
-
const getSelectedLayoutColumnInSection = ({
|
|
537
|
-
doc,
|
|
538
|
-
selection
|
|
539
|
-
}) => {
|
|
540
|
-
const {
|
|
541
|
-
layoutColumn,
|
|
542
|
-
layoutSection
|
|
543
|
-
} = doc.type.schema.nodes;
|
|
544
|
-
if (!(selection instanceof NodeSelection) || selection.node.type !== layoutColumn) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
const {
|
|
548
|
-
$from
|
|
549
|
-
} = selection;
|
|
550
|
-
if ($from.parent.type !== layoutSection) {
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
const selectedColumnIndex = $from.index($from.depth);
|
|
554
|
-
const selectedColumnNode = selection.node;
|
|
555
|
-
const selectedColumnPos = selection.from;
|
|
556
|
-
const layoutSectionPos = $from.before($from.depth);
|
|
557
|
-
return {
|
|
558
|
-
layoutSectionNode: $from.parent,
|
|
559
|
-
layoutSectionPos,
|
|
560
|
-
selectedColumnIndex,
|
|
561
|
-
selectedColumnNode,
|
|
562
|
-
selectedColumnPos
|
|
563
|
-
};
|
|
564
|
-
};
|
|
565
537
|
const insertLayoutColumnAt = (side, editorAnalyticsAPI) => ({
|
|
566
538
|
tr
|
|
567
539
|
}) => {
|
|
568
540
|
if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
|
|
569
541
|
return null;
|
|
570
542
|
}
|
|
571
|
-
const
|
|
572
|
-
if (!
|
|
543
|
+
const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
|
|
544
|
+
if (!selectedLayoutColumns) {
|
|
573
545
|
return null;
|
|
574
546
|
}
|
|
575
547
|
const {
|
|
576
548
|
layoutSectionNode,
|
|
577
549
|
layoutSectionPos,
|
|
578
|
-
|
|
579
|
-
|
|
550
|
+
selectedColumnIndices,
|
|
551
|
+
selectedColumns
|
|
552
|
+
} = selectedLayoutColumns;
|
|
553
|
+
const startIndex = selectedColumnIndices[0];
|
|
554
|
+
const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
|
|
555
|
+
const selectedColumnIndex = side === 'left' ? startIndex : endIndex;
|
|
556
|
+
const selectedColumnCount = selectedColumns.length;
|
|
580
557
|
if (layoutSectionNode.childCount >= getEffectiveMaxLayoutColumns()) {
|
|
581
558
|
return null;
|
|
582
559
|
}
|
|
@@ -613,9 +590,11 @@ const insertLayoutColumnAt = (side, editorAnalyticsAPI) => ({
|
|
|
613
590
|
actionSubjectId: ACTION_SUBJECT_ID.LAYOUT_COLUMN,
|
|
614
591
|
attributes: {
|
|
615
592
|
columnCount: redistributedWidths.length,
|
|
593
|
+
endIndex,
|
|
616
594
|
inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
|
|
617
|
-
|
|
618
|
-
side
|
|
595
|
+
selectedCount: selectedColumnCount,
|
|
596
|
+
side,
|
|
597
|
+
startIndex
|
|
619
598
|
},
|
|
620
599
|
eventType: EVENT_TYPE.TRACK
|
|
621
600
|
})(tr);
|
|
@@ -623,38 +602,64 @@ const insertLayoutColumnAt = (side, editorAnalyticsAPI) => ({
|
|
|
623
602
|
return tr;
|
|
624
603
|
};
|
|
625
604
|
export const insertLayoutColumn = (side, editorAnalyticsAPI) => insertLayoutColumnAt(side, editorAnalyticsAPI);
|
|
626
|
-
export const setLayoutColumnValign = valign => ({
|
|
605
|
+
export const setLayoutColumnValign = (valign, editorAnalyticsAPI) => ({
|
|
627
606
|
tr
|
|
628
607
|
}) => {
|
|
629
608
|
if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
|
|
630
609
|
return null;
|
|
631
610
|
}
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
} = tr.doc.type.schema.nodes;
|
|
635
|
-
const selectedColumn = tr.selection instanceof NodeSelection && tr.selection.node.type === layoutColumn ? {
|
|
636
|
-
node: tr.selection.node,
|
|
637
|
-
pos: tr.selection.from
|
|
638
|
-
} : undefined;
|
|
639
|
-
if (!selectedColumn) {
|
|
611
|
+
const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
|
|
612
|
+
if (!selectedLayoutColumns) {
|
|
640
613
|
return null;
|
|
641
614
|
}
|
|
642
|
-
|
|
615
|
+
const {
|
|
616
|
+
selectedColumnIndices,
|
|
617
|
+
selectedColumns
|
|
618
|
+
} = selectedLayoutColumns;
|
|
619
|
+
const columnsToUpdate = selectedColumns.filter(({
|
|
620
|
+
node
|
|
621
|
+
}) => node.attrs.valign !== valign);
|
|
622
|
+
if (columnsToUpdate.length === 0) {
|
|
643
623
|
return null;
|
|
644
624
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
625
|
+
const startIndex = selectedColumnIndices[0];
|
|
626
|
+
const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
|
|
627
|
+
const selectedColumnCount = selectedColumns.length;
|
|
628
|
+
const updatedColumnCount = columnsToUpdate.length;
|
|
629
|
+
columnsToUpdate.forEach(({
|
|
630
|
+
node,
|
|
631
|
+
pos
|
|
632
|
+
}) => {
|
|
633
|
+
tr.setNodeMarkup(pos, node.type, {
|
|
634
|
+
...node.attrs,
|
|
635
|
+
valign
|
|
636
|
+
});
|
|
648
637
|
});
|
|
638
|
+
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
|
|
639
|
+
action: ACTION.UPDATED,
|
|
640
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
641
|
+
actionSubjectId: ACTION_SUBJECT_ID.LAYOUT_COLUMN,
|
|
642
|
+
attributes: {
|
|
643
|
+
endIndex,
|
|
644
|
+
inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
|
|
645
|
+
selectedCount: selectedColumnCount,
|
|
646
|
+
startIndex,
|
|
647
|
+
updatedCount: updatedColumnCount,
|
|
648
|
+
valign
|
|
649
|
+
},
|
|
650
|
+
eventType: EVENT_TYPE.TRACK
|
|
651
|
+
})(tr);
|
|
649
652
|
tr.setMeta('scrollIntoView', false);
|
|
650
653
|
return tr;
|
|
651
654
|
};
|
|
652
655
|
export const toggleLayoutColumnMenu = ({
|
|
656
|
+
anchorPos,
|
|
653
657
|
isOpen
|
|
654
658
|
}) => ({
|
|
655
659
|
tr
|
|
656
660
|
}) => {
|
|
657
661
|
tr.setMeta('toggleLayoutColumnMenu', {
|
|
662
|
+
anchorPos,
|
|
658
663
|
isOpen
|
|
659
664
|
});
|
|
660
665
|
tr.setMeta('scrollIntoView', false);
|
|
@@ -666,15 +671,20 @@ export const deleteLayoutColumn = editorAnalyticsAPI => ({
|
|
|
666
671
|
if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
|
|
667
672
|
return null;
|
|
668
673
|
}
|
|
669
|
-
const
|
|
670
|
-
if (!
|
|
674
|
+
const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
|
|
675
|
+
if (!selectedLayoutColumns) {
|
|
671
676
|
return null;
|
|
672
677
|
}
|
|
673
678
|
const {
|
|
674
679
|
layoutSectionNode,
|
|
675
680
|
layoutSectionPos,
|
|
676
|
-
|
|
677
|
-
|
|
681
|
+
selectedColumnIndices,
|
|
682
|
+
selectedColumns
|
|
683
|
+
} = selectedLayoutColumns;
|
|
684
|
+
const startIndex = selectedColumnIndices[0];
|
|
685
|
+
const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
|
|
686
|
+
const selectedColumnCount = selectedColumns.length;
|
|
687
|
+
const selectedColumnIndexSet = new Set(selectedColumnIndices);
|
|
678
688
|
const emitDeleteColumnAnalytics = columnCount => {
|
|
679
689
|
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
|
|
680
690
|
action: ACTION.DELETED,
|
|
@@ -682,32 +692,37 @@ export const deleteLayoutColumn = editorAnalyticsAPI => ({
|
|
|
682
692
|
actionSubjectId: ACTION_SUBJECT_ID.LAYOUT_COLUMN,
|
|
683
693
|
attributes: {
|
|
684
694
|
columnCount,
|
|
695
|
+
endIndex,
|
|
685
696
|
inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
|
|
686
|
-
|
|
697
|
+
selectedCount: selectedColumnCount,
|
|
698
|
+
startIndex
|
|
687
699
|
},
|
|
688
700
|
eventType: EVENT_TYPE.TRACK
|
|
689
701
|
})(tr);
|
|
690
702
|
};
|
|
691
703
|
|
|
692
|
-
// If
|
|
693
|
-
if (layoutSectionNode.childCount
|
|
704
|
+
// If all columns are selected, remove the entire layoutSection
|
|
705
|
+
if (selectedColumnCount === layoutSectionNode.childCount) {
|
|
694
706
|
tr.delete(layoutSectionPos, layoutSectionPos + layoutSectionNode.nodeSize);
|
|
695
707
|
emitDeleteColumnAnalytics(0);
|
|
696
708
|
tr.setMeta('scrollIntoView', false);
|
|
697
709
|
return tr;
|
|
698
710
|
}
|
|
699
711
|
|
|
700
|
-
// Build new column list without the selected
|
|
712
|
+
// Build new column list without the selected columns
|
|
701
713
|
const remainingColumns = [];
|
|
702
714
|
layoutSectionNode.forEach((column, _offset, index) => {
|
|
703
|
-
if (index
|
|
715
|
+
if (!selectedColumnIndexSet.has(index)) {
|
|
704
716
|
remainingColumns.push(column);
|
|
705
717
|
}
|
|
706
718
|
});
|
|
707
719
|
|
|
708
720
|
// Redistribute widths proportionally among remaining columns using shared utility
|
|
709
721
|
const existingWidths = mapChildren(layoutSectionNode, column => column.attrs.width);
|
|
710
|
-
const redistributed =
|
|
722
|
+
const redistributed = selectedColumnIndices.slice()
|
|
723
|
+
// Delete highest indices first so lower original indices still point at the same columns
|
|
724
|
+
// as each redistribution step shrinks the widths array.
|
|
725
|
+
.sort((a, b) => b - a).reduce((widths, selectedIndex) => redistributeAfterDeletion(widths, selectedIndex, MIN_LAYOUT_COLUMN_WIDTH_PERCENT), existingWidths);
|
|
711
726
|
const updatedLayoutSectionNode = layoutSectionNode.copy(Fragment.fromArray(remainingColumns));
|
|
712
727
|
tr.replaceWith(layoutSectionPos + 1, layoutSectionPos + layoutSectionNode.nodeSize - 1, columnWidth(updatedLayoutSectionNode, tr.doc.type.schema, redistributed));
|
|
713
728
|
emitDeleteColumnAnalytics(redistributed.length);
|
|
@@ -67,7 +67,8 @@ const getInitialPluginState = (options, state) => {
|
|
|
67
67
|
selectedLayout,
|
|
68
68
|
allowSingleColumnLayout,
|
|
69
69
|
isResizing: false,
|
|
70
|
-
isLayoutColumnMenuOpen: false
|
|
70
|
+
isLayoutColumnMenuOpen: false,
|
|
71
|
+
layoutColumnMenuAnchorPos: undefined
|
|
71
72
|
};
|
|
72
73
|
};
|
|
73
74
|
|
|
@@ -118,7 +119,8 @@ export default (options => {
|
|
|
118
119
|
const columnMenuMeta = tr.getMeta('toggleLayoutColumnMenu');
|
|
119
120
|
const nextPluginState = columnMenuMeta ? {
|
|
120
121
|
...pluginState,
|
|
121
|
-
isLayoutColumnMenuOpen: (_columnMenuMeta$isOpe = columnMenuMeta.isOpen) !== null && _columnMenuMeta$isOpe !== void 0 ? _columnMenuMeta$isOpe : !pluginState.isLayoutColumnMenuOpen
|
|
122
|
+
isLayoutColumnMenuOpen: (_columnMenuMeta$isOpe = columnMenuMeta.isOpen) !== null && _columnMenuMeta$isOpe !== void 0 ? _columnMenuMeta$isOpe : !pluginState.isLayoutColumnMenuOpen,
|
|
123
|
+
layoutColumnMenuAnchorPos: columnMenuMeta.isOpen === false ? undefined : columnMenuMeta.anchorPos
|
|
122
124
|
} : pluginState;
|
|
123
125
|
const isResizing = editorExperiment('single_column_layouts', true) ? (_tr$getMeta = tr.getMeta('is-resizer-resizing')) !== null && _tr$getMeta !== void 0 ? _tr$getMeta : (_pluginKey$getState = pluginKey.getState(oldState)) === null || _pluginKey$getState === void 0 ? void 0 : _pluginKey$getState.isResizing : false;
|
|
124
126
|
if (tr.docChanged || tr.selectionSet) {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
3
|
+
const isLayoutColumn = node => (node === null || node === void 0 ? void 0 : node.type.name) === 'layoutColumn';
|
|
4
|
+
const isLayoutSection = node => (node === null || node === void 0 ? void 0 : node.type.name) === 'layoutSection';
|
|
5
|
+
const getLayoutColumnIndexAtPos = $pos => {
|
|
6
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
7
|
+
if (isLayoutColumn($pos.node(depth)) && isLayoutSection($pos.node(depth - 1))) {
|
|
8
|
+
return $pos.index(depth - 1);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
};
|
|
13
|
+
const getLayoutSectionDepth = selection => {
|
|
14
|
+
const {
|
|
15
|
+
$from,
|
|
16
|
+
$to
|
|
17
|
+
} = selection;
|
|
18
|
+
const sharedDepth = $from.sharedDepth($to.pos);
|
|
19
|
+
for (let depth = sharedDepth; depth > 0; depth--) {
|
|
20
|
+
if (isLayoutSection($from.node(depth))) {
|
|
21
|
+
return depth;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
};
|
|
26
|
+
export const getSelectedLayoutColumns = selection => {
|
|
27
|
+
if (!selection) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
if (selection instanceof NodeSelection && isLayoutColumn(selection.node)) {
|
|
31
|
+
const {
|
|
32
|
+
$from
|
|
33
|
+
} = selection;
|
|
34
|
+
const layoutSectionNode = $from.parent;
|
|
35
|
+
if (!isLayoutSection(layoutSectionNode)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const selectedColumnIndex = $from.index($from.depth);
|
|
39
|
+
return {
|
|
40
|
+
layoutSectionNode,
|
|
41
|
+
layoutSectionPos: $from.before($from.depth),
|
|
42
|
+
selectedColumnIndices: [selectedColumnIndex],
|
|
43
|
+
selectedColumns: [{
|
|
44
|
+
index: selectedColumnIndex,
|
|
45
|
+
node: selection.node,
|
|
46
|
+
pos: selection.from
|
|
47
|
+
}]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (selection.empty) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
if (!editorExperiment('platform_editor_block_menu', true)) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const layoutSectionDepth = getLayoutSectionDepth(selection);
|
|
57
|
+
if (layoutSectionDepth === undefined) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const {
|
|
61
|
+
$from,
|
|
62
|
+
$to
|
|
63
|
+
} = selection;
|
|
64
|
+
const layoutSectionNode = $from.node(layoutSectionDepth);
|
|
65
|
+
const layoutSectionPos = $from.before(layoutSectionDepth);
|
|
66
|
+
const selectedColumns = [];
|
|
67
|
+
let invalidSelection = false;
|
|
68
|
+
layoutSectionNode.forEach((column, offset, index) => {
|
|
69
|
+
const columnStart = layoutSectionPos + 1 + offset;
|
|
70
|
+
const columnEnd = columnStart + column.nodeSize;
|
|
71
|
+
const intersectsColumn = selection.from < columnEnd && selection.to > columnStart;
|
|
72
|
+
if (!intersectsColumn) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!isLayoutColumn(column)) {
|
|
76
|
+
invalidSelection = true;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
selectedColumns.push({
|
|
80
|
+
index,
|
|
81
|
+
node: column,
|
|
82
|
+
pos: columnStart
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// TextSelection inside a single column is normal text editing, not a selected column set.
|
|
87
|
+
if (invalidSelection || selectedColumns.length < 2) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const firstColumn = selectedColumns[0];
|
|
91
|
+
const lastColumn = selectedColumns[selectedColumns.length - 1];
|
|
92
|
+
const startColumnIndex = getLayoutColumnIndexAtPos($from);
|
|
93
|
+
const endColumnIndex = getLayoutColumnIndexAtPos($to);
|
|
94
|
+
if (startColumnIndex !== undefined && startColumnIndex !== firstColumn.index || endColumnIndex !== undefined && endColumnIndex !== lastColumn.index) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
layoutSectionNode,
|
|
99
|
+
layoutSectionPos,
|
|
100
|
+
selectedColumnIndices: selectedColumns.map(({
|
|
101
|
+
index
|
|
102
|
+
}) => index),
|
|
103
|
+
selectedColumns
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export const getLayoutSectionColumnCount = layoutSection => (layoutSection === null || layoutSection === void 0 ? void 0 : layoutSection.type.name) === 'layoutSection' ? layoutSection.childCount : 0;
|
|
107
|
+
export const getLayoutColumnValign = layoutColumn => layoutColumn === null || layoutColumn === void 0 ? void 0 : layoutColumn.attrs.valign;
|
|
108
|
+
export const getLayoutColumnMenuAnchorPos = (selection, anchorPosFromHandle) => {
|
|
109
|
+
var _clickedSelectedColum, _selectedLayoutColumn;
|
|
110
|
+
const selectedLayoutColumns = getSelectedLayoutColumns(selection);
|
|
111
|
+
if (!selectedLayoutColumns) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const clickedSelectedColumn = selectedLayoutColumns.selectedColumns.find(({
|
|
115
|
+
pos
|
|
116
|
+
}) => pos === anchorPosFromHandle);
|
|
117
|
+
return (_clickedSelectedColum = clickedSelectedColumn === null || clickedSelectedColumn === void 0 ? void 0 : clickedSelectedColumn.pos) !== null && _clickedSelectedColum !== void 0 ? _clickedSelectedColum : (_selectedLayoutColumn = selectedLayoutColumns.selectedColumns[0]) === null || _selectedLayoutColumn === void 0 ? void 0 : _selectedLayoutColumn.pos;
|
|
118
|
+
};
|
|
@@ -2,14 +2,14 @@ import React, { useCallback } from 'react';
|
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import { layoutMessages } from '@atlaskit/editor-common/messages';
|
|
4
4
|
import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
|
|
5
|
-
import {
|
|
5
|
+
import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
|
|
6
6
|
const DeleteColumnDropdownItem = ({
|
|
7
7
|
api
|
|
8
8
|
}) => {
|
|
9
9
|
const {
|
|
10
10
|
formatMessage
|
|
11
11
|
} = useIntl();
|
|
12
|
-
const
|
|
12
|
+
const selectedLayoutColumns = useSelectedLayoutColumns(api);
|
|
13
13
|
const onClick = useCallback(() => {
|
|
14
14
|
var _api$layout, _api$core;
|
|
15
15
|
const deleteCommand = api === null || api === void 0 ? void 0 : (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.commands.deleteLayoutColumn;
|
|
@@ -27,11 +27,14 @@ const DeleteColumnDropdownItem = ({
|
|
|
27
27
|
return tr;
|
|
28
28
|
});
|
|
29
29
|
}, [api]);
|
|
30
|
-
if (
|
|
30
|
+
if (selectedLayoutColumns === undefined) {
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
|
+
const selectedColumnCount = selectedLayoutColumns.selectedColumns.length;
|
|
33
34
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
|
|
34
35
|
onClick: onClick
|
|
35
|
-
}, formatMessage(layoutMessages.deleteColumn
|
|
36
|
+
}, formatMessage(layoutMessages.deleteColumn, {
|
|
37
|
+
count: selectedColumnCount
|
|
38
|
+
}));
|
|
36
39
|
};
|
|
37
40
|
export { DeleteColumnDropdownItem };
|
|
@@ -3,8 +3,8 @@ import { useIntl } from 'react-intl';
|
|
|
3
3
|
import { layoutMessages } from '@atlaskit/editor-common/messages';
|
|
4
4
|
import { TableColumnAddLeftIcon, TableColumnAddRightIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
|
|
5
5
|
import { getEffectiveMaxLayoutColumns } from '../../pm-plugins/actions';
|
|
6
|
-
import { getLayoutSectionColumnCount } from '
|
|
7
|
-
import {
|
|
6
|
+
import { getLayoutSectionColumnCount } from '../../pm-plugins/utils/layout-column-selection';
|
|
7
|
+
import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
|
|
8
8
|
const INSERT_COLUMN_OPTIONS = {
|
|
9
9
|
left: {
|
|
10
10
|
Icon: TableColumnAddLeftIcon,
|
|
@@ -28,11 +28,10 @@ export const InsertColumnDropdownItem = ({
|
|
|
28
28
|
Icon,
|
|
29
29
|
label
|
|
30
30
|
} = INSERT_COLUMN_OPTIONS[side];
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const columnCount = getLayoutSectionColumnCount(currentLayoutSection);
|
|
31
|
+
const selectedLayoutColumns = useSelectedLayoutColumns(api);
|
|
32
|
+
const columnCount = getLayoutSectionColumnCount(selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.layoutSectionNode);
|
|
34
33
|
const maxColumnCount = getEffectiveMaxLayoutColumns();
|
|
35
|
-
const canInsertColumn =
|
|
34
|
+
const canInsertColumn = selectedLayoutColumns !== undefined && columnCount < maxColumnCount;
|
|
36
35
|
const onClick = useCallback(() => {
|
|
37
36
|
var _api$layout, _api$core;
|
|
38
37
|
const insertCommand = api === null || api === void 0 ? void 0 : (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.commands.insertLayoutColumn(side);
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import React, { useCallback
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
|
|
4
|
-
import { getLayoutColumnValign } from '
|
|
5
|
-
import {
|
|
4
|
+
import { getLayoutColumnValign } from '../../pm-plugins/utils/layout-column-selection';
|
|
5
|
+
import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
|
|
6
6
|
import { VERTICAL_ALIGN_ICONS } from './verticalAlignIcons';
|
|
7
7
|
export const VerticalAlignDropdownItem = ({
|
|
8
8
|
api,
|
|
9
9
|
label,
|
|
10
10
|
value
|
|
11
11
|
}) => {
|
|
12
|
+
var _selectedLayoutColumn;
|
|
12
13
|
const {
|
|
13
14
|
formatMessage
|
|
14
15
|
} = useIntl();
|
|
15
|
-
const
|
|
16
|
-
const
|
|
16
|
+
const selectedLayoutColumns = useSelectedLayoutColumns(api);
|
|
17
|
+
const isSelected = (_selectedLayoutColumn = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.selectedColumns.every(({
|
|
18
|
+
node
|
|
19
|
+
}) => getLayoutColumnValign(node) === value)) !== null && _selectedLayoutColumn !== void 0 ? _selectedLayoutColumn : false;
|
|
17
20
|
const Icon = VERTICAL_ALIGN_ICONS[value];
|
|
18
21
|
const onClick = useCallback(() => {
|
|
19
22
|
var _api$core, _api$layout;
|
|
@@ -24,7 +27,7 @@ export const VerticalAlignDropdownItem = ({
|
|
|
24
27
|
label: "",
|
|
25
28
|
size: "small"
|
|
26
29
|
}),
|
|
27
|
-
isSelected:
|
|
30
|
+
isSelected: isSelected,
|
|
28
31
|
onClick: onClick
|
|
29
32
|
}, formatMessage(label));
|
|
30
33
|
};
|
|
@@ -2,8 +2,8 @@ import React, { useMemo } from 'react';
|
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import { layoutMessages } from '@atlaskit/editor-common/messages';
|
|
4
4
|
import { LayoutIcon, NestedDropdownRightIcon, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
5
|
-
import { getLayoutColumnValign } from '
|
|
6
|
-
import {
|
|
5
|
+
import { getLayoutColumnValign } from '../../pm-plugins/utils/layout-column-selection';
|
|
6
|
+
import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
|
|
7
7
|
import { VERTICAL_ALIGN_ICONS } from './verticalAlignIcons';
|
|
8
8
|
export const VerticalAlignNestedMenu = ({
|
|
9
9
|
api,
|
|
@@ -12,10 +12,20 @@ export const VerticalAlignNestedMenu = ({
|
|
|
12
12
|
const {
|
|
13
13
|
formatMessage
|
|
14
14
|
} = useIntl();
|
|
15
|
-
const
|
|
16
|
-
const currentValign = useMemo(() =>
|
|
15
|
+
const selectedLayoutColumns = useSelectedLayoutColumns(api);
|
|
16
|
+
const currentValign = useMemo(() => {
|
|
17
|
+
const selectedColumns = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.selectedColumns;
|
|
18
|
+
const firstColumn = selectedColumns === null || selectedColumns === void 0 ? void 0 : selectedColumns[0];
|
|
19
|
+
const firstValign = getLayoutColumnValign(firstColumn === null || firstColumn === void 0 ? void 0 : firstColumn.node);
|
|
20
|
+
if (!firstValign || !(selectedColumns !== null && selectedColumns !== void 0 && selectedColumns.every(({
|
|
21
|
+
node
|
|
22
|
+
}) => getLayoutColumnValign(node) === firstValign))) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return firstValign;
|
|
26
|
+
}, [selectedLayoutColumns]);
|
|
17
27
|
const TriggerIcon = currentValign ? VERTICAL_ALIGN_ICONS[currentValign] : LayoutIcon;
|
|
18
|
-
if (!
|
|
28
|
+
if (!selectedLayoutColumns) {
|
|
19
29
|
return null;
|
|
20
30
|
}
|
|
21
31
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
@@ -7,9 +7,9 @@ import { OutsideClickTargetRefContext, withReactEditorViewOuterListeners } from
|
|
|
7
7
|
import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
|
|
8
8
|
import { ToolbarDropdownMenuProvider } from '@atlaskit/editor-toolbar';
|
|
9
9
|
import { SurfaceRenderer } from '@atlaskit/editor-ui-control-model';
|
|
10
|
+
import { getLayoutColumnMenuAnchorPos } from '../../pm-plugins/utils/layout-column-selection';
|
|
10
11
|
import { LAYOUT_COLUMN_MENU_FALLBACKS } from './components';
|
|
11
12
|
import { LAYOUT_COLUMN_MENU } from './keys';
|
|
12
|
-
import { getLayoutColumnAtSelection } from './layoutColumnSelection';
|
|
13
13
|
const PopupWithListeners = withReactEditorViewOuterListeners(Popup);
|
|
14
14
|
const FALLBACK_MENU_HEIGHT = 300;
|
|
15
15
|
const LAYOUT_COLUMN_MENU_POPUP_OFFSET = [0, 4];
|
|
@@ -17,12 +17,13 @@ const LAYOUT_COLUMN_MENU_POPUP_OFFSET = [0, 4];
|
|
|
17
17
|
/**
|
|
18
18
|
* Returns the drag handle button for the selected layout column.
|
|
19
19
|
*/
|
|
20
|
-
const getLayoutColumnMenuTarget = (editorView, selection) => {
|
|
20
|
+
const getLayoutColumnMenuTarget = (editorView, selection, anchorPosFromHandle) => {
|
|
21
21
|
var _columnDomRef$parentE;
|
|
22
|
-
|
|
22
|
+
const anchorPos = getLayoutColumnMenuAnchorPos(selection, anchorPosFromHandle);
|
|
23
|
+
if (anchorPos === undefined) {
|
|
23
24
|
return null;
|
|
24
25
|
}
|
|
25
|
-
const columnDomRef = editorView.nodeDOM(
|
|
26
|
+
const columnDomRef = editorView.nodeDOM(anchorPos);
|
|
26
27
|
if (!(columnDomRef instanceof HTMLElement)) {
|
|
27
28
|
return null;
|
|
28
29
|
}
|
|
@@ -39,11 +40,13 @@ export const LayoutColumnMenu = /*#__PURE__*/React.memo(function LayoutColumnMen
|
|
|
39
40
|
var _api$uiControlRegistr, _api$uiControlRegistr2;
|
|
40
41
|
const {
|
|
41
42
|
isLayoutColumnMenuOpen,
|
|
43
|
+
layoutColumnMenuAnchorPos,
|
|
42
44
|
selection
|
|
43
45
|
} = useSharedPluginStateWithSelector(api, ['layout', 'selection'], states => {
|
|
44
|
-
var _states$layoutState$i, _states$layoutState, _states$selectionStat;
|
|
46
|
+
var _states$layoutState$i, _states$layoutState, _states$layoutState2, _states$selectionStat;
|
|
45
47
|
return {
|
|
46
48
|
isLayoutColumnMenuOpen: (_states$layoutState$i = (_states$layoutState = states.layoutState) === null || _states$layoutState === void 0 ? void 0 : _states$layoutState.isLayoutColumnMenuOpen) !== null && _states$layoutState$i !== void 0 ? _states$layoutState$i : false,
|
|
49
|
+
layoutColumnMenuAnchorPos: (_states$layoutState2 = states.layoutState) === null || _states$layoutState2 === void 0 ? void 0 : _states$layoutState2.layoutColumnMenuAnchorPos,
|
|
47
50
|
selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection
|
|
48
51
|
};
|
|
49
52
|
});
|
|
@@ -72,6 +75,13 @@ export const LayoutColumnMenu = /*#__PURE__*/React.memo(function LayoutColumnMen
|
|
|
72
75
|
if (event.target instanceof Element && event.target.closest('[data-toolbar-nested-dropdown-menu]')) {
|
|
73
76
|
return;
|
|
74
77
|
}
|
|
78
|
+
|
|
79
|
+
// Clicking a drag handle should let the drag handle's own click handler
|
|
80
|
+
// update selection/menu state. Treating it as a generic outside click
|
|
81
|
+
// races that transaction and can immediately close the layout column menu.
|
|
82
|
+
if (event.target instanceof Element && event.target.closest(DRAG_HANDLE_SELECTOR)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
75
85
|
closeLayoutColumnMenu();
|
|
76
86
|
}, [closeLayoutColumnMenu]);
|
|
77
87
|
const handleSetIsOpen = useCallback(isOpen => {
|
|
@@ -87,7 +97,7 @@ export const LayoutColumnMenu = /*#__PURE__*/React.memo(function LayoutColumnMen
|
|
|
87
97
|
}
|
|
88
98
|
}, [setOutsideClickTargetRef]);
|
|
89
99
|
const components = (_api$uiControlRegistr = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(LAYOUT_COLUMN_MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
|
|
90
|
-
const target = useMemo(() => isLayoutColumnMenuOpen ? getLayoutColumnMenuTarget(editorView, selection) : null, [editorView, isLayoutColumnMenuOpen, selection]);
|
|
100
|
+
const target = useMemo(() => isLayoutColumnMenuOpen ? getLayoutColumnMenuTarget(editorView, selection, layoutColumnMenuAnchorPos) : null, [editorView, isLayoutColumnMenuOpen, layoutColumnMenuAnchorPos, selection]);
|
|
91
101
|
const hasValidTarget = target instanceof HTMLElement;
|
|
92
102
|
useEffect(() => {
|
|
93
103
|
if (isLayoutColumnMenuOpen && (!hasValidTarget || components.length === 0)) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
2
|
+
import { getSelectedLayoutColumns } from '../../pm-plugins/utils/layout-column-selection';
|
|
3
|
+
export const useSelectedLayoutColumns = api => useSharedPluginStateWithSelector(api, ['selection'], states => {
|
|
4
|
+
var _states$selectionStat;
|
|
5
|
+
return getSelectedLayoutColumns((_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection);
|
|
6
|
+
});
|
package/dist/esm/layoutPlugin.js
CHANGED
|
@@ -11,7 +11,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
11
11
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
12
12
|
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
13
13
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
14
|
-
import { createDefaultLayoutSection, createMultiColumnLayoutSection, deleteLayoutColumn as _deleteLayoutColumn, insertLayoutColumn as _insertLayoutColumn, insertLayoutColumnsWithAnalytics, setLayoutColumnValign, toggleLayoutColumnMenu } from './pm-plugins/actions';
|
|
14
|
+
import { createDefaultLayoutSection, createMultiColumnLayoutSection, deleteLayoutColumn as _deleteLayoutColumn, insertLayoutColumn as _insertLayoutColumn, insertLayoutColumnsWithAnalytics, setLayoutColumnValign as _setLayoutColumnValign, toggleLayoutColumnMenu } from './pm-plugins/actions';
|
|
15
15
|
import { default as createLayoutPlugin } from './pm-plugins/main';
|
|
16
16
|
import { pluginKey } from './pm-plugins/plugin-key';
|
|
17
17
|
import { default as createLayoutResizingPlugin } from './pm-plugins/resizing';
|
|
@@ -378,7 +378,10 @@ export var layoutPlugin = function layoutPlugin(_ref) {
|
|
|
378
378
|
var _api$analytics5;
|
|
379
379
|
return _insertLayoutColumn(side, api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions);
|
|
380
380
|
},
|
|
381
|
-
setLayoutColumnValign: setLayoutColumnValign
|
|
381
|
+
setLayoutColumnValign: function setLayoutColumnValign(valign) {
|
|
382
|
+
var _api$analytics6;
|
|
383
|
+
return _setLayoutColumnValign(valign, api === null || api === void 0 || (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 ? void 0 : _api$analytics6.actions);
|
|
384
|
+
},
|
|
382
385
|
toggleLayoutColumnMenu: toggleLayoutColumnMenu
|
|
383
386
|
}
|
|
384
387
|
};
|