@atlaskit/editor-plugin-paste-options-toolbar 9.1.5 → 9.1.6

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,14 @@
1
1
  # @atlaskit/editor-plugin-paste-options-toolbar
2
2
 
3
+ ## 9.1.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [`fc5915138b437`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fc5915138b437) -
8
+ EDITOR-6110 Ensure that paste actions menu appears in the correct position when the first item of
9
+ the paste is an inline node or mark
10
+ - Updated dependencies
11
+
3
12
  ## 9.1.5
4
13
 
5
14
  ### Patch Changes
@@ -157,7 +157,7 @@ function getMarkdownSlice(text, schema, selection) {
157
157
  for (var i = 0; i < textSplitByCodeBlock.length; i++) {
158
158
  if (i % 2 === 0) {
159
159
  // Ignored via go/ees005
160
- // eslint-disable-next-line require-unicode-regexp
160
+ // eslint-disable-next-line require-unicode-regexp, @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
161
161
  textSplitByCodeBlock[i] = textSplitByCodeBlock[i].replace(/\\/g, '\\\\');
162
162
  }
163
163
  }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.PasteActionsMenu = void 0;
9
+ exports.findBlockAncestorDOM = findBlockAncestorDOM;
9
10
  exports.getTargetElement = getTargetElement;
10
11
  exports.getVisualEndBottom = getVisualEndBottom;
11
12
  exports.onPositionCalculated = onPositionCalculated;
@@ -82,10 +83,47 @@ function getVisualEndBottom(editorView, pasteEndPos, tableAfterPos) {
82
83
  }
83
84
 
84
85
  /**
85
- * Adjusts the vertical position of the paste menu to align with the top of the
86
- * pasted content using the exact coordinates at the paste start position,
87
- * and sticks the menu to the top of the scroll container when the pasted
88
- * content scrolls above the visible area.
86
+ * Finds the DOM element for the nearest block-level ProseMirror ancestor of
87
+ * the given document position. Uses ProseMirror's schema (`node.isBlock`)
88
+ * rather than CSS display properties, so the check is always in sync with the
89
+ * document model.
90
+ *
91
+ * Returns `null` if no block ancestor can be resolved to a DOM element.
92
+ */
93
+ function findBlockAncestorDOM(editorView, pos) {
94
+ try {
95
+ var $pos = editorView.state.doc.resolve(pos);
96
+ // Walk up the document tree from the resolved position's innermost
97
+ // node towards the root. $pos.node(depth) gives the ancestor at each
98
+ // depth; $pos.start(depth) gives the position just inside that ancestor,
99
+ // so `$pos.start(depth) - 1` is the position of the ancestor node itself
100
+ // (which is what nodeDOM expects).
101
+ for (var depth = $pos.depth; depth >= 0; depth--) {
102
+ var node = $pos.node(depth);
103
+ if (node.isBlock) {
104
+ var domNode = editorView.nodeDOM($pos.start(depth) - 1);
105
+ if (domNode instanceof HTMLElement) {
106
+ return domNode;
107
+ }
108
+ // depth 0 is the doc node — nodeDOM(–1) won't work, so try
109
+ // the editor's own DOM element as a fallback.
110
+ if (depth === 0 && editorView.dom instanceof HTMLElement) {
111
+ return editorView.dom;
112
+ }
113
+ }
114
+ }
115
+ } catch (_unused2) {
116
+ // Position may be out of range after a concurrent edit — fall through.
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Adjusts the position of the paste menu so that:
123
+ *
124
+ * **Vertical:** The menu aligns with the top of the pasted content using the
125
+ * exact coordinates at the paste start position, and sticks to the top of the
126
+ * scroll container when the pasted content scrolls above the visible area.
89
127
  *
90
128
  * The Popup uses alignY="bottom", which positions the popup below the target
91
129
  * element's bottom edge. This override:
@@ -96,16 +134,26 @@ function getVisualEndBottom(editorView, pasteEndPos, tableAfterPos) {
96
134
  * to the scroll container's top edge (sticky-top).
97
135
  * 3. Stops sticking once the entire pasted range (pasteEndPos) has scrolled
98
136
  * above the visible area.
137
+ *
138
+ * **Horizontal:** When the target element is an inline element (e.g. a mark
139
+ * wrapper like `<strong>`, or an inline node like an emoji), the Popup's
140
+ * `alignX="end"` would place the menu at the right edge of that narrow
141
+ * element. This override resolves the nearest block-level ProseMirror
142
+ * ancestor (using `node.isBlock` from the document schema) and re-anchors
143
+ * the horizontal position to its right edge, so the menu consistently
144
+ * appears at the right side of the content area.
99
145
  */
100
146
  function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElement, scrollableElement) {
101
147
  // Pre-compute once per render to avoid doc.resolve() on every scroll frame.
102
148
  var tableAfterPos = resolveTableAfterPos(editorView, pasteEndPos);
149
+ var blockAncestorDOM = findBlockAncestorDOM(editorView, pasteStartPos);
103
150
  return function (position) {
104
151
  var _position$top;
105
152
  var startCoords = editorView.coordsAtPos(pasteStartPos);
106
153
  var endBottom = getVisualEndBottom(editorView, pasteEndPos, tableAfterPos);
107
154
  var targetRect = targetElement.getBoundingClientRect();
108
155
 
156
+ // ── Vertical adjustment ──────────────────────────────────────────
109
157
  // The Popup places the menu at the target's bottom edge by default.
110
158
  // We shift it up so it aligns with the paste start position.
111
159
  // Both coordinates are in viewport space, so the delta is offset-parent agnostic.
@@ -121,8 +169,28 @@ function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElem
121
169
  adjustedTop += scrollContainerTop - startCoords.top + _constants.PASTE_MENU_GAP_TOP;
122
170
  }
123
171
  }
172
+
173
+ // ── Horizontal adjustment ────────────────────────────────────────
174
+ // When pasted content starts with a mark (bold, italic, link …) or
175
+ // an inline node (emoji, smart link, inline image …),
176
+ // findDomRefAtPos returns the narrow inline wrapper element. The
177
+ // Popup's alignX="end" then places the menu at that element's right
178
+ // edge instead of the content area's right edge. We correct this by
179
+ // resolving the nearest block-level ProseMirror ancestor and
180
+ // re-anchoring to its right edge.
181
+ var adjustedLeft = position.left;
182
+ if (blockAncestorDOM && blockAncestorDOM !== targetElement) {
183
+ var _position$left;
184
+ var blockRect = blockAncestorDOM.getBoundingClientRect();
185
+ // Shift left by the difference between the block's right edge and
186
+ // the inline target's right edge. This mirrors what alignX="end"
187
+ // would have computed if the target were the block element.
188
+ var leftDelta = blockRect.right - targetRect.right;
189
+ adjustedLeft = ((_position$left = position.left) !== null && _position$left !== void 0 ? _position$left : 0) + leftDelta;
190
+ }
124
191
  return _objectSpread(_objectSpread({}, position), {}, {
125
- top: adjustedTop
192
+ top: adjustedTop,
193
+ left: adjustedLeft
126
194
  });
127
195
  };
128
196
  }
@@ -248,7 +316,8 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
248
316
  minPopupMargin: _constants.PASTE_MENU_GAP_HORIZONTAL,
249
317
  zIndex: _editorSharedStyles.akEditorFloatingPanelZIndex,
250
318
  alignX: "end",
251
- alignY: "bottom",
319
+ alignY: "bottom"
320
+ /* eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) */,
252
321
  offset: [_constants.PASTE_MENU_GAP_HORIZONTAL, 0],
253
322
  onPositionCalculated: onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement),
254
323
  handleClickOutside: handleClickOutside,
@@ -152,7 +152,7 @@ export function getMarkdownSlice(text, schema, selection) {
152
152
  for (let i = 0; i < textSplitByCodeBlock.length; i++) {
153
153
  if (i % 2 === 0) {
154
154
  // Ignored via go/ees005
155
- // eslint-disable-next-line require-unicode-regexp
155
+ // eslint-disable-next-line require-unicode-regexp, @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
156
156
  textSplitByCodeBlock[i] = textSplitByCodeBlock[i].replace(/\\/g, '\\\\');
157
157
  }
158
158
  }
@@ -66,10 +66,47 @@ export function getVisualEndBottom(editorView, pasteEndPos, tableAfterPos) {
66
66
  }
67
67
 
68
68
  /**
69
- * Adjusts the vertical position of the paste menu to align with the top of the
70
- * pasted content using the exact coordinates at the paste start position,
71
- * and sticks the menu to the top of the scroll container when the pasted
72
- * content scrolls above the visible area.
69
+ * Finds the DOM element for the nearest block-level ProseMirror ancestor of
70
+ * the given document position. Uses ProseMirror's schema (`node.isBlock`)
71
+ * rather than CSS display properties, so the check is always in sync with the
72
+ * document model.
73
+ *
74
+ * Returns `null` if no block ancestor can be resolved to a DOM element.
75
+ */
76
+ export function findBlockAncestorDOM(editorView, pos) {
77
+ try {
78
+ const $pos = editorView.state.doc.resolve(pos);
79
+ // Walk up the document tree from the resolved position's innermost
80
+ // node towards the root. $pos.node(depth) gives the ancestor at each
81
+ // depth; $pos.start(depth) gives the position just inside that ancestor,
82
+ // so `$pos.start(depth) - 1` is the position of the ancestor node itself
83
+ // (which is what nodeDOM expects).
84
+ for (let depth = $pos.depth; depth >= 0; depth--) {
85
+ const node = $pos.node(depth);
86
+ if (node.isBlock) {
87
+ const domNode = editorView.nodeDOM($pos.start(depth) - 1);
88
+ if (domNode instanceof HTMLElement) {
89
+ return domNode;
90
+ }
91
+ // depth 0 is the doc node — nodeDOM(–1) won't work, so try
92
+ // the editor's own DOM element as a fallback.
93
+ if (depth === 0 && editorView.dom instanceof HTMLElement) {
94
+ return editorView.dom;
95
+ }
96
+ }
97
+ }
98
+ } catch {
99
+ // Position may be out of range after a concurrent edit — fall through.
100
+ }
101
+ return null;
102
+ }
103
+
104
+ /**
105
+ * Adjusts the position of the paste menu so that:
106
+ *
107
+ * **Vertical:** The menu aligns with the top of the pasted content using the
108
+ * exact coordinates at the paste start position, and sticks to the top of the
109
+ * scroll container when the pasted content scrolls above the visible area.
73
110
  *
74
111
  * The Popup uses alignY="bottom", which positions the popup below the target
75
112
  * element's bottom edge. This override:
@@ -80,16 +117,26 @@ export function getVisualEndBottom(editorView, pasteEndPos, tableAfterPos) {
80
117
  * to the scroll container's top edge (sticky-top).
81
118
  * 3. Stops sticking once the entire pasted range (pasteEndPos) has scrolled
82
119
  * above the visible area.
120
+ *
121
+ * **Horizontal:** When the target element is an inline element (e.g. a mark
122
+ * wrapper like `<strong>`, or an inline node like an emoji), the Popup's
123
+ * `alignX="end"` would place the menu at the right edge of that narrow
124
+ * element. This override resolves the nearest block-level ProseMirror
125
+ * ancestor (using `node.isBlock` from the document schema) and re-anchors
126
+ * the horizontal position to its right edge, so the menu consistently
127
+ * appears at the right side of the content area.
83
128
  */
84
129
  export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElement, scrollableElement) {
85
130
  // Pre-compute once per render to avoid doc.resolve() on every scroll frame.
86
131
  const tableAfterPos = resolveTableAfterPos(editorView, pasteEndPos);
132
+ const blockAncestorDOM = findBlockAncestorDOM(editorView, pasteStartPos);
87
133
  return position => {
88
134
  var _position$top;
89
135
  const startCoords = editorView.coordsAtPos(pasteStartPos);
90
136
  const endBottom = getVisualEndBottom(editorView, pasteEndPos, tableAfterPos);
91
137
  const targetRect = targetElement.getBoundingClientRect();
92
138
 
139
+ // ── Vertical adjustment ──────────────────────────────────────────
93
140
  // The Popup places the menu at the target's bottom edge by default.
94
141
  // We shift it up so it aligns with the paste start position.
95
142
  // Both coordinates are in viewport space, so the delta is offset-parent agnostic.
@@ -105,9 +152,29 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
105
152
  adjustedTop += scrollContainerTop - startCoords.top + PASTE_MENU_GAP_TOP;
106
153
  }
107
154
  }
155
+
156
+ // ── Horizontal adjustment ────────────────────────────────────────
157
+ // When pasted content starts with a mark (bold, italic, link …) or
158
+ // an inline node (emoji, smart link, inline image …),
159
+ // findDomRefAtPos returns the narrow inline wrapper element. The
160
+ // Popup's alignX="end" then places the menu at that element's right
161
+ // edge instead of the content area's right edge. We correct this by
162
+ // resolving the nearest block-level ProseMirror ancestor and
163
+ // re-anchoring to its right edge.
164
+ let adjustedLeft = position.left;
165
+ if (blockAncestorDOM && blockAncestorDOM !== targetElement) {
166
+ var _position$left;
167
+ const blockRect = blockAncestorDOM.getBoundingClientRect();
168
+ // Shift left by the difference between the block's right edge and
169
+ // the inline target's right edge. This mirrors what alignX="end"
170
+ // would have computed if the target were the block element.
171
+ const leftDelta = blockRect.right - targetRect.right;
172
+ adjustedLeft = ((_position$left = position.left) !== null && _position$left !== void 0 ? _position$left : 0) + leftDelta;
173
+ }
108
174
  return {
109
175
  ...position,
110
- top: adjustedTop
176
+ top: adjustedTop,
177
+ left: adjustedLeft
111
178
  };
112
179
  };
113
180
  }
@@ -236,7 +303,8 @@ export const PasteActionsMenu = ({
236
303
  minPopupMargin: PASTE_MENU_GAP_HORIZONTAL,
237
304
  zIndex: akEditorFloatingPanelZIndex,
238
305
  alignX: "end",
239
- alignY: "bottom",
306
+ alignY: "bottom"
307
+ /* eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) */,
240
308
  offset: [PASTE_MENU_GAP_HORIZONTAL, 0],
241
309
  onPositionCalculated: onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement),
242
310
  handleClickOutside: handleClickOutside,
@@ -150,7 +150,7 @@ export function getMarkdownSlice(text, schema, selection) {
150
150
  for (var i = 0; i < textSplitByCodeBlock.length; i++) {
151
151
  if (i % 2 === 0) {
152
152
  // Ignored via go/ees005
153
- // eslint-disable-next-line require-unicode-regexp
153
+ // eslint-disable-next-line require-unicode-regexp, @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
154
154
  textSplitByCodeBlock[i] = textSplitByCodeBlock[i].replace(/\\/g, '\\\\');
155
155
  }
156
156
  }
@@ -69,10 +69,47 @@ export function getVisualEndBottom(editorView, pasteEndPos, tableAfterPos) {
69
69
  }
70
70
 
71
71
  /**
72
- * Adjusts the vertical position of the paste menu to align with the top of the
73
- * pasted content using the exact coordinates at the paste start position,
74
- * and sticks the menu to the top of the scroll container when the pasted
75
- * content scrolls above the visible area.
72
+ * Finds the DOM element for the nearest block-level ProseMirror ancestor of
73
+ * the given document position. Uses ProseMirror's schema (`node.isBlock`)
74
+ * rather than CSS display properties, so the check is always in sync with the
75
+ * document model.
76
+ *
77
+ * Returns `null` if no block ancestor can be resolved to a DOM element.
78
+ */
79
+ export function findBlockAncestorDOM(editorView, pos) {
80
+ try {
81
+ var $pos = editorView.state.doc.resolve(pos);
82
+ // Walk up the document tree from the resolved position's innermost
83
+ // node towards the root. $pos.node(depth) gives the ancestor at each
84
+ // depth; $pos.start(depth) gives the position just inside that ancestor,
85
+ // so `$pos.start(depth) - 1` is the position of the ancestor node itself
86
+ // (which is what nodeDOM expects).
87
+ for (var depth = $pos.depth; depth >= 0; depth--) {
88
+ var node = $pos.node(depth);
89
+ if (node.isBlock) {
90
+ var domNode = editorView.nodeDOM($pos.start(depth) - 1);
91
+ if (domNode instanceof HTMLElement) {
92
+ return domNode;
93
+ }
94
+ // depth 0 is the doc node — nodeDOM(–1) won't work, so try
95
+ // the editor's own DOM element as a fallback.
96
+ if (depth === 0 && editorView.dom instanceof HTMLElement) {
97
+ return editorView.dom;
98
+ }
99
+ }
100
+ }
101
+ } catch (_unused2) {
102
+ // Position may be out of range after a concurrent edit — fall through.
103
+ }
104
+ return null;
105
+ }
106
+
107
+ /**
108
+ * Adjusts the position of the paste menu so that:
109
+ *
110
+ * **Vertical:** The menu aligns with the top of the pasted content using the
111
+ * exact coordinates at the paste start position, and sticks to the top of the
112
+ * scroll container when the pasted content scrolls above the visible area.
76
113
  *
77
114
  * The Popup uses alignY="bottom", which positions the popup below the target
78
115
  * element's bottom edge. This override:
@@ -83,16 +120,26 @@ export function getVisualEndBottom(editorView, pasteEndPos, tableAfterPos) {
83
120
  * to the scroll container's top edge (sticky-top).
84
121
  * 3. Stops sticking once the entire pasted range (pasteEndPos) has scrolled
85
122
  * above the visible area.
123
+ *
124
+ * **Horizontal:** When the target element is an inline element (e.g. a mark
125
+ * wrapper like `<strong>`, or an inline node like an emoji), the Popup's
126
+ * `alignX="end"` would place the menu at the right edge of that narrow
127
+ * element. This override resolves the nearest block-level ProseMirror
128
+ * ancestor (using `node.isBlock` from the document schema) and re-anchors
129
+ * the horizontal position to its right edge, so the menu consistently
130
+ * appears at the right side of the content area.
86
131
  */
87
132
  export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElement, scrollableElement) {
88
133
  // Pre-compute once per render to avoid doc.resolve() on every scroll frame.
89
134
  var tableAfterPos = resolveTableAfterPos(editorView, pasteEndPos);
135
+ var blockAncestorDOM = findBlockAncestorDOM(editorView, pasteStartPos);
90
136
  return function (position) {
91
137
  var _position$top;
92
138
  var startCoords = editorView.coordsAtPos(pasteStartPos);
93
139
  var endBottom = getVisualEndBottom(editorView, pasteEndPos, tableAfterPos);
94
140
  var targetRect = targetElement.getBoundingClientRect();
95
141
 
142
+ // ── Vertical adjustment ──────────────────────────────────────────
96
143
  // The Popup places the menu at the target's bottom edge by default.
97
144
  // We shift it up so it aligns with the paste start position.
98
145
  // Both coordinates are in viewport space, so the delta is offset-parent agnostic.
@@ -108,8 +155,28 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
108
155
  adjustedTop += scrollContainerTop - startCoords.top + PASTE_MENU_GAP_TOP;
109
156
  }
110
157
  }
158
+
159
+ // ── Horizontal adjustment ────────────────────────────────────────
160
+ // When pasted content starts with a mark (bold, italic, link …) or
161
+ // an inline node (emoji, smart link, inline image …),
162
+ // findDomRefAtPos returns the narrow inline wrapper element. The
163
+ // Popup's alignX="end" then places the menu at that element's right
164
+ // edge instead of the content area's right edge. We correct this by
165
+ // resolving the nearest block-level ProseMirror ancestor and
166
+ // re-anchoring to its right edge.
167
+ var adjustedLeft = position.left;
168
+ if (blockAncestorDOM && blockAncestorDOM !== targetElement) {
169
+ var _position$left;
170
+ var blockRect = blockAncestorDOM.getBoundingClientRect();
171
+ // Shift left by the difference between the block's right edge and
172
+ // the inline target's right edge. This mirrors what alignX="end"
173
+ // would have computed if the target were the block element.
174
+ var leftDelta = blockRect.right - targetRect.right;
175
+ adjustedLeft = ((_position$left = position.left) !== null && _position$left !== void 0 ? _position$left : 0) + leftDelta;
176
+ }
111
177
  return _objectSpread(_objectSpread({}, position), {}, {
112
- top: adjustedTop
178
+ top: adjustedTop,
179
+ left: adjustedLeft
113
180
  });
114
181
  };
115
182
  }
@@ -235,7 +302,8 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
235
302
  minPopupMargin: PASTE_MENU_GAP_HORIZONTAL,
236
303
  zIndex: akEditorFloatingPanelZIndex,
237
304
  alignX: "end",
238
- alignY: "bottom",
305
+ alignY: "bottom"
306
+ /* eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) */,
239
307
  offset: [PASTE_MENU_GAP_HORIZONTAL, 0],
240
308
  onPositionCalculated: onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement),
241
309
  handleClickOutside: handleClickOutside,
@@ -25,10 +25,20 @@ export declare function resolveTableAfterPos(editorView: EditorView, pos: number
25
25
  */
26
26
  export declare function getVisualEndBottom(editorView: EditorView, pasteEndPos: number, tableAfterPos?: number): number;
27
27
  /**
28
- * Adjusts the vertical position of the paste menu to align with the top of the
29
- * pasted content using the exact coordinates at the paste start position,
30
- * and sticks the menu to the top of the scroll container when the pasted
31
- * content scrolls above the visible area.
28
+ * Finds the DOM element for the nearest block-level ProseMirror ancestor of
29
+ * the given document position. Uses ProseMirror's schema (`node.isBlock`)
30
+ * rather than CSS display properties, so the check is always in sync with the
31
+ * document model.
32
+ *
33
+ * Returns `null` if no block ancestor can be resolved to a DOM element.
34
+ */
35
+ export declare function findBlockAncestorDOM(editorView: EditorView, pos: number): HTMLElement | null;
36
+ /**
37
+ * Adjusts the position of the paste menu so that:
38
+ *
39
+ * **Vertical:** The menu aligns with the top of the pasted content using the
40
+ * exact coordinates at the paste start position, and sticks to the top of the
41
+ * scroll container when the pasted content scrolls above the visible area.
32
42
  *
33
43
  * The Popup uses alignY="bottom", which positions the popup below the target
34
44
  * element's bottom edge. This override:
@@ -39,6 +49,14 @@ export declare function getVisualEndBottom(editorView: EditorView, pasteEndPos:
39
49
  * to the scroll container's top edge (sticky-top).
40
50
  * 3. Stops sticking once the entire pasted range (pasteEndPos) has scrolled
41
51
  * above the visible area.
52
+ *
53
+ * **Horizontal:** When the target element is an inline element (e.g. a mark
54
+ * wrapper like `<strong>`, or an inline node like an emoji), the Popup's
55
+ * `alignX="end"` would place the menu at the right edge of that narrow
56
+ * element. This override resolves the nearest block-level ProseMirror
57
+ * ancestor (using `node.isBlock` from the document schema) and re-anchors
58
+ * the horizontal position to its right edge, so the menu consistently
59
+ * appears at the right side of the content area.
42
60
  */
43
61
  export declare function onPositionCalculated(editorView: EditorView, pasteStartPos: number, pasteEndPos: number, targetElement: HTMLElement, scrollableElement?: HTMLElement | false): (position: {
44
62
  bottom?: number;
@@ -25,10 +25,20 @@ export declare function resolveTableAfterPos(editorView: EditorView, pos: number
25
25
  */
26
26
  export declare function getVisualEndBottom(editorView: EditorView, pasteEndPos: number, tableAfterPos?: number): number;
27
27
  /**
28
- * Adjusts the vertical position of the paste menu to align with the top of the
29
- * pasted content using the exact coordinates at the paste start position,
30
- * and sticks the menu to the top of the scroll container when the pasted
31
- * content scrolls above the visible area.
28
+ * Finds the DOM element for the nearest block-level ProseMirror ancestor of
29
+ * the given document position. Uses ProseMirror's schema (`node.isBlock`)
30
+ * rather than CSS display properties, so the check is always in sync with the
31
+ * document model.
32
+ *
33
+ * Returns `null` if no block ancestor can be resolved to a DOM element.
34
+ */
35
+ export declare function findBlockAncestorDOM(editorView: EditorView, pos: number): HTMLElement | null;
36
+ /**
37
+ * Adjusts the position of the paste menu so that:
38
+ *
39
+ * **Vertical:** The menu aligns with the top of the pasted content using the
40
+ * exact coordinates at the paste start position, and sticks to the top of the
41
+ * scroll container when the pasted content scrolls above the visible area.
32
42
  *
33
43
  * The Popup uses alignY="bottom", which positions the popup below the target
34
44
  * element's bottom edge. This override:
@@ -39,6 +49,14 @@ export declare function getVisualEndBottom(editorView: EditorView, pasteEndPos:
39
49
  * to the scroll container's top edge (sticky-top).
40
50
  * 3. Stops sticking once the entire pasted range (pasteEndPos) has scrolled
41
51
  * above the visible area.
52
+ *
53
+ * **Horizontal:** When the target element is an inline element (e.g. a mark
54
+ * wrapper like `<strong>`, or an inline node like an emoji), the Popup's
55
+ * `alignX="end"` would place the menu at the right edge of that narrow
56
+ * element. This override resolves the nearest block-level ProseMirror
57
+ * ancestor (using `node.isBlock` from the document schema) and re-anchors
58
+ * the horizontal position to its right edge, so the menu consistently
59
+ * appears at the right side of the content area.
42
60
  */
43
61
  export declare function onPositionCalculated(editorView: EditorView, pasteStartPos: number, pasteEndPos: number, targetElement: HTMLElement, scrollableElement?: HTMLElement | false): (position: {
44
62
  bottom?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-paste-options-toolbar",
3
- "version": "9.1.5",
3
+ "version": "9.1.6",
4
4
  "description": "Paste options toolbar for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -48,7 +48,7 @@
48
48
  "react-intl-next": "npm:react-intl@^5.18.1"
49
49
  },
50
50
  "peerDependencies": {
51
- "@atlaskit/editor-common": "^112.6.0",
51
+ "@atlaskit/editor-common": "^112.8.0",
52
52
  "react": "^18.2.0",
53
53
  "react-dom": "^18.2.0"
54
54
  },