@atlaskit/editor-plugin-block-controls 11.2.0 → 11.2.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
+ ## 11.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 11.2.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [`4642f37c59f0f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4642f37c59f0f) -
14
+ Fix Remix button not appearing when hovering over tables in live page view mode. When the
15
+ `platform_editor_native_anchor_with_dnd` experiment is disabled, table rows only have
16
+ `data-node-anchor` (not `data-drag-handler-anchor-name`), so hover detection and anchor resolution
17
+ now fall back to `data-node-anchor`. Also fixes right-edge positioning for wide/max breakout
18
+ tables using `getBoundingClientRect`.
19
+ - Updated dependencies
20
+
3
21
  ## 11.2.0
4
22
 
5
23
  ### Minor Changes
@@ -99,6 +99,19 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
99
99
  }
100
100
  var rootElement = target === null || target === void 0 ? void 0 : target.closest(isNativeAnchorSupported ? getDefaultNodeSelector() : "[data-drag-handler-anchor-name]");
101
101
 
102
+ // Fallback for table nodes in view mode: the table-anchor-names plugin sets data-node-anchor on
103
+ // the first <tr> element.
104
+ // - When platform_editor_native_anchor_with_dnd is disabled, the primary closest() uses
105
+ // [data-drag-handler-anchor-name] and misses table rows. Try data-node-anchor via closest().
106
+ // - For wide/max breakout tables, hovering in the left/right margin area of the full-viewport-
107
+ // width breakout wrapper (ak-editor-breakout-mark) sets event.target to the wrapper div, which
108
+ // has no anchor attribute. Use querySelector to find the [data-node-anchor] descendant inside.
109
+ // Both cases apply only in view mode with right-side remix controls.
110
+ if (!rootElement && isViewMode && rightSideControlsEnabled) {
111
+ var _ref3, _target$closest;
112
+ rootElement = (_ref3 = (_target$closest = target === null || target === void 0 ? void 0 : target.closest("[".concat(_domAttrName.NODE_ANCHOR_ATTR_NAME, "]"))) !== null && _target$closest !== void 0 ? _target$closest : target instanceof HTMLElement ? target.querySelector("[".concat(_domAttrName.NODE_ANCHOR_ATTR_NAME, "]")) : null) !== null && _ref3 !== void 0 ? _ref3 : null;
113
+ }
114
+
102
115
  // When hovering over the right-edge button (rendered in a portal outside the block), resolve the
103
116
  // block from the container's anchor so activeNode stays set and the button remains visible.
104
117
  if (!rootElement && rightSideControlsEnabled && (0, _platformFeatureFlags.fg)('confluence_remix_button_right_side_block_fg')) {
@@ -111,7 +124,7 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
111
124
  }
112
125
  }
113
126
  if (rootElement) {
114
- var _rootElement$parentEl;
127
+ var _rootElement$parentEl, _rootElement$getAttri2;
115
128
  // We want to exlude handles from showing for empty paragraph and heading nodes
116
129
  if (isEmptyNestedParagraphOrHeading(rootElement)) {
117
130
  return false;
@@ -184,6 +197,11 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
184
197
  // Ignored via go/ees005
185
198
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
186
199
  anchorName = rootElement.getAttribute((0, _domAttrName.getAnchorAttrName)());
200
+ // Fallback for table nodes that only have data-node-anchor (not data-drag-handler-anchor-name).
201
+ if (!anchorName) {
202
+ var _rootElement$getAttri;
203
+ anchorName = (_rootElement$getAttri = rootElement.getAttribute(_domAttrName.NODE_ANCHOR_ATTR_NAME)) !== null && _rootElement$getAttri !== void 0 ? _rootElement$getAttri : anchorName;
204
+ }
187
205
  }
188
206
 
189
207
  // No need to update handle position if its already there
@@ -231,13 +249,16 @@ var handleMouseOver = exports.handleMouseOver = function handleMouseOver(view, e
231
249
  if (targetPos !== rootPos) {
232
250
  var rootDOM = view.nodeDOM(rootPos);
233
251
  if (rootDOM instanceof HTMLElement) {
234
- var _rootDOM$getAttribute;
235
- rootAnchorName = (_rootDOM$getAttribute = rootDOM.getAttribute((0, _domAttrName.getAnchorAttrName)())) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : undefined;
236
- rootNodeType = isNativeAnchorSupported ? (0, _domAttrName.getTypeNameFromDom)(rootDOM) : rootDOM.getAttribute('data-drag-handler-node-type');
252
+ var _ref4, _rootDOM$getAttribute, _rootDOM$getAttribute2;
253
+ rootAnchorName = (_ref4 = (_rootDOM$getAttribute = rootDOM.getAttribute((0, _domAttrName.getAnchorAttrName)())) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : rootDOM.getAttribute(_domAttrName.NODE_ANCHOR_ATTR_NAME)) !== null && _ref4 !== void 0 ? _ref4 : undefined;
254
+ rootNodeType = isNativeAnchorSupported ? (0, _domAttrName.getTypeNameFromDom)(rootDOM) : // Fallback: breakout mark wrappers have no data-drag-handler-node-type;
255
+ // use data-prosemirror-node-name instead.
256
+ (_rootDOM$getAttribute2 = rootDOM.getAttribute('data-drag-handler-node-type')) !== null && _rootDOM$getAttribute2 !== void 0 ? _rootDOM$getAttribute2 : (0, _domAttrName.getTypeNameFromDom)(rootDOM);
237
257
  }
238
258
  }
239
259
  }
240
- var nodeType = isNativeAnchorSupported ? (0, _domAttrName.getTypeNameFromDom)(rootElement) : rootElement.getAttribute('data-drag-handler-node-type');
260
+ var nodeType = isNativeAnchorSupported ? (0, _domAttrName.getTypeNameFromDom)(rootElement) : // Fallback for table nodes: tr has data-prosemirror-node-name but not data-drag-handler-node-type.
261
+ (_rootElement$getAttri2 = rootElement.getAttribute('data-drag-handler-node-type')) !== null && _rootElement$getAttri2 !== void 0 ? _rootElement$getAttri2 : (0, _domAttrName.getTypeNameFromDom)(rootElement);
241
262
  if (nodeType) {
242
263
  // platform_editor_controls note: enables quick insert
243
264
  if (toolbarFlagsEnabled) {
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.key = exports.getDecorations = exports.getBlockControlsMeta = exports.createPlugin = exports.apply = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _rafSchd = _interopRequireDefault(require("raf-schd"));
10
+ var _browserApis = require("@atlaskit/browser-apis");
10
11
  var _analytics = require("@atlaskit/editor-common/analytics");
11
12
  var _browser = require("@atlaskit/editor-common/browser");
12
13
  var _nodeAnchor = require("@atlaskit/editor-common/node-anchor");
@@ -56,7 +57,8 @@ var isHTMLElement = function isHTMLElement(element) {
56
57
  return element instanceof HTMLElement;
57
58
  };
58
59
  var destroyFn = function destroyFn(api, editorView) {
59
- var scrollable = document.querySelector('.fabric-editor-popup-scroll-parent');
60
+ var _getDocument$querySel, _getDocument;
61
+ var scrollable = (_getDocument$querySel = (_getDocument = (0, _browserApis.getDocument)()) === null || _getDocument === void 0 ? void 0 : _getDocument.querySelector('.fabric-editor-popup-scroll-parent')) !== null && _getDocument$querySel !== void 0 ? _getDocument$querySel : null;
60
62
  var cleanupFn = [];
61
63
  if (scrollable) {
62
64
  cleanupFn.push((0, _element.autoScrollForElements)({
@@ -275,10 +277,11 @@ var _apply = exports.apply = function apply(api, formatMessage, tr, currentState
275
277
  var meta = tr.getMeta(key);
276
278
  var hasDocumentSizeBreachedThreshold = api === null || api === void 0 || (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.limitedModePluginKey.getState(newState)) === null || _api$limitedMode === void 0 ? void 0 : _api$limitedMode.documentSizeBreachesThreshold;
277
279
  if (hasDocumentSizeBreachedThreshold) {
280
+ var _getDocument$querySel2, _getDocument2;
278
281
  /**
279
282
  * INFO: This if statement is a duplicate of the logic in destroy(). When the threshold is breached and we enter limited mode, we want to trigger the cleanup logic in destroy().
280
283
  */
281
- var editorContentArea = document.querySelector('.fabric-editor-popup-scroll-parent');
284
+ var editorContentArea = (_getDocument$querySel2 = (_getDocument2 = (0, _browserApis.getDocument)()) === null || _getDocument2 === void 0 ? void 0 : _getDocument2.querySelector('.fabric-editor-popup-scroll-parent')) !== null && _getDocument$querySel2 !== void 0 ? _getDocument$querySel2 : null;
282
285
  if (editorContentArea && resizeObserverWidth) {
283
286
  resizeObserverWidth.unobserve(editorContentArea);
284
287
  }
@@ -441,6 +444,16 @@ var _apply = exports.apply = function apply(api, formatMessage, tr, currentState
441
444
  // Remove handle dec when editor is blurred
442
445
  shouldRemoveHandle = shouldRemoveHandle || (meta === null || meta === void 0 ? void 0 : meta.editorBlurred);
443
446
  }
447
+
448
+ // In view mode with right-side controls, remove any lingering drag handle decorations
449
+ // (they may carry over from edit mode). Only remove drag handles specifically, not
450
+ // the remix button decorations (those are managed separately via showInViewMode).
451
+ if (isViewMode && rightSideControlsEnabled) {
452
+ var allHandleDecs = (0, _decorationsDragHandle.findHandleDec)(decorations, 0, newState.doc.content.size);
453
+ if (allHandleDecs.length > 0) {
454
+ decorations = decorations.remove(allHandleDecs);
455
+ }
456
+ }
444
457
  if (shouldRemoveHandle) {
445
458
  var _activeNode5, _activeNode6;
446
459
  var oldHandle = (0, _decorationsDragHandle.findHandleDec)(decorations, (_activeNode5 = activeNode) === null || _activeNode5 === void 0 ? void 0 : _activeNode5.pos, (_activeNode6 = activeNode) === null || _activeNode6 === void 0 ? void 0 : _activeNode6.pos);
@@ -808,7 +821,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl, no
808
821
  },
809
822
  props: {
810
823
  decorations: function decorations(state) {
811
- var _api$limitedMode2, _api$editorDisabled, _key$getState2;
824
+ var _api$limitedMode2, _api$editorDisabled, _key$getState2, _api$editorViewMode3;
812
825
  if (api !== null && api !== void 0 && (_api$limitedMode2 = api.limitedMode) !== null && _api$limitedMode2 !== void 0 && (_api$limitedMode2 = _api$limitedMode2.sharedState.currentState()) !== null && _api$limitedMode2 !== void 0 && _api$limitedMode2.enabled) {
813
826
  return;
814
827
  }
@@ -821,7 +834,16 @@ var createPlugin = exports.createPlugin = function createPlugin(api, getIntl, no
821
834
  return;
822
835
  }
823
836
  }
824
- return (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
837
+ var decorationSet = (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
838
+ // In view mode with right-side controls, remove any lingering drag-handle decorations
839
+ // (created in edit mode) that may not have been cleaned up on mode switch.
840
+ if (decorationSet && rightSideControlsEnabled && (api === null || api === void 0 || (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 || (_api$editorViewMode3 = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3 === void 0 ? void 0 : _api$editorViewMode3.mode) === 'view') {
841
+ var handleDecs = (0, _decorationsDragHandle.findHandleDec)(decorationSet, 0, state.doc.content.size);
842
+ if (handleDecs.length > 0) {
843
+ decorationSet = decorationSet.remove(handleDecs);
844
+ }
845
+ }
846
+ return decorationSet;
825
847
  },
826
848
  handleDOMEvents: {
827
849
  drop: function drop(view, event) {
@@ -91,6 +91,19 @@ export const handleMouseOver = (view, event, api) => {
91
91
  }
92
92
  let rootElement = target === null || target === void 0 ? void 0 : target.closest(isNativeAnchorSupported ? getDefaultNodeSelector() : `[data-drag-handler-anchor-name]`);
93
93
 
94
+ // Fallback for table nodes in view mode: the table-anchor-names plugin sets data-node-anchor on
95
+ // the first <tr> element.
96
+ // - When platform_editor_native_anchor_with_dnd is disabled, the primary closest() uses
97
+ // [data-drag-handler-anchor-name] and misses table rows. Try data-node-anchor via closest().
98
+ // - For wide/max breakout tables, hovering in the left/right margin area of the full-viewport-
99
+ // width breakout wrapper (ak-editor-breakout-mark) sets event.target to the wrapper div, which
100
+ // has no anchor attribute. Use querySelector to find the [data-node-anchor] descendant inside.
101
+ // Both cases apply only in view mode with right-side remix controls.
102
+ if (!rootElement && isViewMode && rightSideControlsEnabled) {
103
+ var _ref, _target$closest;
104
+ rootElement = (_ref = (_target$closest = target === null || target === void 0 ? void 0 : target.closest(`[${NODE_ANCHOR_ATTR_NAME}]`)) !== null && _target$closest !== void 0 ? _target$closest : target instanceof HTMLElement ? target.querySelector(`[${NODE_ANCHOR_ATTR_NAME}]`) : null) !== null && _ref !== void 0 ? _ref : null;
105
+ }
106
+
94
107
  // When hovering over the right-edge button (rendered in a portal outside the block), resolve the
95
108
  // block from the container's anchor so activeNode stays set and the button remains visible.
96
109
  if (!rootElement && rightSideControlsEnabled && fg('confluence_remix_button_right_side_block_fg')) {
@@ -103,7 +116,7 @@ export const handleMouseOver = (view, event, api) => {
103
116
  }
104
117
  }
105
118
  if (rootElement) {
106
- var _rootElement$parentEl;
119
+ var _rootElement$parentEl, _rootElement$getAttri2;
107
120
  // We want to exlude handles from showing for empty paragraph and heading nodes
108
121
  if (isEmptyNestedParagraphOrHeading(rootElement)) {
109
122
  return false;
@@ -176,6 +189,11 @@ export const handleMouseOver = (view, event, api) => {
176
189
  // Ignored via go/ees005
177
190
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
178
191
  anchorName = rootElement.getAttribute(getAnchorAttrName());
192
+ // Fallback for table nodes that only have data-node-anchor (not data-drag-handler-anchor-name).
193
+ if (!anchorName) {
194
+ var _rootElement$getAttri;
195
+ anchorName = (_rootElement$getAttri = rootElement.getAttribute(NODE_ANCHOR_ATTR_NAME)) !== null && _rootElement$getAttri !== void 0 ? _rootElement$getAttri : anchorName;
196
+ }
179
197
  }
180
198
 
181
199
  // No need to update handle position if its already there
@@ -223,13 +241,16 @@ export const handleMouseOver = (view, event, api) => {
223
241
  if (targetPos !== rootPos) {
224
242
  const rootDOM = view.nodeDOM(rootPos);
225
243
  if (rootDOM instanceof HTMLElement) {
226
- var _rootDOM$getAttribute;
227
- rootAnchorName = (_rootDOM$getAttribute = rootDOM.getAttribute(getAnchorAttrName())) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : undefined;
228
- rootNodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootDOM) : rootDOM.getAttribute('data-drag-handler-node-type');
244
+ var _ref2, _rootDOM$getAttribute, _rootDOM$getAttribute2;
245
+ rootAnchorName = (_ref2 = (_rootDOM$getAttribute = rootDOM.getAttribute(getAnchorAttrName())) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : rootDOM.getAttribute(NODE_ANCHOR_ATTR_NAME)) !== null && _ref2 !== void 0 ? _ref2 : undefined;
246
+ rootNodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootDOM) : // Fallback: breakout mark wrappers have no data-drag-handler-node-type;
247
+ // use data-prosemirror-node-name instead.
248
+ (_rootDOM$getAttribute2 = rootDOM.getAttribute('data-drag-handler-node-type')) !== null && _rootDOM$getAttribute2 !== void 0 ? _rootDOM$getAttribute2 : getTypeNameFromDom(rootDOM);
229
249
  }
230
250
  }
231
251
  }
232
- const nodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootElement) : rootElement.getAttribute('data-drag-handler-node-type');
252
+ const nodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootElement) : // Fallback for table nodes: tr has data-prosemirror-node-name but not data-drag-handler-node-type.
253
+ (_rootElement$getAttri2 = rootElement.getAttribute('data-drag-handler-node-type')) !== null && _rootElement$getAttri2 !== void 0 ? _rootElement$getAttri2 : getTypeNameFromDom(rootElement);
233
254
  if (nodeType) {
234
255
  // platform_editor_controls note: enables quick insert
235
256
  if (toolbarFlagsEnabled) {
@@ -1,4 +1,5 @@
1
1
  import rafSchedule from 'raf-schd';
2
+ import { getDocument } from '@atlaskit/browser-apis';
2
3
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
3
4
  import { getBrowserInfo } from '@atlaskit/editor-common/browser';
4
5
  import { getNodeIdProvider } from '@atlaskit/editor-common/node-anchor';
@@ -44,7 +45,8 @@ const isHTMLElement = element => {
44
45
  return element instanceof HTMLElement;
45
46
  };
46
47
  const destroyFn = (api, editorView) => {
47
- const scrollable = document.querySelector('.fabric-editor-popup-scroll-parent');
48
+ var _getDocument$querySel, _getDocument;
49
+ const scrollable = (_getDocument$querySel = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.querySelector('.fabric-editor-popup-scroll-parent')) !== null && _getDocument$querySel !== void 0 ? _getDocument$querySel : null;
48
50
  const cleanupFn = [];
49
51
  if (scrollable) {
50
52
  cleanupFn.push(autoScrollForElements({
@@ -266,10 +268,11 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
266
268
  const meta = tr.getMeta(key);
267
269
  const hasDocumentSizeBreachedThreshold = api === null || api === void 0 ? void 0 : (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 ? void 0 : (_api$limitedMode$shar = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode$shar === void 0 ? void 0 : (_api$limitedMode$shar2 = _api$limitedMode$shar.limitedModePluginKey.getState(newState)) === null || _api$limitedMode$shar2 === void 0 ? void 0 : _api$limitedMode$shar2.documentSizeBreachesThreshold;
268
270
  if (hasDocumentSizeBreachedThreshold) {
271
+ var _getDocument$querySel2, _getDocument2;
269
272
  /**
270
273
  * INFO: This if statement is a duplicate of the logic in destroy(). When the threshold is breached and we enter limited mode, we want to trigger the cleanup logic in destroy().
271
274
  */
272
- const editorContentArea = document.querySelector('.fabric-editor-popup-scroll-parent');
275
+ const editorContentArea = (_getDocument$querySel2 = (_getDocument2 = getDocument()) === null || _getDocument2 === void 0 ? void 0 : _getDocument2.querySelector('.fabric-editor-popup-scroll-parent')) !== null && _getDocument$querySel2 !== void 0 ? _getDocument$querySel2 : null;
273
276
  if (editorContentArea && resizeObserverWidth) {
274
277
  resizeObserverWidth.unobserve(editorContentArea);
275
278
  }
@@ -430,6 +433,16 @@ export const apply = (api, formatMessage, tr, currentState, newState, flags, nod
430
433
  // Remove handle dec when editor is blurred
431
434
  shouldRemoveHandle = shouldRemoveHandle || (meta === null || meta === void 0 ? void 0 : meta.editorBlurred);
432
435
  }
436
+
437
+ // In view mode with right-side controls, remove any lingering drag handle decorations
438
+ // (they may carry over from edit mode). Only remove drag handles specifically, not
439
+ // the remix button decorations (those are managed separately via showInViewMode).
440
+ if (isViewMode && rightSideControlsEnabled) {
441
+ const allHandleDecs = findHandleDec(decorations, 0, newState.doc.content.size);
442
+ if (allHandleDecs.length > 0) {
443
+ decorations = decorations.remove(allHandleDecs);
444
+ }
445
+ }
433
446
  if (shouldRemoveHandle) {
434
447
  var _activeNode5, _activeNode6;
435
448
  const oldHandle = findHandleDec(decorations, (_activeNode5 = activeNode) === null || _activeNode5 === void 0 ? void 0 : _activeNode5.pos, (_activeNode6 = activeNode) === null || _activeNode6 === void 0 ? void 0 : _activeNode6.pos);
@@ -705,7 +718,7 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
705
718
  },
706
719
  props: {
707
720
  decorations: state => {
708
- var _api$limitedMode2, _api$limitedMode2$sha, _api$editorDisabled, _api$editorDisabled$s, _key$getState2;
721
+ var _api$limitedMode2, _api$limitedMode2$sha, _api$editorDisabled, _api$editorDisabled$s, _key$getState2, _api$editorViewMode3, _api$editorViewMode3$;
709
722
  if (api !== null && api !== void 0 && (_api$limitedMode2 = api.limitedMode) !== null && _api$limitedMode2 !== void 0 && (_api$limitedMode2$sha = _api$limitedMode2.sharedState.currentState()) !== null && _api$limitedMode2$sha !== void 0 && _api$limitedMode2$sha.enabled) {
710
723
  return;
711
724
  }
@@ -718,7 +731,16 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI, nodeDecora
718
731
  return;
719
732
  }
720
733
  }
721
- return (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
734
+ let decorationSet = (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
735
+ // In view mode with right-side controls, remove any lingering drag-handle decorations
736
+ // (created in edit mode) that may not have been cleaned up on mode switch.
737
+ if (decorationSet && rightSideControlsEnabled && (api === null || api === void 0 ? void 0 : (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 ? void 0 : (_api$editorViewMode3$ = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3$ === void 0 ? void 0 : _api$editorViewMode3$.mode) === 'view') {
738
+ const handleDecs = findHandleDec(decorationSet, 0, state.doc.content.size);
739
+ if (handleDecs.length > 0) {
740
+ decorationSet = decorationSet.remove(handleDecs);
741
+ }
742
+ }
743
+ return decorationSet;
722
744
  },
723
745
  handleDOMEvents: {
724
746
  drop(view, event) {
@@ -92,6 +92,19 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
92
92
  }
93
93
  var rootElement = target === null || target === void 0 ? void 0 : target.closest(isNativeAnchorSupported ? getDefaultNodeSelector() : "[data-drag-handler-anchor-name]");
94
94
 
95
+ // Fallback for table nodes in view mode: the table-anchor-names plugin sets data-node-anchor on
96
+ // the first <tr> element.
97
+ // - When platform_editor_native_anchor_with_dnd is disabled, the primary closest() uses
98
+ // [data-drag-handler-anchor-name] and misses table rows. Try data-node-anchor via closest().
99
+ // - For wide/max breakout tables, hovering in the left/right margin area of the full-viewport-
100
+ // width breakout wrapper (ak-editor-breakout-mark) sets event.target to the wrapper div, which
101
+ // has no anchor attribute. Use querySelector to find the [data-node-anchor] descendant inside.
102
+ // Both cases apply only in view mode with right-side remix controls.
103
+ if (!rootElement && isViewMode && rightSideControlsEnabled) {
104
+ var _ref3, _target$closest;
105
+ rootElement = (_ref3 = (_target$closest = target === null || target === void 0 ? void 0 : target.closest("[".concat(NODE_ANCHOR_ATTR_NAME, "]"))) !== null && _target$closest !== void 0 ? _target$closest : target instanceof HTMLElement ? target.querySelector("[".concat(NODE_ANCHOR_ATTR_NAME, "]")) : null) !== null && _ref3 !== void 0 ? _ref3 : null;
106
+ }
107
+
95
108
  // When hovering over the right-edge button (rendered in a portal outside the block), resolve the
96
109
  // block from the container's anchor so activeNode stays set and the button remains visible.
97
110
  if (!rootElement && rightSideControlsEnabled && fg('confluence_remix_button_right_side_block_fg')) {
@@ -104,7 +117,7 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
104
117
  }
105
118
  }
106
119
  if (rootElement) {
107
- var _rootElement$parentEl;
120
+ var _rootElement$parentEl, _rootElement$getAttri2;
108
121
  // We want to exlude handles from showing for empty paragraph and heading nodes
109
122
  if (isEmptyNestedParagraphOrHeading(rootElement)) {
110
123
  return false;
@@ -177,6 +190,11 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
177
190
  // Ignored via go/ees005
178
191
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
179
192
  anchorName = rootElement.getAttribute(getAnchorAttrName());
193
+ // Fallback for table nodes that only have data-node-anchor (not data-drag-handler-anchor-name).
194
+ if (!anchorName) {
195
+ var _rootElement$getAttri;
196
+ anchorName = (_rootElement$getAttri = rootElement.getAttribute(NODE_ANCHOR_ATTR_NAME)) !== null && _rootElement$getAttri !== void 0 ? _rootElement$getAttri : anchorName;
197
+ }
180
198
  }
181
199
 
182
200
  // No need to update handle position if its already there
@@ -224,13 +242,16 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
224
242
  if (targetPos !== rootPos) {
225
243
  var rootDOM = view.nodeDOM(rootPos);
226
244
  if (rootDOM instanceof HTMLElement) {
227
- var _rootDOM$getAttribute;
228
- rootAnchorName = (_rootDOM$getAttribute = rootDOM.getAttribute(getAnchorAttrName())) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : undefined;
229
- rootNodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootDOM) : rootDOM.getAttribute('data-drag-handler-node-type');
245
+ var _ref4, _rootDOM$getAttribute, _rootDOM$getAttribute2;
246
+ rootAnchorName = (_ref4 = (_rootDOM$getAttribute = rootDOM.getAttribute(getAnchorAttrName())) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : rootDOM.getAttribute(NODE_ANCHOR_ATTR_NAME)) !== null && _ref4 !== void 0 ? _ref4 : undefined;
247
+ rootNodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootDOM) : // Fallback: breakout mark wrappers have no data-drag-handler-node-type;
248
+ // use data-prosemirror-node-name instead.
249
+ (_rootDOM$getAttribute2 = rootDOM.getAttribute('data-drag-handler-node-type')) !== null && _rootDOM$getAttribute2 !== void 0 ? _rootDOM$getAttribute2 : getTypeNameFromDom(rootDOM);
230
250
  }
231
251
  }
232
252
  }
233
- var nodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootElement) : rootElement.getAttribute('data-drag-handler-node-type');
253
+ var nodeType = isNativeAnchorSupported ? getTypeNameFromDom(rootElement) : // Fallback for table nodes: tr has data-prosemirror-node-name but not data-drag-handler-node-type.
254
+ (_rootElement$getAttri2 = rootElement.getAttribute('data-drag-handler-node-type')) !== null && _rootElement$getAttri2 !== void 0 ? _rootElement$getAttri2 : getTypeNameFromDom(rootElement);
234
255
  if (nodeType) {
235
256
  // platform_editor_controls note: enables quick insert
236
257
  if (toolbarFlagsEnabled) {
@@ -5,6 +5,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
5
5
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
6
6
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
7
7
  import rafSchedule from 'raf-schd';
8
+ import { getDocument } from '@atlaskit/browser-apis';
8
9
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
9
10
  import { getBrowserInfo } from '@atlaskit/editor-common/browser';
10
11
  import { getNodeIdProvider } from '@atlaskit/editor-common/node-anchor';
@@ -49,7 +50,8 @@ var isHTMLElement = function isHTMLElement(element) {
49
50
  return element instanceof HTMLElement;
50
51
  };
51
52
  var destroyFn = function destroyFn(api, editorView) {
52
- var scrollable = document.querySelector('.fabric-editor-popup-scroll-parent');
53
+ var _getDocument$querySel, _getDocument;
54
+ var scrollable = (_getDocument$querySel = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.querySelector('.fabric-editor-popup-scroll-parent')) !== null && _getDocument$querySel !== void 0 ? _getDocument$querySel : null;
53
55
  var cleanupFn = [];
54
56
  if (scrollable) {
55
57
  cleanupFn.push(autoScrollForElements({
@@ -268,10 +270,11 @@ var _apply = function apply(api, formatMessage, tr, currentState, newState, flag
268
270
  var meta = tr.getMeta(key);
269
271
  var hasDocumentSizeBreachedThreshold = api === null || api === void 0 || (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.limitedModePluginKey.getState(newState)) === null || _api$limitedMode === void 0 ? void 0 : _api$limitedMode.documentSizeBreachesThreshold;
270
272
  if (hasDocumentSizeBreachedThreshold) {
273
+ var _getDocument$querySel2, _getDocument2;
271
274
  /**
272
275
  * INFO: This if statement is a duplicate of the logic in destroy(). When the threshold is breached and we enter limited mode, we want to trigger the cleanup logic in destroy().
273
276
  */
274
- var editorContentArea = document.querySelector('.fabric-editor-popup-scroll-parent');
277
+ var editorContentArea = (_getDocument$querySel2 = (_getDocument2 = getDocument()) === null || _getDocument2 === void 0 ? void 0 : _getDocument2.querySelector('.fabric-editor-popup-scroll-parent')) !== null && _getDocument$querySel2 !== void 0 ? _getDocument$querySel2 : null;
275
278
  if (editorContentArea && resizeObserverWidth) {
276
279
  resizeObserverWidth.unobserve(editorContentArea);
277
280
  }
@@ -434,6 +437,16 @@ var _apply = function apply(api, formatMessage, tr, currentState, newState, flag
434
437
  // Remove handle dec when editor is blurred
435
438
  shouldRemoveHandle = shouldRemoveHandle || (meta === null || meta === void 0 ? void 0 : meta.editorBlurred);
436
439
  }
440
+
441
+ // In view mode with right-side controls, remove any lingering drag handle decorations
442
+ // (they may carry over from edit mode). Only remove drag handles specifically, not
443
+ // the remix button decorations (those are managed separately via showInViewMode).
444
+ if (isViewMode && rightSideControlsEnabled) {
445
+ var allHandleDecs = findHandleDec(decorations, 0, newState.doc.content.size);
446
+ if (allHandleDecs.length > 0) {
447
+ decorations = decorations.remove(allHandleDecs);
448
+ }
449
+ }
437
450
  if (shouldRemoveHandle) {
438
451
  var _activeNode5, _activeNode6;
439
452
  var oldHandle = findHandleDec(decorations, (_activeNode5 = activeNode) === null || _activeNode5 === void 0 ? void 0 : _activeNode5.pos, (_activeNode6 = activeNode) === null || _activeNode6 === void 0 ? void 0 : _activeNode6.pos);
@@ -802,7 +815,7 @@ export var createPlugin = function createPlugin(api, getIntl, nodeViewPortalProv
802
815
  },
803
816
  props: {
804
817
  decorations: function decorations(state) {
805
- var _api$limitedMode2, _api$editorDisabled, _key$getState2;
818
+ var _api$limitedMode2, _api$editorDisabled, _key$getState2, _api$editorViewMode3;
806
819
  if (api !== null && api !== void 0 && (_api$limitedMode2 = api.limitedMode) !== null && _api$limitedMode2 !== void 0 && (_api$limitedMode2 = _api$limitedMode2.sharedState.currentState()) !== null && _api$limitedMode2 !== void 0 && _api$limitedMode2.enabled) {
807
820
  return;
808
821
  }
@@ -815,7 +828,16 @@ export var createPlugin = function createPlugin(api, getIntl, nodeViewPortalProv
815
828
  return;
816
829
  }
817
830
  }
818
- return (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
831
+ var decorationSet = (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
832
+ // In view mode with right-side controls, remove any lingering drag-handle decorations
833
+ // (created in edit mode) that may not have been cleaned up on mode switch.
834
+ if (decorationSet && rightSideControlsEnabled && (api === null || api === void 0 || (_api$editorViewMode3 = api.editorViewMode) === null || _api$editorViewMode3 === void 0 || (_api$editorViewMode3 = _api$editorViewMode3.sharedState.currentState()) === null || _api$editorViewMode3 === void 0 ? void 0 : _api$editorViewMode3.mode) === 'view') {
835
+ var handleDecs = findHandleDec(decorationSet, 0, state.doc.content.size);
836
+ if (handleDecs.length > 0) {
837
+ decorationSet = decorationSet.remove(handleDecs);
838
+ }
839
+ }
840
+ return decorationSet;
819
841
  },
820
842
  handleDOMEvents: {
821
843
  drop: function drop(view, event) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "11.2.0",
3
+ "version": "11.2.2",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -30,15 +30,15 @@
30
30
  "dependencies": {
31
31
  "@atlaskit/browser-apis": "^0.0.1",
32
32
  "@atlaskit/button": "^23.11.0",
33
- "@atlaskit/editor-plugin-accessibility-utils": "^10.0.0",
33
+ "@atlaskit/editor-plugin-accessibility-utils": "^10.1.0",
34
34
  "@atlaskit/editor-plugin-analytics": "^10.0.0",
35
35
  "@atlaskit/editor-plugin-editor-disabled": "^10.0.0",
36
36
  "@atlaskit/editor-plugin-editor-viewmode": "^12.0.0",
37
37
  "@atlaskit/editor-plugin-feature-flags": "^9.0.0",
38
38
  "@atlaskit/editor-plugin-interaction": "^19.0.0",
39
- "@atlaskit/editor-plugin-limited-mode": "^7.0.0",
39
+ "@atlaskit/editor-plugin-limited-mode": "^7.1.0",
40
40
  "@atlaskit/editor-plugin-metrics": "^11.0.0",
41
- "@atlaskit/editor-plugin-quick-insert": "^10.0.0",
41
+ "@atlaskit/editor-plugin-quick-insert": "^10.1.0",
42
42
  "@atlaskit/editor-plugin-selection": "^10.0.0",
43
43
  "@atlaskit/editor-plugin-toolbar": "^7.0.0",
44
44
  "@atlaskit/editor-plugin-type-ahead": "^10.0.0",
@@ -47,8 +47,8 @@
47
47
  "@atlaskit/editor-prosemirror": "^7.3.0",
48
48
  "@atlaskit/editor-shared-styles": "^3.10.0",
49
49
  "@atlaskit/editor-tables": "^2.9.0",
50
- "@atlaskit/icon": "^34.2.0",
51
- "@atlaskit/icon-lab": "^6.5.0",
50
+ "@atlaskit/icon": "^34.3.0",
51
+ "@atlaskit/icon-lab": "^6.6.0",
52
52
  "@atlaskit/link": "^3.4.0",
53
53
  "@atlaskit/platform-feature-flags": "^1.1.0",
54
54
  "@atlaskit/pragmatic-drag-and-drop": "^1.8.0",
@@ -56,7 +56,7 @@
56
56
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^3.2.0",
57
57
  "@atlaskit/primitives": "^19.0.0",
58
58
  "@atlaskit/theme": "^23.1.0",
59
- "@atlaskit/tmp-editor-statsig": "^64.1.0",
59
+ "@atlaskit/tmp-editor-statsig": "^66.0.0",
60
60
  "@atlaskit/tokens": "^13.0.0",
61
61
  "@atlaskit/tooltip": "^21.1.0",
62
62
  "@babel/runtime": "^7.0.0",
@@ -67,7 +67,7 @@
67
67
  "uuid": "^3.1.0"
68
68
  },
69
69
  "peerDependencies": {
70
- "@atlaskit/editor-common": "^114.6.0",
70
+ "@atlaskit/editor-common": "^114.7.0",
71
71
  "react": "^18.2.0",
72
72
  "react-dom": "^18.2.0",
73
73
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"