@atlaskit/editor-plugin-selection-extension 10.0.1 → 10.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,13 @@
1
1
  # @atlaskit/editor-plugin-selection-extension
2
2
 
3
+ ## 10.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`5d14fe3afd499`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5d14fe3afd499) -
8
+ Implement `SelectionRanges` for multiple nodes selection to indicate actual selection ranges
9
+ - Updated dependencies
10
+
3
11
  ## 10.0.1
4
12
 
5
13
  ### Patch Changes
@@ -1,17 +1,118 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.wrapNodesInDoc = exports.getSelectionInfoFromSameNode = exports.getSelectionInfo = exports.getCommonParentContainer = void 0;
7
+ exports.wrapNodesInDoc = exports.getSelectionInfoFromSameNode = exports.getSelectionInfo = exports.getCommonParentContainer = exports.buildSelectionRanges = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
7
9
  var _monitoring = require("@atlaskit/editor-common/monitoring");
8
10
  var _model = require("@atlaskit/editor-prosemirror/model");
9
11
  var LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
10
12
  var LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
11
13
 
12
14
  /**
13
- * Find the depth of the deepest common ancestor node.
15
+ * Build a JSON pointer path for a node within the selectedNode structure.
16
+ * @param pathIndices - Array of content indices representing the path to the node
14
17
  */
18
+ var buildJsonPointer = function buildJsonPointer(pathIndices) {
19
+ return pathIndices.map(function (index) {
20
+ return "/content/".concat(index);
21
+ }).join('');
22
+ };
23
+
24
+ /**
25
+ * Build selection ranges for multi-node selections.
26
+ * This function traverses the selectedNode and creates JSON pointer-based ranges
27
+ * that describe what parts of the selectedNode are included in the selection.
28
+ */
29
+ var buildSelectionRanges = exports.buildSelectionRanges = function buildSelectionRanges(selectedNode, selectedNodePos, $from, $to) {
30
+ var selectionStart = $from.pos;
31
+ var selectionEnd = $to.pos;
32
+ var tokenOffset = selectedNode.type.name === 'doc' ? 0 : 1;
33
+ var nodeStart = selectedNodePos + tokenOffset;
34
+ var nodeEnd = selectedNodePos + selectedNode.nodeSize - tokenOffset;
35
+
36
+ // If selection spans entire content, return undefined (complete block selection)
37
+ if (selectionStart <= nodeStart && selectionEnd >= nodeEnd) {
38
+ return undefined;
39
+ }
40
+ var selectionRanges = [];
41
+
42
+ // Traverse the selectedNode and find all nodes/text within the selection range
43
+ var _traverse = function traverse(node, nodePos, path) {
44
+ var nodeEndPos = nodePos + node.nodeSize;
45
+
46
+ // Skip nodes completely before or after selection
47
+ if (nodeEndPos <= selectionStart || nodePos >= selectionEnd) {
48
+ return;
49
+ }
50
+ if (node.isText) {
51
+ var _node$text;
52
+ var textStart = nodePos;
53
+ var textEnd = nodePos + (((_node$text = node.text) === null || _node$text === void 0 ? void 0 : _node$text.length) || 0);
54
+ var rangeStart = Math.max(textStart, selectionStart);
55
+ var rangeEnd = Math.min(textEnd, selectionEnd);
56
+ if (rangeStart < rangeEnd) {
57
+ var pointer = "".concat(buildJsonPointer(path), "/text");
58
+ selectionRanges.push({
59
+ start: {
60
+ pointer: pointer,
61
+ position: rangeStart - textStart
62
+ },
63
+ end: {
64
+ pointer: pointer,
65
+ position: rangeEnd - textStart
66
+ }
67
+ });
68
+ }
69
+ } else if (node.content.size > 0) {
70
+ var contentStart = nodePos + 1;
71
+ var contentEnd = nodeEndPos - 1;
72
+ var isWholeBlockSelected = node.isBlock && !node.isTextblock && !LIST_NODE_TYPES.has(node.type.name) && selectionStart <= contentStart && selectionEnd >= contentEnd;
73
+ if (isWholeBlockSelected) {
74
+ var _pointer = buildJsonPointer(path);
75
+ selectionRanges.push({
76
+ start: {
77
+ pointer: _pointer
78
+ },
79
+ end: {
80
+ pointer: _pointer
81
+ }
82
+ });
83
+ } else {
84
+ // Traverse children for textblocks, lists, or partial selections
85
+ var _childPos = nodePos + 1;
86
+ for (var i = 0; i < node.content.childCount; i++) {
87
+ _traverse(node.content.child(i), _childPos, [].concat((0, _toConsumableArray2.default)(path), [i]));
88
+ _childPos += node.content.child(i).nodeSize;
89
+ }
90
+ }
91
+ } else if (nodePos >= selectionStart && nodeEndPos <= selectionEnd) {
92
+ // Handle leaf nodes (e.g., hardBreak, image)
93
+ var _pointer2 = buildJsonPointer(path);
94
+ selectionRanges.push({
95
+ start: {
96
+ pointer: _pointer2
97
+ },
98
+ end: {
99
+ pointer: _pointer2
100
+ }
101
+ });
102
+ }
103
+ };
104
+
105
+ // Traverse each child of the selectedNode
106
+ var childPos = nodeStart;
107
+ for (var i = 0; i < selectedNode.content.childCount; i++) {
108
+ var child = selectedNode.content.child(i);
109
+ _traverse(child, childPos, [i]);
110
+ childPos += child.nodeSize;
111
+ }
112
+ return selectionRanges.length > 0 ? selectionRanges : undefined;
113
+ };
114
+
115
+ /** Find the depth of the deepest common ancestor node. */
15
116
  var getCommonAncestorDepth = function getCommonAncestorDepth($from, $to) {
16
117
  var minDepth = Math.min($from.depth, $to.depth);
17
118
  for (var d = 0; d <= minDepth; d++) {
@@ -113,15 +214,19 @@ var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(sele
113
214
  parentNode = _getCommonParentConta.node,
114
215
  parentNodePos = _getCommonParentConta.pos;
115
216
  if (parentNode) {
217
+ var _selectionRanges = buildSelectionRanges(parentNode, parentNodePos, $from, $to);
116
218
  return {
117
219
  selectedNode: parentNode,
118
- nodePos: parentNodePos
220
+ nodePos: parentNodePos,
221
+ selectionRanges: _selectionRanges
119
222
  };
120
223
  }
121
224
  var nodePos = $from.before();
225
+ var _selectionRanges2 = buildSelectionRanges($from.node(), nodePos, $from, $to);
122
226
  return {
123
227
  selectedNode: $from.node(),
124
- nodePos: nodePos
228
+ nodePos: nodePos,
229
+ selectionRanges: _selectionRanges2
125
230
  };
126
231
  }
127
232
 
@@ -134,24 +239,26 @@ var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(sele
134
239
  };
135
240
  }
136
241
  if (range.parent.type.name !== 'doc') {
137
- // If it's a list OR list item, check for topmost list parent
242
+ // For lists, find topmost list parent; otherwise use immediate parent
138
243
  if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
139
244
  var _getCommonParentConta2 = getCommonParentContainer($from, $to),
140
245
  topList = _getCommonParentConta2.node,
141
246
  topListPos = _getCommonParentConta2.pos;
142
247
  if (topList) {
248
+ var _selectionRanges3 = buildSelectionRanges(topList, topListPos, $from, $to);
143
249
  return {
144
250
  selectedNode: topList,
145
- nodePos: topListPos
251
+ nodePos: topListPos,
252
+ selectionRanges: _selectionRanges3
146
253
  };
147
254
  }
148
255
  }
149
-
150
- // For non-list containers (panel, expand, etc.), return the immediate parent
151
256
  var _nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
257
+ var _selectionRanges4 = buildSelectionRanges(range.parent, _nodePos, $from, $to);
152
258
  return {
153
259
  selectedNode: range.parent,
154
- nodePos: _nodePos
260
+ nodePos: _nodePos,
261
+ selectionRanges: _selectionRanges4
155
262
  };
156
263
  }
157
264
 
@@ -161,8 +268,10 @@ var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(sele
161
268
  nodes.push(range.parent.child(i));
162
269
  }
163
270
  var selectedNode = wrapNodesInDoc(schema, nodes);
271
+ var selectionRanges = buildSelectionRanges(selectedNode, range.start, $from, $to);
164
272
  return {
165
273
  selectedNode: selectedNode,
166
- nodePos: range.start
274
+ nodePos: range.start,
275
+ selectionRanges: selectionRanges
167
276
  };
168
277
  };
@@ -4,8 +4,103 @@ const LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
4
4
  const LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
5
5
 
6
6
  /**
7
- * Find the depth of the deepest common ancestor node.
7
+ * Build a JSON pointer path for a node within the selectedNode structure.
8
+ * @param pathIndices - Array of content indices representing the path to the node
8
9
  */
10
+ const buildJsonPointer = pathIndices => pathIndices.map(index => `/content/${index}`).join('');
11
+
12
+ /**
13
+ * Build selection ranges for multi-node selections.
14
+ * This function traverses the selectedNode and creates JSON pointer-based ranges
15
+ * that describe what parts of the selectedNode are included in the selection.
16
+ */
17
+ export const buildSelectionRanges = (selectedNode, selectedNodePos, $from, $to) => {
18
+ const selectionStart = $from.pos;
19
+ const selectionEnd = $to.pos;
20
+ const tokenOffset = selectedNode.type.name === 'doc' ? 0 : 1;
21
+ const nodeStart = selectedNodePos + tokenOffset;
22
+ const nodeEnd = selectedNodePos + selectedNode.nodeSize - tokenOffset;
23
+
24
+ // If selection spans entire content, return undefined (complete block selection)
25
+ if (selectionStart <= nodeStart && selectionEnd >= nodeEnd) {
26
+ return undefined;
27
+ }
28
+ const selectionRanges = [];
29
+
30
+ // Traverse the selectedNode and find all nodes/text within the selection range
31
+ const traverse = (node, nodePos, path) => {
32
+ const nodeEndPos = nodePos + node.nodeSize;
33
+
34
+ // Skip nodes completely before or after selection
35
+ if (nodeEndPos <= selectionStart || nodePos >= selectionEnd) {
36
+ return;
37
+ }
38
+ if (node.isText) {
39
+ var _node$text;
40
+ const textStart = nodePos;
41
+ const textEnd = nodePos + (((_node$text = node.text) === null || _node$text === void 0 ? void 0 : _node$text.length) || 0);
42
+ const rangeStart = Math.max(textStart, selectionStart);
43
+ const rangeEnd = Math.min(textEnd, selectionEnd);
44
+ if (rangeStart < rangeEnd) {
45
+ const pointer = `${buildJsonPointer(path)}/text`;
46
+ selectionRanges.push({
47
+ start: {
48
+ pointer,
49
+ position: rangeStart - textStart
50
+ },
51
+ end: {
52
+ pointer,
53
+ position: rangeEnd - textStart
54
+ }
55
+ });
56
+ }
57
+ } else if (node.content.size > 0) {
58
+ const contentStart = nodePos + 1;
59
+ const contentEnd = nodeEndPos - 1;
60
+ const isWholeBlockSelected = node.isBlock && !node.isTextblock && !LIST_NODE_TYPES.has(node.type.name) && selectionStart <= contentStart && selectionEnd >= contentEnd;
61
+ if (isWholeBlockSelected) {
62
+ const pointer = buildJsonPointer(path);
63
+ selectionRanges.push({
64
+ start: {
65
+ pointer
66
+ },
67
+ end: {
68
+ pointer
69
+ }
70
+ });
71
+ } else {
72
+ // Traverse children for textblocks, lists, or partial selections
73
+ let childPos = nodePos + 1;
74
+ for (let i = 0; i < node.content.childCount; i++) {
75
+ traverse(node.content.child(i), childPos, [...path, i]);
76
+ childPos += node.content.child(i).nodeSize;
77
+ }
78
+ }
79
+ } else if (nodePos >= selectionStart && nodeEndPos <= selectionEnd) {
80
+ // Handle leaf nodes (e.g., hardBreak, image)
81
+ const pointer = buildJsonPointer(path);
82
+ selectionRanges.push({
83
+ start: {
84
+ pointer
85
+ },
86
+ end: {
87
+ pointer
88
+ }
89
+ });
90
+ }
91
+ };
92
+
93
+ // Traverse each child of the selectedNode
94
+ let childPos = nodeStart;
95
+ for (let i = 0; i < selectedNode.content.childCount; i++) {
96
+ const child = selectedNode.content.child(i);
97
+ traverse(child, childPos, [i]);
98
+ childPos += child.nodeSize;
99
+ }
100
+ return selectionRanges.length > 0 ? selectionRanges : undefined;
101
+ };
102
+
103
+ /** Find the depth of the deepest common ancestor node. */
9
104
  const getCommonAncestorDepth = ($from, $to) => {
10
105
  const minDepth = Math.min($from.depth, $to.depth);
11
106
  for (let d = 0; d <= minDepth; d++) {
@@ -112,15 +207,19 @@ export const getSelectionInfo = (selection, schema) => {
112
207
  pos: parentNodePos
113
208
  } = getCommonParentContainer($from, $to);
114
209
  if (parentNode) {
210
+ const selectionRanges = buildSelectionRanges(parentNode, parentNodePos, $from, $to);
115
211
  return {
116
212
  selectedNode: parentNode,
117
- nodePos: parentNodePos
213
+ nodePos: parentNodePos,
214
+ selectionRanges
118
215
  };
119
216
  }
120
217
  const nodePos = $from.before();
218
+ const selectionRanges = buildSelectionRanges($from.node(), nodePos, $from, $to);
121
219
  return {
122
220
  selectedNode: $from.node(),
123
- nodePos
221
+ nodePos,
222
+ selectionRanges
124
223
  };
125
224
  }
126
225
 
@@ -133,25 +232,27 @@ export const getSelectionInfo = (selection, schema) => {
133
232
  };
134
233
  }
135
234
  if (range.parent.type.name !== 'doc') {
136
- // If it's a list OR list item, check for topmost list parent
235
+ // For lists, find topmost list parent; otherwise use immediate parent
137
236
  if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
138
237
  const {
139
238
  node: topList,
140
239
  pos: topListPos
141
240
  } = getCommonParentContainer($from, $to);
142
241
  if (topList) {
242
+ const selectionRanges = buildSelectionRanges(topList, topListPos, $from, $to);
143
243
  return {
144
244
  selectedNode: topList,
145
- nodePos: topListPos
245
+ nodePos: topListPos,
246
+ selectionRanges
146
247
  };
147
248
  }
148
249
  }
149
-
150
- // For non-list containers (panel, expand, etc.), return the immediate parent
151
250
  const nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
251
+ const selectionRanges = buildSelectionRanges(range.parent, nodePos, $from, $to);
152
252
  return {
153
253
  selectedNode: range.parent,
154
- nodePos
254
+ nodePos,
255
+ selectionRanges
155
256
  };
156
257
  }
157
258
 
@@ -161,8 +262,10 @@ export const getSelectionInfo = (selection, schema) => {
161
262
  nodes.push(range.parent.child(i));
162
263
  }
163
264
  const selectedNode = wrapNodesInDoc(schema, nodes);
265
+ const selectionRanges = buildSelectionRanges(selectedNode, range.start, $from, $to);
164
266
  return {
165
267
  selectedNode,
166
- nodePos: range.start
268
+ nodePos: range.start,
269
+ selectionRanges
167
270
  };
168
271
  };
@@ -1,11 +1,111 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import { logException } from '@atlaskit/editor-common/monitoring';
2
3
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
4
  var LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
4
5
  var LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
5
6
 
6
7
  /**
7
- * Find the depth of the deepest common ancestor node.
8
+ * Build a JSON pointer path for a node within the selectedNode structure.
9
+ * @param pathIndices - Array of content indices representing the path to the node
8
10
  */
11
+ var buildJsonPointer = function buildJsonPointer(pathIndices) {
12
+ return pathIndices.map(function (index) {
13
+ return "/content/".concat(index);
14
+ }).join('');
15
+ };
16
+
17
+ /**
18
+ * Build selection ranges for multi-node selections.
19
+ * This function traverses the selectedNode and creates JSON pointer-based ranges
20
+ * that describe what parts of the selectedNode are included in the selection.
21
+ */
22
+ export var buildSelectionRanges = function buildSelectionRanges(selectedNode, selectedNodePos, $from, $to) {
23
+ var selectionStart = $from.pos;
24
+ var selectionEnd = $to.pos;
25
+ var tokenOffset = selectedNode.type.name === 'doc' ? 0 : 1;
26
+ var nodeStart = selectedNodePos + tokenOffset;
27
+ var nodeEnd = selectedNodePos + selectedNode.nodeSize - tokenOffset;
28
+
29
+ // If selection spans entire content, return undefined (complete block selection)
30
+ if (selectionStart <= nodeStart && selectionEnd >= nodeEnd) {
31
+ return undefined;
32
+ }
33
+ var selectionRanges = [];
34
+
35
+ // Traverse the selectedNode and find all nodes/text within the selection range
36
+ var _traverse = function traverse(node, nodePos, path) {
37
+ var nodeEndPos = nodePos + node.nodeSize;
38
+
39
+ // Skip nodes completely before or after selection
40
+ if (nodeEndPos <= selectionStart || nodePos >= selectionEnd) {
41
+ return;
42
+ }
43
+ if (node.isText) {
44
+ var _node$text;
45
+ var textStart = nodePos;
46
+ var textEnd = nodePos + (((_node$text = node.text) === null || _node$text === void 0 ? void 0 : _node$text.length) || 0);
47
+ var rangeStart = Math.max(textStart, selectionStart);
48
+ var rangeEnd = Math.min(textEnd, selectionEnd);
49
+ if (rangeStart < rangeEnd) {
50
+ var pointer = "".concat(buildJsonPointer(path), "/text");
51
+ selectionRanges.push({
52
+ start: {
53
+ pointer: pointer,
54
+ position: rangeStart - textStart
55
+ },
56
+ end: {
57
+ pointer: pointer,
58
+ position: rangeEnd - textStart
59
+ }
60
+ });
61
+ }
62
+ } else if (node.content.size > 0) {
63
+ var contentStart = nodePos + 1;
64
+ var contentEnd = nodeEndPos - 1;
65
+ var isWholeBlockSelected = node.isBlock && !node.isTextblock && !LIST_NODE_TYPES.has(node.type.name) && selectionStart <= contentStart && selectionEnd >= contentEnd;
66
+ if (isWholeBlockSelected) {
67
+ var _pointer = buildJsonPointer(path);
68
+ selectionRanges.push({
69
+ start: {
70
+ pointer: _pointer
71
+ },
72
+ end: {
73
+ pointer: _pointer
74
+ }
75
+ });
76
+ } else {
77
+ // Traverse children for textblocks, lists, or partial selections
78
+ var _childPos = nodePos + 1;
79
+ for (var i = 0; i < node.content.childCount; i++) {
80
+ _traverse(node.content.child(i), _childPos, [].concat(_toConsumableArray(path), [i]));
81
+ _childPos += node.content.child(i).nodeSize;
82
+ }
83
+ }
84
+ } else if (nodePos >= selectionStart && nodeEndPos <= selectionEnd) {
85
+ // Handle leaf nodes (e.g., hardBreak, image)
86
+ var _pointer2 = buildJsonPointer(path);
87
+ selectionRanges.push({
88
+ start: {
89
+ pointer: _pointer2
90
+ },
91
+ end: {
92
+ pointer: _pointer2
93
+ }
94
+ });
95
+ }
96
+ };
97
+
98
+ // Traverse each child of the selectedNode
99
+ var childPos = nodeStart;
100
+ for (var i = 0; i < selectedNode.content.childCount; i++) {
101
+ var child = selectedNode.content.child(i);
102
+ _traverse(child, childPos, [i]);
103
+ childPos += child.nodeSize;
104
+ }
105
+ return selectionRanges.length > 0 ? selectionRanges : undefined;
106
+ };
107
+
108
+ /** Find the depth of the deepest common ancestor node. */
9
109
  var getCommonAncestorDepth = function getCommonAncestorDepth($from, $to) {
10
110
  var minDepth = Math.min($from.depth, $to.depth);
11
111
  for (var d = 0; d <= minDepth; d++) {
@@ -107,15 +207,19 @@ export var getSelectionInfo = function getSelectionInfo(selection, schema) {
107
207
  parentNode = _getCommonParentConta.node,
108
208
  parentNodePos = _getCommonParentConta.pos;
109
209
  if (parentNode) {
210
+ var _selectionRanges = buildSelectionRanges(parentNode, parentNodePos, $from, $to);
110
211
  return {
111
212
  selectedNode: parentNode,
112
- nodePos: parentNodePos
213
+ nodePos: parentNodePos,
214
+ selectionRanges: _selectionRanges
113
215
  };
114
216
  }
115
217
  var nodePos = $from.before();
218
+ var _selectionRanges2 = buildSelectionRanges($from.node(), nodePos, $from, $to);
116
219
  return {
117
220
  selectedNode: $from.node(),
118
- nodePos: nodePos
221
+ nodePos: nodePos,
222
+ selectionRanges: _selectionRanges2
119
223
  };
120
224
  }
121
225
 
@@ -128,24 +232,26 @@ export var getSelectionInfo = function getSelectionInfo(selection, schema) {
128
232
  };
129
233
  }
130
234
  if (range.parent.type.name !== 'doc') {
131
- // If it's a list OR list item, check for topmost list parent
235
+ // For lists, find topmost list parent; otherwise use immediate parent
132
236
  if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
133
237
  var _getCommonParentConta2 = getCommonParentContainer($from, $to),
134
238
  topList = _getCommonParentConta2.node,
135
239
  topListPos = _getCommonParentConta2.pos;
136
240
  if (topList) {
241
+ var _selectionRanges3 = buildSelectionRanges(topList, topListPos, $from, $to);
137
242
  return {
138
243
  selectedNode: topList,
139
- nodePos: topListPos
244
+ nodePos: topListPos,
245
+ selectionRanges: _selectionRanges3
140
246
  };
141
247
  }
142
248
  }
143
-
144
- // For non-list containers (panel, expand, etc.), return the immediate parent
145
249
  var _nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
250
+ var _selectionRanges4 = buildSelectionRanges(range.parent, _nodePos, $from, $to);
146
251
  return {
147
252
  selectedNode: range.parent,
148
- nodePos: _nodePos
253
+ nodePos: _nodePos,
254
+ selectionRanges: _selectionRanges4
149
255
  };
150
256
  }
151
257
 
@@ -155,8 +261,10 @@ export var getSelectionInfo = function getSelectionInfo(selection, schema) {
155
261
  nodes.push(range.parent.child(i));
156
262
  }
157
263
  var selectedNode = wrapNodesInDoc(schema, nodes);
264
+ var selectionRanges = buildSelectionRanges(selectedNode, range.start, $from, $to);
158
265
  return {
159
266
  selectedNode: selectedNode,
160
- nodePos: range.start
267
+ nodePos: range.start,
268
+ selectionRanges: selectionRanges
161
269
  };
162
270
  };
@@ -1,5 +1,12 @@
1
1
  import { type Node as PMNode, type ResolvedPos, type Schema } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
+ import type { SelectionRange } from '../../types';
4
+ /**
5
+ * Build selection ranges for multi-node selections.
6
+ * This function traverses the selectedNode and creates JSON pointer-based ranges
7
+ * that describe what parts of the selectedNode are included in the selection.
8
+ */
9
+ export declare const buildSelectionRanges: (selectedNode: PMNode, selectedNodePos: number, $from: ResolvedPos, $to: ResolvedPos) => SelectionRange[] | undefined;
3
10
  /**
4
11
  * Find the closest parent container node that contains the selection.
5
12
  * - For lists: returns the topmost list (to handle nested lists)
@@ -31,4 +38,9 @@ export declare const getSelectionInfoFromSameNode: (selection: TextSelection) =>
31
38
  export declare const getSelectionInfo: (selection: TextSelection, schema: Schema) => {
32
39
  selectedNode: PMNode;
33
40
  nodePos: number;
41
+ selectionRanges: SelectionRange[] | undefined;
42
+ } | {
43
+ selectedNode: PMNode;
44
+ nodePos: number;
45
+ selectionRanges?: undefined;
34
46
  };
@@ -1,5 +1,12 @@
1
1
  import { type Node as PMNode, type ResolvedPos, type Schema } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
+ import type { SelectionRange } from '../../types';
4
+ /**
5
+ * Build selection ranges for multi-node selections.
6
+ * This function traverses the selectedNode and creates JSON pointer-based ranges
7
+ * that describe what parts of the selectedNode are included in the selection.
8
+ */
9
+ export declare const buildSelectionRanges: (selectedNode: PMNode, selectedNodePos: number, $from: ResolvedPos, $to: ResolvedPos) => SelectionRange[] | undefined;
3
10
  /**
4
11
  * Find the closest parent container node that contains the selection.
5
12
  * - For lists: returns the topmost list (to handle nested lists)
@@ -31,4 +38,9 @@ export declare const getSelectionInfoFromSameNode: (selection: TextSelection) =>
31
38
  export declare const getSelectionInfo: (selection: TextSelection, schema: Schema) => {
32
39
  selectedNode: PMNode;
33
40
  nodePos: number;
41
+ selectionRanges: SelectionRange[] | undefined;
42
+ } | {
43
+ selectedNode: PMNode;
44
+ nodePos: number;
45
+ selectionRanges?: undefined;
34
46
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-selection-extension",
3
- "version": "10.0.1",
3
+ "version": "10.0.2",
4
4
  "description": "editor-plugin-selection-extension plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -52,14 +52,14 @@
52
52
  "@atlaskit/platform-feature-flags": "^1.1.0",
53
53
  "@atlaskit/platform-feature-flags-react": "^0.4.0",
54
54
  "@atlaskit/primitives": "^17.0.0",
55
- "@atlaskit/tmp-editor-statsig": "^16.3.0",
55
+ "@atlaskit/tmp-editor-statsig": "^16.5.0",
56
56
  "@babel/runtime": "^7.0.0",
57
57
  "lodash": "^4.17.21",
58
58
  "react-intl-next": "npm:react-intl@^5.18.1",
59
59
  "uuid": "^3.1.0"
60
60
  },
61
61
  "peerDependencies": {
62
- "@atlaskit/editor-common": "^111.0.0",
62
+ "@atlaskit/editor-common": "^111.2.0",
63
63
  "react": "^18.2.0"
64
64
  },
65
65
  "devDependencies": {