@atlaskit/editor-plugin-selection-extension 7.1.1 → 7.1.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 +7 -0
- package/dist/cjs/pm-plugins/utils/index.js +17 -28
- package/dist/cjs/pm-plugins/utils/selection-helpers.js +168 -0
- package/dist/es2019/pm-plugins/utils/index.js +21 -34
- package/dist/es2019/pm-plugins/utils/selection-helpers.js +168 -0
- package/dist/esm/pm-plugins/utils/index.js +17 -28
- package/dist/esm/pm-plugins/utils/selection-helpers.js +162 -0
- package/dist/types/pm-plugins/utils/selection-helpers.d.ts +34 -0
- package/dist/types-ts4.5/pm-plugins/utils/selection-helpers.d.ts +34 -0
- package/package.json +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-selection-extension
|
|
2
2
|
|
|
3
|
+
## 7.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`0b0f96c20a852`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0b0f96c20a852) -
|
|
8
|
+
Improve getSelectionAdf api to return expanded selection
|
|
9
|
+
|
|
3
10
|
## 7.1.1
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
|
@@ -18,6 +18,7 @@ var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
|
|
|
18
18
|
var _editorTables = require("@atlaskit/editor-tables");
|
|
19
19
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
20
20
|
var _getBoundingBoxFromSelection = require("../../ui/getBoundingBoxFromSelection");
|
|
21
|
+
var _selectionHelpers = require("./selection-helpers");
|
|
21
22
|
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; }
|
|
22
23
|
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) { (0, _defineProperty2.default)(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; }
|
|
23
24
|
var getSelectedRect = function getSelectedRect(selection) {
|
|
@@ -29,24 +30,6 @@ var getSelectedRect = function getSelectedRect(selection) {
|
|
|
29
30
|
var rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
30
31
|
return rect;
|
|
31
32
|
};
|
|
32
|
-
var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
33
|
-
var $from = selection.$from,
|
|
34
|
-
$to = selection.$to;
|
|
35
|
-
return {
|
|
36
|
-
selectedNode: $from.node(),
|
|
37
|
-
selectionRanges: [{
|
|
38
|
-
start: {
|
|
39
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
40
|
-
position: $from.parentOffset
|
|
41
|
-
},
|
|
42
|
-
end: {
|
|
43
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
44
|
-
position: $to.parentOffset
|
|
45
|
-
}
|
|
46
|
-
}],
|
|
47
|
-
nodePos: $from.before() // position before the selection
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
33
|
var getSelectionInfoFromCellSelection = function getSelectionInfoFromCellSelection(selection) {
|
|
51
34
|
var selectedNode = selection.$anchorCell.node(-1);
|
|
52
35
|
var nodePos = selection.$anchorCell.before(-1);
|
|
@@ -117,12 +100,15 @@ function getSelectionAdfInfo(state) {
|
|
|
117
100
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
118
101
|
};
|
|
119
102
|
if (selection instanceof _state.TextSelection) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
103
|
+
if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_improvement')) {
|
|
104
|
+
// New implementation: unified handler for all text selections
|
|
105
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfo)(selection, state.schema);
|
|
124
106
|
} else {
|
|
125
|
-
|
|
107
|
+
var $from = selection.$from,
|
|
108
|
+
$to = selection.$to;
|
|
109
|
+
if ($from.parent === $to.parent) {
|
|
110
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfoFromSameNode)(selection);
|
|
111
|
+
}
|
|
126
112
|
}
|
|
127
113
|
} else if (selection instanceof _editorTables.CellSelection) {
|
|
128
114
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -134,17 +120,20 @@ function getSelectionAdfInfo(state) {
|
|
|
134
120
|
});
|
|
135
121
|
}
|
|
136
122
|
function getSelectionAdfInfoNew(selection) {
|
|
123
|
+
var schema = selection.$from.doc.type.schema;
|
|
137
124
|
var selectionInfo = {
|
|
138
125
|
selectedNode: selection.$from.node(),
|
|
139
126
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
140
127
|
};
|
|
141
128
|
if (selection instanceof _state.TextSelection) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if ($from.parent === $to.parent) {
|
|
145
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
129
|
+
if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_improvement')) {
|
|
130
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfo)(selection, schema);
|
|
146
131
|
} else {
|
|
147
|
-
|
|
132
|
+
var $from = selection.$from,
|
|
133
|
+
$to = selection.$to;
|
|
134
|
+
if ($from.parent === $to.parent) {
|
|
135
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfoFromSameNode)(selection);
|
|
136
|
+
}
|
|
148
137
|
}
|
|
149
138
|
} else if (selection instanceof _editorTables.CellSelection) {
|
|
150
139
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.wrapNodesInDoc = exports.getSelectionInfoFromSameNode = exports.getSelectionInfo = exports.getCommonParentContainer = void 0;
|
|
7
|
+
var _monitoring = require("@atlaskit/editor-common/monitoring");
|
|
8
|
+
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
9
|
+
var LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
|
|
10
|
+
var LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Find the depth of the deepest common ancestor node.
|
|
14
|
+
*/
|
|
15
|
+
var getCommonAncestorDepth = function getCommonAncestorDepth($from, $to) {
|
|
16
|
+
var minDepth = Math.min($from.depth, $to.depth);
|
|
17
|
+
for (var d = 0; d <= minDepth; d++) {
|
|
18
|
+
if ($from.node(d) !== $to.node(d)) {
|
|
19
|
+
return d - 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return minDepth;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find the closest parent container node that contains the selection.
|
|
27
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
28
|
+
* - For other containers returns the closest one
|
|
29
|
+
* Returns the parent and its position.
|
|
30
|
+
*/
|
|
31
|
+
var getCommonParentContainer = exports.getCommonParentContainer = function getCommonParentContainer($from, $to) {
|
|
32
|
+
var commonDepth = getCommonAncestorDepth($from, $to);
|
|
33
|
+
|
|
34
|
+
// Single pass: look for topmost list OR first non-list parent
|
|
35
|
+
var topMostList = null;
|
|
36
|
+
var topMostListPos = -1;
|
|
37
|
+
var firstNonListParent = null;
|
|
38
|
+
var firstNonListParentPos = -1;
|
|
39
|
+
for (var depth = commonDepth; depth > 0; depth--) {
|
|
40
|
+
var node = $from.node(depth);
|
|
41
|
+
if (LIST_NODE_TYPES.has(node.type.name)) {
|
|
42
|
+
// Keep updating to find the topmost list (last one found going upward)
|
|
43
|
+
topMostList = node;
|
|
44
|
+
topMostListPos = $from.before(depth);
|
|
45
|
+
} else if (!firstNonListParent && node.type.name !== 'doc') {
|
|
46
|
+
// Only capture the first (innermost) non-list parent
|
|
47
|
+
firstNonListParent = node;
|
|
48
|
+
firstNonListParentPos = $from.before(depth);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Return topmost list if found, else first non-list parent
|
|
53
|
+
if (topMostList) {
|
|
54
|
+
return {
|
|
55
|
+
node: topMostList,
|
|
56
|
+
pos: topMostListPos
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
node: firstNonListParent,
|
|
61
|
+
pos: firstNonListParentPos
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
67
|
+
*/
|
|
68
|
+
var wrapNodesInDoc = exports.wrapNodesInDoc = function wrapNodesInDoc(schema, nodes) {
|
|
69
|
+
if (nodes.length === 0) {
|
|
70
|
+
return schema.nodes.doc.createChecked({}, _model.Fragment.empty);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Single node: return unwrapped
|
|
74
|
+
if (nodes.length === 1) {
|
|
75
|
+
return nodes[0];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// For multiple nodes, wrap in doc
|
|
79
|
+
try {
|
|
80
|
+
return schema.node('doc', null, _model.Fragment.from(nodes));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
(0, _monitoring.logException)(error, {
|
|
83
|
+
location: 'editor-plugin-selection-extension'
|
|
84
|
+
});
|
|
85
|
+
return schema.nodes.doc.createChecked({}, _model.Fragment.empty);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var getSelectionInfoFromSameNode = exports.getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
89
|
+
var $from = selection.$from,
|
|
90
|
+
$to = selection.$to;
|
|
91
|
+
return {
|
|
92
|
+
selectedNode: $from.node(),
|
|
93
|
+
selectionRanges: [{
|
|
94
|
+
start: {
|
|
95
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
96
|
+
position: $from.parentOffset
|
|
97
|
+
},
|
|
98
|
+
end: {
|
|
99
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
100
|
+
position: $to.parentOffset
|
|
101
|
+
}
|
|
102
|
+
}],
|
|
103
|
+
nodePos: $from.before()
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(selection, schema) {
|
|
107
|
+
var $from = selection.$from,
|
|
108
|
+
$to = selection.$to;
|
|
109
|
+
|
|
110
|
+
// For same parent selections, check for parent container
|
|
111
|
+
if ($from.parent === $to.parent) {
|
|
112
|
+
var _getCommonParentConta = getCommonParentContainer($from, $to),
|
|
113
|
+
parentNode = _getCommonParentConta.node,
|
|
114
|
+
parentNodePos = _getCommonParentConta.pos;
|
|
115
|
+
if (parentNode) {
|
|
116
|
+
return {
|
|
117
|
+
selectedNode: parentNode,
|
|
118
|
+
nodePos: parentNodePos
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
var nodePos = $from.before();
|
|
122
|
+
return {
|
|
123
|
+
selectedNode: $from.node(),
|
|
124
|
+
nodePos: nodePos
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// find the common ancestor
|
|
129
|
+
var range = $from.blockRange($to);
|
|
130
|
+
if (!range) {
|
|
131
|
+
return {
|
|
132
|
+
selectedNode: $from.node(),
|
|
133
|
+
nodePos: $from.depth > 0 ? $from.before() : $from.pos
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (range.parent.type.name !== 'doc') {
|
|
137
|
+
// If it's a list OR list item, check for topmost list parent
|
|
138
|
+
if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
|
|
139
|
+
var _getCommonParentConta2 = getCommonParentContainer($from, $to),
|
|
140
|
+
topList = _getCommonParentConta2.node,
|
|
141
|
+
topListPos = _getCommonParentConta2.pos;
|
|
142
|
+
if (topList) {
|
|
143
|
+
return {
|
|
144
|
+
selectedNode: topList,
|
|
145
|
+
nodePos: topListPos
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// For non-list containers (panel, expand, etc.), return the immediate parent
|
|
151
|
+
var _nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
|
|
152
|
+
return {
|
|
153
|
+
selectedNode: range.parent,
|
|
154
|
+
nodePos: _nodePos
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Extract complete nodes within the block range
|
|
159
|
+
var nodes = [];
|
|
160
|
+
for (var i = range.startIndex; i < range.endIndex; i++) {
|
|
161
|
+
nodes.push(range.parent.child(i));
|
|
162
|
+
}
|
|
163
|
+
var selectedNode = wrapNodesInDoc(schema, nodes);
|
|
164
|
+
return {
|
|
165
|
+
selectedNode: selectedNode,
|
|
166
|
+
nodePos: range.start
|
|
167
|
+
};
|
|
168
|
+
};
|
|
@@ -7,6 +7,7 @@ import { akEditorFullPageToolbarHeight } from '@atlaskit/editor-shared-styles';
|
|
|
7
7
|
import { CellSelection, TableMap } from '@atlaskit/editor-tables';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
9
9
|
import { getBoundingBoxFromSelection } from '../../ui/getBoundingBoxFromSelection';
|
|
10
|
+
import { getSelectionInfo, getSelectionInfoFromSameNode } from './selection-helpers';
|
|
10
11
|
const getSelectedRect = selection => {
|
|
11
12
|
const {
|
|
12
13
|
$anchorCell,
|
|
@@ -18,26 +19,6 @@ const getSelectedRect = selection => {
|
|
|
18
19
|
const rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
19
20
|
return rect;
|
|
20
21
|
};
|
|
21
|
-
const getSelectionInfoFromSameNode = selection => {
|
|
22
|
-
const {
|
|
23
|
-
$from,
|
|
24
|
-
$to
|
|
25
|
-
} = selection;
|
|
26
|
-
return {
|
|
27
|
-
selectedNode: $from.node(),
|
|
28
|
-
selectionRanges: [{
|
|
29
|
-
start: {
|
|
30
|
-
pointer: `/content/${$from.index()}/text`,
|
|
31
|
-
position: $from.parentOffset
|
|
32
|
-
},
|
|
33
|
-
end: {
|
|
34
|
-
pointer: `/content/${$from.index()}/text`,
|
|
35
|
-
position: $to.parentOffset
|
|
36
|
-
}
|
|
37
|
-
}],
|
|
38
|
-
nodePos: $from.before() // position before the selection
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
22
|
const getSelectionInfoFromCellSelection = selection => {
|
|
42
23
|
const selectedNode = selection.$anchorCell.node(-1);
|
|
43
24
|
const nodePos = selection.$anchorCell.before(-1);
|
|
@@ -116,14 +97,17 @@ export function getSelectionAdfInfo(state) {
|
|
|
116
97
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
117
98
|
};
|
|
118
99
|
if (selection instanceof TextSelection) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
} = selection;
|
|
123
|
-
if ($from.parent === $to.parent) {
|
|
124
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
100
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
101
|
+
// New implementation: unified handler for all text selections
|
|
102
|
+
selectionInfo = getSelectionInfo(selection, state.schema);
|
|
125
103
|
} else {
|
|
126
|
-
|
|
104
|
+
const {
|
|
105
|
+
$from,
|
|
106
|
+
$to
|
|
107
|
+
} = selection;
|
|
108
|
+
if ($from.parent === $to.parent) {
|
|
109
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
110
|
+
}
|
|
127
111
|
}
|
|
128
112
|
} else if (selection instanceof CellSelection) {
|
|
129
113
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -136,19 +120,22 @@ export function getSelectionAdfInfo(state) {
|
|
|
136
120
|
};
|
|
137
121
|
}
|
|
138
122
|
export function getSelectionAdfInfoNew(selection) {
|
|
123
|
+
const schema = selection.$from.doc.type.schema;
|
|
139
124
|
let selectionInfo = {
|
|
140
125
|
selectedNode: selection.$from.node(),
|
|
141
126
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
142
127
|
};
|
|
143
128
|
if (selection instanceof TextSelection) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
$to
|
|
147
|
-
} = selection;
|
|
148
|
-
if ($from.parent === $to.parent) {
|
|
149
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
129
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
130
|
+
selectionInfo = getSelectionInfo(selection, schema);
|
|
150
131
|
} else {
|
|
151
|
-
|
|
132
|
+
const {
|
|
133
|
+
$from,
|
|
134
|
+
$to
|
|
135
|
+
} = selection;
|
|
136
|
+
if ($from.parent === $to.parent) {
|
|
137
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
138
|
+
}
|
|
152
139
|
}
|
|
153
140
|
} else if (selection instanceof CellSelection) {
|
|
154
141
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
const LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
|
|
4
|
+
const LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find the depth of the deepest common ancestor node.
|
|
8
|
+
*/
|
|
9
|
+
const getCommonAncestorDepth = ($from, $to) => {
|
|
10
|
+
const minDepth = Math.min($from.depth, $to.depth);
|
|
11
|
+
for (let d = 0; d <= minDepth; d++) {
|
|
12
|
+
if ($from.node(d) !== $to.node(d)) {
|
|
13
|
+
return d - 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return minDepth;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Find the closest parent container node that contains the selection.
|
|
21
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
22
|
+
* - For other containers returns the closest one
|
|
23
|
+
* Returns the parent and its position.
|
|
24
|
+
*/
|
|
25
|
+
export const getCommonParentContainer = ($from, $to) => {
|
|
26
|
+
const commonDepth = getCommonAncestorDepth($from, $to);
|
|
27
|
+
|
|
28
|
+
// Single pass: look for topmost list OR first non-list parent
|
|
29
|
+
let topMostList = null;
|
|
30
|
+
let topMostListPos = -1;
|
|
31
|
+
let firstNonListParent = null;
|
|
32
|
+
let firstNonListParentPos = -1;
|
|
33
|
+
for (let depth = commonDepth; depth > 0; depth--) {
|
|
34
|
+
const node = $from.node(depth);
|
|
35
|
+
if (LIST_NODE_TYPES.has(node.type.name)) {
|
|
36
|
+
// Keep updating to find the topmost list (last one found going upward)
|
|
37
|
+
topMostList = node;
|
|
38
|
+
topMostListPos = $from.before(depth);
|
|
39
|
+
} else if (!firstNonListParent && node.type.name !== 'doc') {
|
|
40
|
+
// Only capture the first (innermost) non-list parent
|
|
41
|
+
firstNonListParent = node;
|
|
42
|
+
firstNonListParentPos = $from.before(depth);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Return topmost list if found, else first non-list parent
|
|
47
|
+
if (topMostList) {
|
|
48
|
+
return {
|
|
49
|
+
node: topMostList,
|
|
50
|
+
pos: topMostListPos
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
node: firstNonListParent,
|
|
55
|
+
pos: firstNonListParentPos
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
61
|
+
*/
|
|
62
|
+
export const wrapNodesInDoc = (schema, nodes) => {
|
|
63
|
+
if (nodes.length === 0) {
|
|
64
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Single node: return unwrapped
|
|
68
|
+
if (nodes.length === 1) {
|
|
69
|
+
return nodes[0];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// For multiple nodes, wrap in doc
|
|
73
|
+
try {
|
|
74
|
+
return schema.node('doc', null, Fragment.from(nodes));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logException(error, {
|
|
77
|
+
location: 'editor-plugin-selection-extension'
|
|
78
|
+
});
|
|
79
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
export const getSelectionInfoFromSameNode = selection => {
|
|
83
|
+
const {
|
|
84
|
+
$from,
|
|
85
|
+
$to
|
|
86
|
+
} = selection;
|
|
87
|
+
return {
|
|
88
|
+
selectedNode: $from.node(),
|
|
89
|
+
selectionRanges: [{
|
|
90
|
+
start: {
|
|
91
|
+
pointer: `/content/${$from.index()}/text`,
|
|
92
|
+
position: $from.parentOffset
|
|
93
|
+
},
|
|
94
|
+
end: {
|
|
95
|
+
pointer: `/content/${$from.index()}/text`,
|
|
96
|
+
position: $to.parentOffset
|
|
97
|
+
}
|
|
98
|
+
}],
|
|
99
|
+
nodePos: $from.before()
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
export const getSelectionInfo = (selection, schema) => {
|
|
103
|
+
const {
|
|
104
|
+
$from,
|
|
105
|
+
$to
|
|
106
|
+
} = selection;
|
|
107
|
+
|
|
108
|
+
// For same parent selections, check for parent container
|
|
109
|
+
if ($from.parent === $to.parent) {
|
|
110
|
+
const {
|
|
111
|
+
node: parentNode,
|
|
112
|
+
pos: parentNodePos
|
|
113
|
+
} = getCommonParentContainer($from, $to);
|
|
114
|
+
if (parentNode) {
|
|
115
|
+
return {
|
|
116
|
+
selectedNode: parentNode,
|
|
117
|
+
nodePos: parentNodePos
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const nodePos = $from.before();
|
|
121
|
+
return {
|
|
122
|
+
selectedNode: $from.node(),
|
|
123
|
+
nodePos
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// find the common ancestor
|
|
128
|
+
const range = $from.blockRange($to);
|
|
129
|
+
if (!range) {
|
|
130
|
+
return {
|
|
131
|
+
selectedNode: $from.node(),
|
|
132
|
+
nodePos: $from.depth > 0 ? $from.before() : $from.pos
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (range.parent.type.name !== 'doc') {
|
|
136
|
+
// If it's a list OR list item, check for topmost list parent
|
|
137
|
+
if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
|
|
138
|
+
const {
|
|
139
|
+
node: topList,
|
|
140
|
+
pos: topListPos
|
|
141
|
+
} = getCommonParentContainer($from, $to);
|
|
142
|
+
if (topList) {
|
|
143
|
+
return {
|
|
144
|
+
selectedNode: topList,
|
|
145
|
+
nodePos: topListPos
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// For non-list containers (panel, expand, etc.), return the immediate parent
|
|
151
|
+
const nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
|
|
152
|
+
return {
|
|
153
|
+
selectedNode: range.parent,
|
|
154
|
+
nodePos
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Extract complete nodes within the block range
|
|
159
|
+
const nodes = [];
|
|
160
|
+
for (let i = range.startIndex; i < range.endIndex; i++) {
|
|
161
|
+
nodes.push(range.parent.child(i));
|
|
162
|
+
}
|
|
163
|
+
const selectedNode = wrapNodesInDoc(schema, nodes);
|
|
164
|
+
return {
|
|
165
|
+
selectedNode,
|
|
166
|
+
nodePos: range.start
|
|
167
|
+
};
|
|
168
|
+
};
|
|
@@ -10,6 +10,7 @@ import { akEditorFullPageToolbarHeight } from '@atlaskit/editor-shared-styles';
|
|
|
10
10
|
import { CellSelection, TableMap } from '@atlaskit/editor-tables';
|
|
11
11
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
12
12
|
import { getBoundingBoxFromSelection } from '../../ui/getBoundingBoxFromSelection';
|
|
13
|
+
import { getSelectionInfo, getSelectionInfoFromSameNode } from './selection-helpers';
|
|
13
14
|
var getSelectedRect = function getSelectedRect(selection) {
|
|
14
15
|
var $anchorCell = selection.$anchorCell,
|
|
15
16
|
$headCell = selection.$headCell;
|
|
@@ -19,24 +20,6 @@ var getSelectedRect = function getSelectedRect(selection) {
|
|
|
19
20
|
var rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
20
21
|
return rect;
|
|
21
22
|
};
|
|
22
|
-
var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
23
|
-
var $from = selection.$from,
|
|
24
|
-
$to = selection.$to;
|
|
25
|
-
return {
|
|
26
|
-
selectedNode: $from.node(),
|
|
27
|
-
selectionRanges: [{
|
|
28
|
-
start: {
|
|
29
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
30
|
-
position: $from.parentOffset
|
|
31
|
-
},
|
|
32
|
-
end: {
|
|
33
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
34
|
-
position: $to.parentOffset
|
|
35
|
-
}
|
|
36
|
-
}],
|
|
37
|
-
nodePos: $from.before() // position before the selection
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
23
|
var getSelectionInfoFromCellSelection = function getSelectionInfoFromCellSelection(selection) {
|
|
41
24
|
var selectedNode = selection.$anchorCell.node(-1);
|
|
42
25
|
var nodePos = selection.$anchorCell.before(-1);
|
|
@@ -107,12 +90,15 @@ export function getSelectionAdfInfo(state) {
|
|
|
107
90
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
108
91
|
};
|
|
109
92
|
if (selection instanceof TextSelection) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
93
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
94
|
+
// New implementation: unified handler for all text selections
|
|
95
|
+
selectionInfo = getSelectionInfo(selection, state.schema);
|
|
114
96
|
} else {
|
|
115
|
-
|
|
97
|
+
var $from = selection.$from,
|
|
98
|
+
$to = selection.$to;
|
|
99
|
+
if ($from.parent === $to.parent) {
|
|
100
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
101
|
+
}
|
|
116
102
|
}
|
|
117
103
|
} else if (selection instanceof CellSelection) {
|
|
118
104
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -124,17 +110,20 @@ export function getSelectionAdfInfo(state) {
|
|
|
124
110
|
});
|
|
125
111
|
}
|
|
126
112
|
export function getSelectionAdfInfoNew(selection) {
|
|
113
|
+
var schema = selection.$from.doc.type.schema;
|
|
127
114
|
var selectionInfo = {
|
|
128
115
|
selectedNode: selection.$from.node(),
|
|
129
116
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
130
117
|
};
|
|
131
118
|
if (selection instanceof TextSelection) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if ($from.parent === $to.parent) {
|
|
135
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
119
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
120
|
+
selectionInfo = getSelectionInfo(selection, schema);
|
|
136
121
|
} else {
|
|
137
|
-
|
|
122
|
+
var $from = selection.$from,
|
|
123
|
+
$to = selection.$to;
|
|
124
|
+
if ($from.parent === $to.parent) {
|
|
125
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
126
|
+
}
|
|
138
127
|
}
|
|
139
128
|
} else if (selection instanceof CellSelection) {
|
|
140
129
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
var LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
|
|
4
|
+
var LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find the depth of the deepest common ancestor node.
|
|
8
|
+
*/
|
|
9
|
+
var getCommonAncestorDepth = function getCommonAncestorDepth($from, $to) {
|
|
10
|
+
var minDepth = Math.min($from.depth, $to.depth);
|
|
11
|
+
for (var d = 0; d <= minDepth; d++) {
|
|
12
|
+
if ($from.node(d) !== $to.node(d)) {
|
|
13
|
+
return d - 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return minDepth;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Find the closest parent container node that contains the selection.
|
|
21
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
22
|
+
* - For other containers returns the closest one
|
|
23
|
+
* Returns the parent and its position.
|
|
24
|
+
*/
|
|
25
|
+
export var getCommonParentContainer = function getCommonParentContainer($from, $to) {
|
|
26
|
+
var commonDepth = getCommonAncestorDepth($from, $to);
|
|
27
|
+
|
|
28
|
+
// Single pass: look for topmost list OR first non-list parent
|
|
29
|
+
var topMostList = null;
|
|
30
|
+
var topMostListPos = -1;
|
|
31
|
+
var firstNonListParent = null;
|
|
32
|
+
var firstNonListParentPos = -1;
|
|
33
|
+
for (var depth = commonDepth; depth > 0; depth--) {
|
|
34
|
+
var node = $from.node(depth);
|
|
35
|
+
if (LIST_NODE_TYPES.has(node.type.name)) {
|
|
36
|
+
// Keep updating to find the topmost list (last one found going upward)
|
|
37
|
+
topMostList = node;
|
|
38
|
+
topMostListPos = $from.before(depth);
|
|
39
|
+
} else if (!firstNonListParent && node.type.name !== 'doc') {
|
|
40
|
+
// Only capture the first (innermost) non-list parent
|
|
41
|
+
firstNonListParent = node;
|
|
42
|
+
firstNonListParentPos = $from.before(depth);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Return topmost list if found, else first non-list parent
|
|
47
|
+
if (topMostList) {
|
|
48
|
+
return {
|
|
49
|
+
node: topMostList,
|
|
50
|
+
pos: topMostListPos
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
node: firstNonListParent,
|
|
55
|
+
pos: firstNonListParentPos
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
61
|
+
*/
|
|
62
|
+
export var wrapNodesInDoc = function wrapNodesInDoc(schema, nodes) {
|
|
63
|
+
if (nodes.length === 0) {
|
|
64
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Single node: return unwrapped
|
|
68
|
+
if (nodes.length === 1) {
|
|
69
|
+
return nodes[0];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// For multiple nodes, wrap in doc
|
|
73
|
+
try {
|
|
74
|
+
return schema.node('doc', null, Fragment.from(nodes));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logException(error, {
|
|
77
|
+
location: 'editor-plugin-selection-extension'
|
|
78
|
+
});
|
|
79
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
export var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
83
|
+
var $from = selection.$from,
|
|
84
|
+
$to = selection.$to;
|
|
85
|
+
return {
|
|
86
|
+
selectedNode: $from.node(),
|
|
87
|
+
selectionRanges: [{
|
|
88
|
+
start: {
|
|
89
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
90
|
+
position: $from.parentOffset
|
|
91
|
+
},
|
|
92
|
+
end: {
|
|
93
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
94
|
+
position: $to.parentOffset
|
|
95
|
+
}
|
|
96
|
+
}],
|
|
97
|
+
nodePos: $from.before()
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export var getSelectionInfo = function getSelectionInfo(selection, schema) {
|
|
101
|
+
var $from = selection.$from,
|
|
102
|
+
$to = selection.$to;
|
|
103
|
+
|
|
104
|
+
// For same parent selections, check for parent container
|
|
105
|
+
if ($from.parent === $to.parent) {
|
|
106
|
+
var _getCommonParentConta = getCommonParentContainer($from, $to),
|
|
107
|
+
parentNode = _getCommonParentConta.node,
|
|
108
|
+
parentNodePos = _getCommonParentConta.pos;
|
|
109
|
+
if (parentNode) {
|
|
110
|
+
return {
|
|
111
|
+
selectedNode: parentNode,
|
|
112
|
+
nodePos: parentNodePos
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
var nodePos = $from.before();
|
|
116
|
+
return {
|
|
117
|
+
selectedNode: $from.node(),
|
|
118
|
+
nodePos: nodePos
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// find the common ancestor
|
|
123
|
+
var range = $from.blockRange($to);
|
|
124
|
+
if (!range) {
|
|
125
|
+
return {
|
|
126
|
+
selectedNode: $from.node(),
|
|
127
|
+
nodePos: $from.depth > 0 ? $from.before() : $from.pos
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (range.parent.type.name !== 'doc') {
|
|
131
|
+
// If it's a list OR list item, check for topmost list parent
|
|
132
|
+
if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
|
|
133
|
+
var _getCommonParentConta2 = getCommonParentContainer($from, $to),
|
|
134
|
+
topList = _getCommonParentConta2.node,
|
|
135
|
+
topListPos = _getCommonParentConta2.pos;
|
|
136
|
+
if (topList) {
|
|
137
|
+
return {
|
|
138
|
+
selectedNode: topList,
|
|
139
|
+
nodePos: topListPos
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// For non-list containers (panel, expand, etc.), return the immediate parent
|
|
145
|
+
var _nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
|
|
146
|
+
return {
|
|
147
|
+
selectedNode: range.parent,
|
|
148
|
+
nodePos: _nodePos
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Extract complete nodes within the block range
|
|
153
|
+
var nodes = [];
|
|
154
|
+
for (var i = range.startIndex; i < range.endIndex; i++) {
|
|
155
|
+
nodes.push(range.parent.child(i));
|
|
156
|
+
}
|
|
157
|
+
var selectedNode = wrapNodesInDoc(schema, nodes);
|
|
158
|
+
return {
|
|
159
|
+
selectedNode: selectedNode,
|
|
160
|
+
nodePos: range.start
|
|
161
|
+
};
|
|
162
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Node as PMNode, type ResolvedPos, type Schema } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import type { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
/**
|
|
4
|
+
* Find the closest parent container node that contains the selection.
|
|
5
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
6
|
+
* - For other containers returns the closest one
|
|
7
|
+
* Returns the parent and its position.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getCommonParentContainer: ($from: ResolvedPos, $to: ResolvedPos) => {
|
|
10
|
+
node: PMNode | null;
|
|
11
|
+
pos: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
15
|
+
*/
|
|
16
|
+
export declare const wrapNodesInDoc: (schema: Schema, nodes: PMNode[]) => PMNode;
|
|
17
|
+
export declare const getSelectionInfoFromSameNode: (selection: TextSelection) => {
|
|
18
|
+
selectedNode: PMNode;
|
|
19
|
+
selectionRanges: {
|
|
20
|
+
start: {
|
|
21
|
+
pointer: string;
|
|
22
|
+
position: number;
|
|
23
|
+
};
|
|
24
|
+
end: {
|
|
25
|
+
pointer: string;
|
|
26
|
+
position: number;
|
|
27
|
+
};
|
|
28
|
+
}[];
|
|
29
|
+
nodePos: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const getSelectionInfo: (selection: TextSelection, schema: Schema) => {
|
|
32
|
+
selectedNode: PMNode;
|
|
33
|
+
nodePos: number;
|
|
34
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Node as PMNode, type ResolvedPos, type Schema } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import type { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
/**
|
|
4
|
+
* Find the closest parent container node that contains the selection.
|
|
5
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
6
|
+
* - For other containers returns the closest one
|
|
7
|
+
* Returns the parent and its position.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getCommonParentContainer: ($from: ResolvedPos, $to: ResolvedPos) => {
|
|
10
|
+
node: PMNode | null;
|
|
11
|
+
pos: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
15
|
+
*/
|
|
16
|
+
export declare const wrapNodesInDoc: (schema: Schema, nodes: PMNode[]) => PMNode;
|
|
17
|
+
export declare const getSelectionInfoFromSameNode: (selection: TextSelection) => {
|
|
18
|
+
selectedNode: PMNode;
|
|
19
|
+
selectionRanges: {
|
|
20
|
+
start: {
|
|
21
|
+
pointer: string;
|
|
22
|
+
position: number;
|
|
23
|
+
};
|
|
24
|
+
end: {
|
|
25
|
+
pointer: string;
|
|
26
|
+
position: number;
|
|
27
|
+
};
|
|
28
|
+
}[];
|
|
29
|
+
nodePos: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const getSelectionInfo: (selection: TextSelection, schema: Schema) => {
|
|
32
|
+
selectedNode: PMNode;
|
|
33
|
+
nodePos: number;
|
|
34
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-selection-extension",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.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",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@atlaskit/adf-utils": "^19.26.0",
|
|
36
36
|
"@atlaskit/editor-json-transformer": "^8.31.0",
|
|
37
37
|
"@atlaskit/editor-plugin-analytics": "^6.2.0",
|
|
38
|
-
"@atlaskit/editor-plugin-block-menu": "^5.
|
|
38
|
+
"@atlaskit/editor-plugin-block-menu": "^5.1.0",
|
|
39
39
|
"@atlaskit/editor-plugin-editor-viewmode": "^8.0.0",
|
|
40
40
|
"@atlaskit/editor-plugin-editor-viewmode-effects": "^6.1.0",
|
|
41
41
|
"@atlaskit/editor-plugin-primary-toolbar": "^7.0.0",
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"@atlaskit/icon": "^29.0.0",
|
|
50
50
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
51
51
|
"@atlaskit/platform-feature-flags-react": "^0.4.0",
|
|
52
|
-
"@atlaskit/tmp-editor-statsig": "^14.
|
|
52
|
+
"@atlaskit/tmp-editor-statsig": "^14.4.0",
|
|
53
53
|
"@babel/runtime": "^7.0.0",
|
|
54
54
|
"lodash": "^4.17.21",
|
|
55
55
|
"react-intl-next": "npm:react-intl@^5.18.1",
|
|
56
56
|
"uuid": "^3.1.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@atlaskit/editor-common": "^110.
|
|
59
|
+
"@atlaskit/editor-common": "^110.37.0",
|
|
60
60
|
"react": "^18.2.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
@@ -108,6 +108,9 @@
|
|
|
108
108
|
},
|
|
109
109
|
"platform_editor_use_preferences_plugin": {
|
|
110
110
|
"type": "boolean"
|
|
111
|
+
},
|
|
112
|
+
"platform_editor_selection_extension_improvement": {
|
|
113
|
+
"type": "boolean"
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
116
|
}
|