@atlaskit/editor-plugin-block-controls 2.0.0 → 2.0.2

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 2.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#138575](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/138575)
8
+ [`d97bfb713c2b9`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/d97bfb713c2b9) -
9
+ [ux] Fix handles not showing or in wrong pos for divider nodes in panels/expands
10
+ - Updated dependencies
11
+
12
+ ## 2.0.1
13
+
14
+ ### Patch Changes
15
+
16
+ - [#141656](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/141656)
17
+ [`3d7bc0bff5bea`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/3d7bc0bff5bea) -
18
+ [ux] ED-24969 Add CSS override to prevent drag handle overlap with empty line prompt button when
19
+ under an expanded code block
20
+
3
21
  ## 2.0.0
4
22
 
5
23
  ### Major Changes
@@ -31,6 +31,7 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
31
31
  var rootElement = target === null || target === void 0 ? void 0 : target.closest('[data-drag-handler-anchor-name]');
32
32
  if (rootElement) {
33
33
  var _rootElement$parentEl;
34
+ // We want to exlude handles from showing for empty paragraph and heading nodes
34
35
  if ((0, _experiments.editorExperiment)('nested-dnd', true, {
35
36
  exposure: true
36
37
  }) && isEmptyNestedParagraphOrHeading(rootElement)) {
@@ -38,50 +39,49 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
38
39
  }
39
40
  var parentElement = (_rootElement$parentEl = rootElement.parentElement) === null || _rootElement$parentEl === void 0 ? void 0 : _rootElement$parentEl.closest('[data-drag-handler-anchor-name]');
40
41
  var parentElementType = parentElement === null || parentElement === void 0 ? void 0 : parentElement.getAttribute('data-drag-handler-node-type');
41
- if (parentElement && parentElementType === 'panel' && (0, _experiments.editorExperiment)('nested-dnd', true)) {
42
- var eventTargetPos = view.posAtDOM(rootElement, 0, -1);
43
- var $eventTargetPos = view.state.doc.resolve(eventTargetPos);
44
- var depth = $eventTargetPos.depth > 1 ? $eventTargetPos.depth - 1 : $eventTargetPos.depth;
45
- if ($eventTargetPos.node(depth).firstChild === $eventTargetPos.node()) {
46
- return false;
47
- }
48
- }
42
+ // We want to exlude handles from showing for direct decendant of table nodes (i.e. nodes in cells)
49
43
  if (parentElement && parentElementType === 'table' && (0, _experiments.editorExperiment)('nested-dnd', true) && (0, _experiments.editorExperiment)('table-nested-dnd', false, {
50
44
  exposure: true
51
45
  })) {
52
46
  rootElement = parentElement;
53
47
  }
54
48
  var anchorName = rootElement.getAttribute('data-drag-handler-anchor-name');
55
- var nodeType = rootElement.getAttribute('data-drag-handler-node-type');
49
+ // No need to update handle position if its already there
56
50
  if ((activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) === anchorName) {
57
51
  return false;
58
52
  }
53
+
54
+ // We want to exlude handles from showing for wrapped nodes
59
55
  if (['wrap-right', 'wrap-left'].includes(rootElement.getAttribute('layout') || '') && (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_24227')) {
60
56
  return false;
61
57
  }
62
- var pos = view.posAtDOM(rootElement, 0, -1);
58
+ var parentRootElement = rootElement.parentElement;
59
+ var pos;
60
+ if (parentRootElement && (0, _experiments.editorExperiment)('nested-dnd', true, {
61
+ exposure: true
62
+ })) {
63
+ var _parentRootElement$ch;
64
+ var childNodes = Array.from(parentRootElement.childNodes);
65
+ var index = childNodes.indexOf(rootElement);
66
+ pos = view.posAtDOM(parentRootElement, index);
67
+
68
+ // We want to exlude handles showing for first element in a Panel, ignoring widgets like gapcursor
69
+ var firstChildIsWidget = parentRootElement === null || parentRootElement === void 0 || (_parentRootElement$ch = parentRootElement.children[0]) === null || _parentRootElement$ch === void 0 ? void 0 : _parentRootElement$ch.classList.contains('ProseMirror-widget');
70
+ if (parentElement && parentElementType === 'panel' && (index === 0 || firstChildIsWidget && index === 1)) {
71
+ return false;
72
+ }
73
+ } else {
74
+ pos = view.posAtDOM(rootElement, 0);
75
+ }
63
76
  var rootPos;
64
77
  if ((0, _experiments.editorExperiment)('nested-dnd', true, {
65
78
  exposure: true
66
79
  })) {
67
- var _$rootPos$parent, _$rootPos$parent2, _$rootPos$nodeAfter;
68
- var $rootPos = view.state.doc.resolve(pos);
69
- var _depth = $rootPos.depth;
70
- var isParentAnIsolatingNode = ((_$rootPos$parent = $rootPos.parent) === null || _$rootPos$parent === void 0 ? void 0 : _$rootPos$parent.type.name) !== 'doc' && ((_$rootPos$parent2 = $rootPos.parent) === null || _$rootPos$parent2 === void 0 ? void 0 : _$rootPos$parent2.type.spec.isolating);
71
- var isCurrentNodeAtom = (_$rootPos$nodeAfter = $rootPos.nodeAfter) === null || _$rootPos$nodeAfter === void 0 ? void 0 : _$rootPos$nodeAfter.isAtom;
72
-
73
- /**
74
- * If the parent node is an isolating node, the sides of nodes of this type are considered boundaries, such as a table cell.
75
- * And the current node, as a direct child, is an atom node, meaning it does not have directly editable content.
76
- * e.g. a card or an extension
77
- * We maintain the original position by adding 1 to the depth.
78
- * This prevents the decoration from being inserted in the wrong position, like between table cells.
79
- */
80
- var posDepth = isParentAnIsolatingNode && isCurrentNodeAtom ? _depth + 1 : _depth;
81
- rootPos = _depth ? $rootPos.before(posDepth) : $rootPos.pos;
80
+ rootPos = view.state.doc.resolve(pos).pos;
82
81
  } else {
83
82
  rootPos = view.state.doc.resolve(pos).start(1) - 1;
84
83
  }
84
+ var nodeType = rootElement.getAttribute('data-drag-handler-node-type');
85
85
  if (nodeType) {
86
86
  var _api$core, _api$blockControls2;
87
87
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(rootPos, anchorName, nodeType));
@@ -348,6 +348,8 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl) {
348
348
  if (!nodeElement) {
349
349
  return false;
350
350
  }
351
+
352
+ // TODO: Review usage of posAtDOM here
351
353
  var domPos = (0, _platformFeatureFlags.fg)('platform_editor_element_drag_and_drop_ed_24304') ? Math.max(view.posAtDOM(nodeElement, 0) - 1, 0) : view.posAtDOM(nodeElement, 0) - 1;
352
354
  var nodeTarget = state.doc.nodeAt(domPos);
353
355
  var isSameNode = !!(nodeTarget && draggable !== null && draggable !== void 0 && draggable.eq(nodeTarget));
@@ -18,6 +18,8 @@ var emptyBlockExperimentWidget = '.ProseMirror-widget[data-empty-block-experimen
18
18
  var quickInsertWidget = '.ProseMirror-widget[data-type-ahead="typeaheadDecoration"]';
19
19
  var formattingElement = 'div.fabric-editor-block-mark';
20
20
  var markFragment = 'div[data-mark-type="fragment"]';
21
+ var breakoutMark = 'div.fabric-editor-breakout-mark';
22
+ var breakoutMarkDom = 'div.fabric-editor-breakout-mark-dom';
21
23
  var elementWithEmptyBlockExperiment = "+ p > ".concat(emptyBlockExperimentWidget, ", + h1 > ").concat(emptyBlockExperimentWidget, ", + h2 > ").concat(emptyBlockExperimentWidget, ", + h3 > ").concat(emptyBlockExperimentWidget, ", + h4 > ").concat(emptyBlockExperimentWidget, ", + h5 > ").concat(emptyBlockExperimentWidget, ", + h6 > ").concat(emptyBlockExperimentWidget);
22
24
  // Selectors for when contained withing a formatting container mark (eg. indent, centering, right-align)
23
25
  var elementWithEmptyBlockExperimentFormatted = "+ ".concat(formattingElement, " > p > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h1 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h2 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h3 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h4 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h5 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h6 > ").concat(emptyBlockExperimentWidget);
@@ -28,7 +30,11 @@ var dragHandleSelector = 'button[data-testid="block-ctrl-drag-handle"]';
28
30
  // Override is consistent with how the drag handle is hidden when the block contains a placeholder
29
31
  var dragHandleWithInlineNodeStyle = (0, _react.css)((0, _defineProperty2.default)({}, "".concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperiment, "),\n\t\t").concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperimentFormatted, "),") + // In certain circumstances - eg. a paragraph after an indent, or after a table fragment, the dragHandleContainer
30
32
  // is nested in the previous div. These selectors are to handle those cases.
31
- "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child"), {
33
+ // -------------------
34
+ // Empty block in new paragraph after indent
35
+ "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child,") + // Empty block in new paragraph after table
36
+ "".concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child,") + // Empty block in new paragraph after breakout mark
37
+ "".concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child,\n\t").concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child"), {
32
38
  display: 'none !important'
33
39
  }));
34
40
 
@@ -41,7 +47,11 @@ var dragHandleWithInlineNodeStyle = (0, _react.css)((0, _defineProperty2.default
41
47
  */
42
48
  var dragHandleWithInlineNodeStyleWithChromeFix = (0, _react.css)((0, _defineProperty2.default)({}, "".concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperiment, ") ").concat(dragHandleSelector, ",\n\t\t").concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperimentFormatted, ") ").concat(dragHandleSelector, ",") + // In certain circumstances - eg. a paragraph after an indent, or after a table fragment, the dragHandleContainer
43
49
  // is nested in the previous div. These selectors are to handle those cases.
44
- "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector), {
50
+ // -------------------
51
+ // Empty block in new paragraph after indent
52
+ "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",") + // Empty block in new paragraph after table
53
+ "".concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",") + // Empty block in new paragraph after breakout mark
54
+ "".concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector), {
45
55
  transform: 'scale(0)'
46
56
  }));
47
57
  var getDragHandleOverrides = function getDragHandleOverrides() {
@@ -26,6 +26,7 @@ export const handleMouseOver = (view, event, api) => {
26
26
  let rootElement = target === null || target === void 0 ? void 0 : target.closest('[data-drag-handler-anchor-name]');
27
27
  if (rootElement) {
28
28
  var _rootElement$parentEl;
29
+ // We want to exlude handles from showing for empty paragraph and heading nodes
29
30
  if (editorExperiment('nested-dnd', true, {
30
31
  exposure: true
31
32
  }) && isEmptyNestedParagraphOrHeading(rootElement)) {
@@ -33,50 +34,49 @@ export const handleMouseOver = (view, event, api) => {
33
34
  }
34
35
  const parentElement = (_rootElement$parentEl = rootElement.parentElement) === null || _rootElement$parentEl === void 0 ? void 0 : _rootElement$parentEl.closest('[data-drag-handler-anchor-name]');
35
36
  const parentElementType = parentElement === null || parentElement === void 0 ? void 0 : parentElement.getAttribute('data-drag-handler-node-type');
36
- if (parentElement && parentElementType === 'panel' && editorExperiment('nested-dnd', true)) {
37
- const eventTargetPos = view.posAtDOM(rootElement, 0, -1);
38
- const $eventTargetPos = view.state.doc.resolve(eventTargetPos);
39
- const depth = $eventTargetPos.depth > 1 ? $eventTargetPos.depth - 1 : $eventTargetPos.depth;
40
- if ($eventTargetPos.node(depth).firstChild === $eventTargetPos.node()) {
41
- return false;
42
- }
43
- }
37
+ // We want to exlude handles from showing for direct decendant of table nodes (i.e. nodes in cells)
44
38
  if (parentElement && parentElementType === 'table' && editorExperiment('nested-dnd', true) && editorExperiment('table-nested-dnd', false, {
45
39
  exposure: true
46
40
  })) {
47
41
  rootElement = parentElement;
48
42
  }
49
43
  const anchorName = rootElement.getAttribute('data-drag-handler-anchor-name');
50
- const nodeType = rootElement.getAttribute('data-drag-handler-node-type');
44
+ // No need to update handle position if its already there
51
45
  if ((activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) === anchorName) {
52
46
  return false;
53
47
  }
48
+
49
+ // We want to exlude handles from showing for wrapped nodes
54
50
  if (['wrap-right', 'wrap-left'].includes(rootElement.getAttribute('layout') || '') && fg('platform_editor_element_drag_and_drop_ed_24227')) {
55
51
  return false;
56
52
  }
57
- const pos = view.posAtDOM(rootElement, 0, -1);
53
+ const parentRootElement = rootElement.parentElement;
54
+ let pos;
55
+ if (parentRootElement && editorExperiment('nested-dnd', true, {
56
+ exposure: true
57
+ })) {
58
+ var _parentRootElement$ch;
59
+ const childNodes = Array.from(parentRootElement.childNodes);
60
+ const index = childNodes.indexOf(rootElement);
61
+ pos = view.posAtDOM(parentRootElement, index);
62
+
63
+ // We want to exlude handles showing for first element in a Panel, ignoring widgets like gapcursor
64
+ const firstChildIsWidget = parentRootElement === null || parentRootElement === void 0 ? void 0 : (_parentRootElement$ch = parentRootElement.children[0]) === null || _parentRootElement$ch === void 0 ? void 0 : _parentRootElement$ch.classList.contains('ProseMirror-widget');
65
+ if (parentElement && parentElementType === 'panel' && (index === 0 || firstChildIsWidget && index === 1)) {
66
+ return false;
67
+ }
68
+ } else {
69
+ pos = view.posAtDOM(rootElement, 0);
70
+ }
58
71
  let rootPos;
59
72
  if (editorExperiment('nested-dnd', true, {
60
73
  exposure: true
61
74
  })) {
62
- var _$rootPos$parent, _$rootPos$parent2, _$rootPos$nodeAfter;
63
- const $rootPos = view.state.doc.resolve(pos);
64
- const depth = $rootPos.depth;
65
- const isParentAnIsolatingNode = ((_$rootPos$parent = $rootPos.parent) === null || _$rootPos$parent === void 0 ? void 0 : _$rootPos$parent.type.name) !== 'doc' && ((_$rootPos$parent2 = $rootPos.parent) === null || _$rootPos$parent2 === void 0 ? void 0 : _$rootPos$parent2.type.spec.isolating);
66
- const isCurrentNodeAtom = (_$rootPos$nodeAfter = $rootPos.nodeAfter) === null || _$rootPos$nodeAfter === void 0 ? void 0 : _$rootPos$nodeAfter.isAtom;
67
-
68
- /**
69
- * If the parent node is an isolating node, the sides of nodes of this type are considered boundaries, such as a table cell.
70
- * And the current node, as a direct child, is an atom node, meaning it does not have directly editable content.
71
- * e.g. a card or an extension
72
- * We maintain the original position by adding 1 to the depth.
73
- * This prevents the decoration from being inserted in the wrong position, like between table cells.
74
- */
75
- const posDepth = isParentAnIsolatingNode && isCurrentNodeAtom ? depth + 1 : depth;
76
- rootPos = depth ? $rootPos.before(posDepth) : $rootPos.pos;
75
+ rootPos = view.state.doc.resolve(pos).pos;
77
76
  } else {
78
77
  rootPos = view.state.doc.resolve(pos).start(1) - 1;
79
78
  }
79
+ const nodeType = rootElement.getAttribute('data-drag-handler-node-type');
80
80
  if (nodeType) {
81
81
  var _api$core, _api$blockControls2;
82
82
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(rootPos, anchorName, nodeType));
@@ -326,6 +326,8 @@ export const createPlugin = (api, getIntl) => {
326
326
  if (!nodeElement) {
327
327
  return false;
328
328
  }
329
+
330
+ // TODO: Review usage of posAtDOM here
329
331
  const domPos = fg('platform_editor_element_drag_and_drop_ed_24304') ? Math.max(view.posAtDOM(nodeElement, 0) - 1, 0) : view.posAtDOM(nodeElement, 0) - 1;
330
332
  const nodeTarget = state.doc.nodeAt(domPos);
331
333
  const isSameNode = !!(nodeTarget && draggable !== null && draggable !== void 0 && draggable.eq(nodeTarget));
@@ -9,6 +9,8 @@ const emptyBlockExperimentWidget = '.ProseMirror-widget[data-empty-block-experim
9
9
  const quickInsertWidget = '.ProseMirror-widget[data-type-ahead="typeaheadDecoration"]';
10
10
  const formattingElement = 'div.fabric-editor-block-mark';
11
11
  const markFragment = 'div[data-mark-type="fragment"]';
12
+ const breakoutMark = 'div.fabric-editor-breakout-mark';
13
+ const breakoutMarkDom = 'div.fabric-editor-breakout-mark-dom';
12
14
  const elementWithEmptyBlockExperiment = `+ p > ${emptyBlockExperimentWidget}, + h1 > ${emptyBlockExperimentWidget}, + h2 > ${emptyBlockExperimentWidget}, + h3 > ${emptyBlockExperimentWidget}, + h4 > ${emptyBlockExperimentWidget}, + h5 > ${emptyBlockExperimentWidget}, + h6 > ${emptyBlockExperimentWidget}`;
13
15
  // Selectors for when contained withing a formatting container mark (eg. indent, centering, right-align)
14
16
  const elementWithEmptyBlockExperimentFormatted = `+ ${formattingElement} > p > ${emptyBlockExperimentWidget}, + ${formattingElement} > h1 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h2 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h3 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h4 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h5 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h6 > ${emptyBlockExperimentWidget}`;
@@ -22,10 +24,16 @@ const dragHandleWithInlineNodeStyle = css({
22
24
  ${dragHandleContainer}:has(${elementWithEmptyBlockExperimentFormatted}),` +
23
25
  // In certain circumstances - eg. a paragraph after an indent, or after a table fragment, the dragHandleContainer
24
26
  // is nested in the previous div. These selectors are to handle those cases.
27
+ // -------------------
28
+ // Empty block in new paragraph after indent
25
29
  `${formattingElement}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${dragHandleContainer}:last-child,
26
- ${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${dragHandleContainer}:last-child,
27
- ${formattingElement}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child,
28
- ${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child`]: {
30
+ ${formattingElement}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child,` +
31
+ // Empty block in new paragraph after table
32
+ `${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${dragHandleContainer}:last-child,
33
+ ${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child,` +
34
+ // Empty block in new paragraph after breakout mark
35
+ `${breakoutMark}:has(> ${breakoutMarkDom} > ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${breakoutMarkDom} > ${dragHandleContainer}:last-child,
36
+ ${breakoutMark}:has(> ${breakoutMarkDom} > ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${breakoutMarkDom} > ${dragHandleContainer}:last-child`]: {
29
37
  display: 'none !important'
30
38
  }
31
39
  });
@@ -42,10 +50,16 @@ const dragHandleWithInlineNodeStyleWithChromeFix = css({
42
50
  ${dragHandleContainer}:has(${elementWithEmptyBlockExperimentFormatted}) ${dragHandleSelector},` +
43
51
  // In certain circumstances - eg. a paragraph after an indent, or after a table fragment, the dragHandleContainer
44
52
  // is nested in the previous div. These selectors are to handle those cases.
53
+ // -------------------
54
+ // Empty block in new paragraph after indent
45
55
  `${formattingElement}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${dragHandleContainer}:last-child ${dragHandleSelector},
46
- ${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${dragHandleContainer}:last-child ${dragHandleSelector},
47
- ${formattingElement}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child ${dragHandleSelector},
48
- ${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child ${dragHandleSelector}`]: {
56
+ ${formattingElement}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child ${dragHandleSelector},` +
57
+ // Empty block in new paragraph after table
58
+ `${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${dragHandleContainer}:last-child ${dragHandleSelector},
59
+ ${markFragment}:has(> ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${dragHandleContainer}:last-child ${dragHandleSelector},` +
60
+ // Empty block in new paragraph after breakout mark
61
+ `${breakoutMark}:has(> ${breakoutMarkDom} > ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperiment}) > ${breakoutMarkDom} > ${dragHandleContainer}:last-child ${dragHandleSelector},
62
+ ${breakoutMark}:has(> ${breakoutMarkDom} > ${dragHandleContainer}:last-child):has(${elementWithEmptyBlockExperimentFormatted}) > ${breakoutMarkDom} > ${dragHandleContainer}:last-child ${dragHandleSelector}`]: {
49
63
  transform: 'scale(0)'
50
64
  }
51
65
  });
@@ -25,6 +25,7 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
25
25
  var rootElement = target === null || target === void 0 ? void 0 : target.closest('[data-drag-handler-anchor-name]');
26
26
  if (rootElement) {
27
27
  var _rootElement$parentEl;
28
+ // We want to exlude handles from showing for empty paragraph and heading nodes
28
29
  if (editorExperiment('nested-dnd', true, {
29
30
  exposure: true
30
31
  }) && isEmptyNestedParagraphOrHeading(rootElement)) {
@@ -32,50 +33,49 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
32
33
  }
33
34
  var parentElement = (_rootElement$parentEl = rootElement.parentElement) === null || _rootElement$parentEl === void 0 ? void 0 : _rootElement$parentEl.closest('[data-drag-handler-anchor-name]');
34
35
  var parentElementType = parentElement === null || parentElement === void 0 ? void 0 : parentElement.getAttribute('data-drag-handler-node-type');
35
- if (parentElement && parentElementType === 'panel' && editorExperiment('nested-dnd', true)) {
36
- var eventTargetPos = view.posAtDOM(rootElement, 0, -1);
37
- var $eventTargetPos = view.state.doc.resolve(eventTargetPos);
38
- var depth = $eventTargetPos.depth > 1 ? $eventTargetPos.depth - 1 : $eventTargetPos.depth;
39
- if ($eventTargetPos.node(depth).firstChild === $eventTargetPos.node()) {
40
- return false;
41
- }
42
- }
36
+ // We want to exlude handles from showing for direct decendant of table nodes (i.e. nodes in cells)
43
37
  if (parentElement && parentElementType === 'table' && editorExperiment('nested-dnd', true) && editorExperiment('table-nested-dnd', false, {
44
38
  exposure: true
45
39
  })) {
46
40
  rootElement = parentElement;
47
41
  }
48
42
  var anchorName = rootElement.getAttribute('data-drag-handler-anchor-name');
49
- var nodeType = rootElement.getAttribute('data-drag-handler-node-type');
43
+ // No need to update handle position if its already there
50
44
  if ((activeNode === null || activeNode === void 0 ? void 0 : activeNode.anchorName) === anchorName) {
51
45
  return false;
52
46
  }
47
+
48
+ // We want to exlude handles from showing for wrapped nodes
53
49
  if (['wrap-right', 'wrap-left'].includes(rootElement.getAttribute('layout') || '') && fg('platform_editor_element_drag_and_drop_ed_24227')) {
54
50
  return false;
55
51
  }
56
- var pos = view.posAtDOM(rootElement, 0, -1);
52
+ var parentRootElement = rootElement.parentElement;
53
+ var pos;
54
+ if (parentRootElement && editorExperiment('nested-dnd', true, {
55
+ exposure: true
56
+ })) {
57
+ var _parentRootElement$ch;
58
+ var childNodes = Array.from(parentRootElement.childNodes);
59
+ var index = childNodes.indexOf(rootElement);
60
+ pos = view.posAtDOM(parentRootElement, index);
61
+
62
+ // We want to exlude handles showing for first element in a Panel, ignoring widgets like gapcursor
63
+ var firstChildIsWidget = parentRootElement === null || parentRootElement === void 0 || (_parentRootElement$ch = parentRootElement.children[0]) === null || _parentRootElement$ch === void 0 ? void 0 : _parentRootElement$ch.classList.contains('ProseMirror-widget');
64
+ if (parentElement && parentElementType === 'panel' && (index === 0 || firstChildIsWidget && index === 1)) {
65
+ return false;
66
+ }
67
+ } else {
68
+ pos = view.posAtDOM(rootElement, 0);
69
+ }
57
70
  var rootPos;
58
71
  if (editorExperiment('nested-dnd', true, {
59
72
  exposure: true
60
73
  })) {
61
- var _$rootPos$parent, _$rootPos$parent2, _$rootPos$nodeAfter;
62
- var $rootPos = view.state.doc.resolve(pos);
63
- var _depth = $rootPos.depth;
64
- var isParentAnIsolatingNode = ((_$rootPos$parent = $rootPos.parent) === null || _$rootPos$parent === void 0 ? void 0 : _$rootPos$parent.type.name) !== 'doc' && ((_$rootPos$parent2 = $rootPos.parent) === null || _$rootPos$parent2 === void 0 ? void 0 : _$rootPos$parent2.type.spec.isolating);
65
- var isCurrentNodeAtom = (_$rootPos$nodeAfter = $rootPos.nodeAfter) === null || _$rootPos$nodeAfter === void 0 ? void 0 : _$rootPos$nodeAfter.isAtom;
66
-
67
- /**
68
- * If the parent node is an isolating node, the sides of nodes of this type are considered boundaries, such as a table cell.
69
- * And the current node, as a direct child, is an atom node, meaning it does not have directly editable content.
70
- * e.g. a card or an extension
71
- * We maintain the original position by adding 1 to the depth.
72
- * This prevents the decoration from being inserted in the wrong position, like between table cells.
73
- */
74
- var posDepth = isParentAnIsolatingNode && isCurrentNodeAtom ? _depth + 1 : _depth;
75
- rootPos = _depth ? $rootPos.before(posDepth) : $rootPos.pos;
74
+ rootPos = view.state.doc.resolve(pos).pos;
76
75
  } else {
77
76
  rootPos = view.state.doc.resolve(pos).start(1) - 1;
78
77
  }
78
+ var nodeType = rootElement.getAttribute('data-drag-handler-node-type');
79
79
  if (nodeType) {
80
80
  var _api$core, _api$blockControls2;
81
81
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(rootPos, anchorName, nodeType));
@@ -341,6 +341,8 @@ export var createPlugin = function createPlugin(api, getIntl) {
341
341
  if (!nodeElement) {
342
342
  return false;
343
343
  }
344
+
345
+ // TODO: Review usage of posAtDOM here
344
346
  var domPos = fg('platform_editor_element_drag_and_drop_ed_24304') ? Math.max(view.posAtDOM(nodeElement, 0) - 1, 0) : view.posAtDOM(nodeElement, 0) - 1;
345
347
  var nodeTarget = state.doc.nodeAt(domPos);
346
348
  var isSameNode = !!(nodeTarget && draggable !== null && draggable !== void 0 && draggable.eq(nodeTarget));
@@ -10,6 +10,8 @@ var emptyBlockExperimentWidget = '.ProseMirror-widget[data-empty-block-experimen
10
10
  var quickInsertWidget = '.ProseMirror-widget[data-type-ahead="typeaheadDecoration"]';
11
11
  var formattingElement = 'div.fabric-editor-block-mark';
12
12
  var markFragment = 'div[data-mark-type="fragment"]';
13
+ var breakoutMark = 'div.fabric-editor-breakout-mark';
14
+ var breakoutMarkDom = 'div.fabric-editor-breakout-mark-dom';
13
15
  var elementWithEmptyBlockExperiment = "+ p > ".concat(emptyBlockExperimentWidget, ", + h1 > ").concat(emptyBlockExperimentWidget, ", + h2 > ").concat(emptyBlockExperimentWidget, ", + h3 > ").concat(emptyBlockExperimentWidget, ", + h4 > ").concat(emptyBlockExperimentWidget, ", + h5 > ").concat(emptyBlockExperimentWidget, ", + h6 > ").concat(emptyBlockExperimentWidget);
14
16
  // Selectors for when contained withing a formatting container mark (eg. indent, centering, right-align)
15
17
  var elementWithEmptyBlockExperimentFormatted = "+ ".concat(formattingElement, " > p > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h1 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h2 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h3 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h4 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h5 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h6 > ").concat(emptyBlockExperimentWidget);
@@ -20,7 +22,11 @@ var dragHandleSelector = 'button[data-testid="block-ctrl-drag-handle"]';
20
22
  // Override is consistent with how the drag handle is hidden when the block contains a placeholder
21
23
  var dragHandleWithInlineNodeStyle = css(_defineProperty({}, "".concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperiment, "),\n\t\t").concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperimentFormatted, "),") + // In certain circumstances - eg. a paragraph after an indent, or after a table fragment, the dragHandleContainer
22
24
  // is nested in the previous div. These selectors are to handle those cases.
23
- "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child"), {
25
+ // -------------------
26
+ // Empty block in new paragraph after indent
27
+ "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child,") + // Empty block in new paragraph after table
28
+ "".concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child,\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child,") + // Empty block in new paragraph after breakout mark
29
+ "".concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child,\n\t").concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child"), {
24
30
  display: 'none !important'
25
31
  }));
26
32
 
@@ -33,7 +39,11 @@ var dragHandleWithInlineNodeStyle = css(_defineProperty({}, "".concat(dragHandle
33
39
  */
34
40
  var dragHandleWithInlineNodeStyleWithChromeFix = css(_defineProperty({}, "".concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperiment, ") ").concat(dragHandleSelector, ",\n\t\t").concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperimentFormatted, ") ").concat(dragHandleSelector, ",") + // In certain circumstances - eg. a paragraph after an indent, or after a table fragment, the dragHandleContainer
35
41
  // is nested in the previous div. These selectors are to handle those cases.
36
- "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector), {
42
+ // -------------------
43
+ // Empty block in new paragraph after indent
44
+ "".concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t").concat(formattingElement, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",") + // Empty block in new paragraph after table
45
+ "".concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(markFragment, ":has(> ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",") + // Empty block in new paragraph after breakout mark
46
+ "".concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperiment, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector, ",\n\t\t").concat(breakoutMark, ":has(> ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child):has(").concat(elementWithEmptyBlockExperimentFormatted, ") > ").concat(breakoutMarkDom, " > ").concat(dragHandleContainer, ":last-child ").concat(dragHandleSelector), {
37
47
  transform: 'scale(0)'
38
48
  }));
39
49
  var getDragHandleOverrides = function getDragHandleOverrides() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -30,7 +30,7 @@
30
30
  ".": "./src/index.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@atlaskit/editor-common": "^89.1.0",
33
+ "@atlaskit/editor-common": "^89.3.0",
34
34
  "@atlaskit/editor-plugin-accessibility-utils": "^1.2.0",
35
35
  "@atlaskit/editor-plugin-analytics": "^1.8.0",
36
36
  "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",