@atlaskit/editor-plugin-local-id 4.0.0 → 4.2.0

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,35 @@
1
1
  # @atlaskit/editor-plugin-local-id
2
2
 
3
+ ## 4.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`5167552fe1a93`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5167552fe1a93) -
8
+ [EDITOR-2339] Bump @atlaskit/adf-schema to 51.3.0
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
14
+ ## 4.1.0
15
+
16
+ ### Minor Changes
17
+
18
+ - [`1b290cb1f993b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1b290cb1f993b) -
19
+ Adds actions to get and replace nodes by their localId
20
+
21
+ ```ts
22
+ // Replace a local id with a ProseMirror node
23
+ api?.localId.actions.replaceNode({ localId: 'example-id', value: node });
24
+
25
+ // Get a prosemirror node based on its local id
26
+ api?.localId.actions.getNode({ localId: 'example-id' });
27
+ ```
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies
32
+
3
33
  ## 4.0.0
4
34
 
5
35
  ### Patch Changes
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findNodeByLocalId = findNodeByLocalId;
7
+ exports.replaceNode = exports.getNode = void 0;
8
+ function findNodeByLocalId(tr, localId) {
9
+ var result;
10
+ tr.doc.descendants(function (node, pos) {
11
+ if (result) {
12
+ return false;
13
+ }
14
+ if (node.attrs.localId === localId) {
15
+ result = {
16
+ node: node,
17
+ pos: pos
18
+ };
19
+ }
20
+ return result === undefined;
21
+ });
22
+ return result;
23
+ }
24
+ var replaceNode = exports.replaceNode = function replaceNode(api) {
25
+ return function (_ref) {
26
+ var _api$core$actions$exe;
27
+ var localId = _ref.localId,
28
+ value = _ref.value;
29
+ var nodeWithPos = getNode(api)({
30
+ localId: localId
31
+ });
32
+ if (!nodeWithPos) {
33
+ return false;
34
+ }
35
+ var pos = nodeWithPos.pos,
36
+ node = nodeWithPos.node;
37
+ return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(function (_ref2) {
38
+ var tr = _ref2.tr;
39
+ return tr.replaceWith(pos, pos + node.nodeSize, value).scrollIntoView();
40
+ })) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false;
41
+ };
42
+ };
43
+ var getNode = exports.getNode = function getNode(api) {
44
+ return function (_ref3) {
45
+ var localId = _ref3.localId;
46
+ var result;
47
+ api === null || api === void 0 || api.core.actions.execute(function (_ref4) {
48
+ var tr = _ref4.tr;
49
+ result = findNodeByLocalId(tr, localId);
50
+ return null;
51
+ });
52
+ return result;
53
+ };
54
+ };
@@ -4,10 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.localIdPlugin = void 0;
7
+ var _editorActions = require("./editor-actions");
7
8
  var _main = require("./pm-plugins/main");
8
- var localIdPlugin = exports.localIdPlugin = function localIdPlugin() {
9
+ var localIdPlugin = exports.localIdPlugin = function localIdPlugin(_ref) {
10
+ var api = _ref.api;
9
11
  return {
10
12
  name: 'localId',
13
+ actions: {
14
+ replaceNode: (0, _editorActions.replaceNode)(api),
15
+ getNode: (0, _editorActions.getNode)(api)
16
+ },
11
17
  pmPlugins: function pmPlugins() {
12
18
  return [{
13
19
  name: 'localIdPlugin',
@@ -1,10 +1,13 @@
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.localIdPluginKey = exports.createPlugin = exports.addLocalIdToNode = void 0;
7
+ exports.localIdPluginKey = exports.createPlugin = exports.batchAddLocalIdToNodes = exports.addLocalIdToNode = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
7
9
  var _adfSchema = require("@atlaskit/adf-schema");
10
+ var _steps = require("@atlaskit/adf-schema/steps");
8
11
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
9
12
  var _utils = require("@atlaskit/editor-common/utils");
10
13
  var _state = require("@atlaskit/editor-prosemirror/state");
@@ -35,6 +38,8 @@ var createPlugin = exports.createPlugin = function createPlugin() {
35
38
  requestIdleCallbackWithFallback(function () {
36
39
  var tr = editorView.state.tr;
37
40
  var localIdWasAdded = false;
41
+ var nodesToUpdate = new Map(); // position -> localId
42
+
38
43
  var _editorView$state$sch = editorView.state.schema.nodes,
39
44
  text = _editorView$state$sch.text,
40
45
  hardBreak = _editorView$state$sch.hardBreak,
@@ -45,14 +50,21 @@ var createPlugin = exports.createPlugin = function createPlugin() {
45
50
  editorView.state.doc.descendants(function (node, pos) {
46
51
  var _node$type$spec$attrs;
47
52
  if (!ignoredNodeTypes.includes(node.type.name) && !node.attrs.localId && !!((_node$type$spec$attrs = node.type.spec.attrs) !== null && _node$type$spec$attrs !== void 0 && _node$type$spec$attrs.localId)) {
48
- localIdWasAdded = true;
49
- addLocalIdToNode(pos, tr);
53
+ if ((0, _platformFeatureFlags.fg)('platform_editor_localid_improvements')) {
54
+ nodesToUpdate.set(pos, _adfSchema.uuid.generate());
55
+ } else {
56
+ localIdWasAdded = true;
57
+ addLocalIdToNode(pos, tr);
58
+ }
50
59
  }
51
60
  return true; // Continue traversing
52
61
  });
53
-
54
- // Only dispatch the transaction if we actually added local IDs
55
- if (localIdWasAdded) {
62
+ if ((0, _platformFeatureFlags.fg)('platform_editor_localid_improvements')) {
63
+ if (nodesToUpdate.size > 0) {
64
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
65
+ editorView.dispatch(tr);
66
+ }
67
+ } else if (localIdWasAdded) {
56
68
  tr.setMeta('addToHistory', false);
57
69
  editorView.dispatch(tr);
58
70
  }
@@ -78,6 +90,7 @@ var createPlugin = exports.createPlugin = function createPlugin() {
78
90
  var addedNodes = new Set();
79
91
  var addedNodePos = new Map();
80
92
  var localIds = new Set();
93
+ var nodesToUpdate = new Map(); // position -> localId
81
94
 
82
95
  // Process only the nodes added in the transactions
83
96
  transactions.forEach(function (transaction) {
@@ -114,7 +127,12 @@ var createPlugin = exports.createPlugin = function createPlugin() {
114
127
  addedNodePos.set(node, pos);
115
128
  } else {
116
129
  if (!(node !== null && node !== void 0 && node.attrs.localId)) {
117
- addLocalIdToNode(pos, tr);
130
+ if ((0, _platformFeatureFlags.fg)('platform_editor_localid_improvements')) {
131
+ nodesToUpdate.set(pos, _adfSchema.uuid.generate());
132
+ } else {
133
+ // Legacy behavior - individual steps
134
+ addLocalIdToNode(pos, tr);
135
+ }
118
136
  }
119
137
  }
120
138
  return true;
@@ -138,7 +156,11 @@ var createPlugin = exports.createPlugin = function createPlugin() {
138
156
  if (!node.attrs.localId || localIds.has(node.attrs.localId)) {
139
157
  var pos = addedNodePos.get(node);
140
158
  if (pos !== undefined) {
141
- addLocalIdToNode(pos, tr);
159
+ if ((0, _platformFeatureFlags.fg)('platform_editor_localid_improvements')) {
160
+ nodesToUpdate.set(pos, _adfSchema.uuid.generate());
161
+ } else {
162
+ addLocalIdToNode(pos, tr);
163
+ }
142
164
  modified = true;
143
165
  }
144
166
  }
@@ -149,6 +171,13 @@ var createPlugin = exports.createPlugin = function createPlugin() {
149
171
  _iterator.f();
150
172
  }
151
173
  }
174
+
175
+ // Apply local ID updates based on the improvements feature flag:
176
+ // - When enabled: Batch all updates into a single BatchAttrsStep
177
+ // - When disabled: Individual steps were already applied above during node processing
178
+ if (modified && nodesToUpdate.size > 0 && (0, _platformFeatureFlags.fg)('platform_editor_localid_improvements')) {
179
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
180
+ }
152
181
  return modified ? tr : undefined;
153
182
  }
154
183
  });
@@ -164,4 +193,30 @@ var createPlugin = exports.createPlugin = function createPlugin() {
164
193
  var addLocalIdToNode = exports.addLocalIdToNode = function addLocalIdToNode(pos, tr) {
165
194
  tr.setNodeAttribute(pos, 'localId', _adfSchema.uuid.generate());
166
195
  tr.setMeta('addToHistory', false);
196
+ };
197
+
198
+ /**
199
+ * Batch adds local IDs to nodes using a BatchAttrsStep
200
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
201
+ * @param tr
202
+ */
203
+ var batchAddLocalIdToNodes = exports.batchAddLocalIdToNodes = function batchAddLocalIdToNodes(nodesToUpdate, tr) {
204
+ var batchData = Array.from(nodesToUpdate.entries()).map(function (_ref) {
205
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
206
+ pos = _ref2[0],
207
+ localId = _ref2[1];
208
+ var node = tr.doc.nodeAt(pos);
209
+ if (!node) {
210
+ throw new Error("Node does not exist at position ".concat(pos));
211
+ }
212
+ return {
213
+ position: pos,
214
+ attrs: {
215
+ localId: localId
216
+ },
217
+ nodeType: node.type.name
218
+ };
219
+ });
220
+ tr.step(new _steps.BatchAttrsStep(batchData));
221
+ tr.setMeta('addToHistory', false);
167
222
  };
@@ -0,0 +1,47 @@
1
+ export function findNodeByLocalId(tr, localId) {
2
+ let result;
3
+ tr.doc.descendants((node, pos) => {
4
+ if (result) {
5
+ return false;
6
+ }
7
+ if (node.attrs.localId === localId) {
8
+ result = {
9
+ node,
10
+ pos
11
+ };
12
+ }
13
+ return result === undefined;
14
+ });
15
+ return result;
16
+ }
17
+ export const replaceNode = api => ({
18
+ localId,
19
+ value
20
+ }) => {
21
+ var _api$core$actions$exe;
22
+ const nodeWithPos = getNode(api)({
23
+ localId
24
+ });
25
+ if (!nodeWithPos) {
26
+ return false;
27
+ }
28
+ const {
29
+ pos,
30
+ node
31
+ } = nodeWithPos;
32
+ return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(({
33
+ tr
34
+ }) => tr.replaceWith(pos, pos + node.nodeSize, value).scrollIntoView())) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false;
35
+ };
36
+ export const getNode = api => ({
37
+ localId
38
+ }) => {
39
+ let result;
40
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(({
41
+ tr
42
+ }) => {
43
+ result = findNodeByLocalId(tr, localId);
44
+ return null;
45
+ });
46
+ return result;
47
+ };
@@ -1,6 +1,13 @@
1
+ import { replaceNode, getNode } from './editor-actions';
1
2
  import { createPlugin } from './pm-plugins/main';
2
- export const localIdPlugin = () => ({
3
+ export const localIdPlugin = ({
4
+ api
5
+ }) => ({
3
6
  name: 'localId',
7
+ actions: {
8
+ replaceNode: replaceNode(api),
9
+ getNode: getNode(api)
10
+ },
4
11
  pmPlugins() {
5
12
  return [{
6
13
  name: 'localIdPlugin',
@@ -1,4 +1,5 @@
1
1
  import { uuid } from '@atlaskit/adf-schema';
2
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
2
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
4
  import { stepHasSlice } from '@atlaskit/editor-common/utils';
4
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
@@ -26,6 +27,8 @@ export const createPlugin = () => {
26
27
  requestIdleCallbackWithFallback(() => {
27
28
  const tr = editorView.state.tr;
28
29
  let localIdWasAdded = false;
30
+ const nodesToUpdate = new Map(); // position -> localId
31
+
29
32
  const {
30
33
  text,
31
34
  hardBreak,
@@ -37,14 +40,21 @@ export const createPlugin = () => {
37
40
  editorView.state.doc.descendants((node, pos) => {
38
41
  var _node$type$spec$attrs;
39
42
  if (!ignoredNodeTypes.includes(node.type.name) && !node.attrs.localId && !!((_node$type$spec$attrs = node.type.spec.attrs) !== null && _node$type$spec$attrs !== void 0 && _node$type$spec$attrs.localId)) {
40
- localIdWasAdded = true;
41
- addLocalIdToNode(pos, tr);
43
+ if (fg('platform_editor_localid_improvements')) {
44
+ nodesToUpdate.set(pos, uuid.generate());
45
+ } else {
46
+ localIdWasAdded = true;
47
+ addLocalIdToNode(pos, tr);
48
+ }
42
49
  }
43
50
  return true; // Continue traversing
44
51
  });
45
-
46
- // Only dispatch the transaction if we actually added local IDs
47
- if (localIdWasAdded) {
52
+ if (fg('platform_editor_localid_improvements')) {
53
+ if (nodesToUpdate.size > 0) {
54
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
55
+ editorView.dispatch(tr);
56
+ }
57
+ } else if (localIdWasAdded) {
48
58
  tr.setMeta('addToHistory', false);
49
59
  editorView.dispatch(tr);
50
60
  }
@@ -71,6 +81,7 @@ export const createPlugin = () => {
71
81
  const addedNodes = new Set();
72
82
  const addedNodePos = new Map();
73
83
  const localIds = new Set();
84
+ const nodesToUpdate = new Map(); // position -> localId
74
85
 
75
86
  // Process only the nodes added in the transactions
76
87
  transactions.forEach(transaction => {
@@ -107,7 +118,12 @@ export const createPlugin = () => {
107
118
  addedNodePos.set(node, pos);
108
119
  } else {
109
120
  if (!(node !== null && node !== void 0 && node.attrs.localId)) {
110
- addLocalIdToNode(pos, tr);
121
+ if (fg('platform_editor_localid_improvements')) {
122
+ nodesToUpdate.set(pos, uuid.generate());
123
+ } else {
124
+ // Legacy behavior - individual steps
125
+ addLocalIdToNode(pos, tr);
126
+ }
111
127
  }
112
128
  }
113
129
  return true;
@@ -127,12 +143,23 @@ export const createPlugin = () => {
127
143
  if (!node.attrs.localId || localIds.has(node.attrs.localId)) {
128
144
  const pos = addedNodePos.get(node);
129
145
  if (pos !== undefined) {
130
- addLocalIdToNode(pos, tr);
146
+ if (fg('platform_editor_localid_improvements')) {
147
+ nodesToUpdate.set(pos, uuid.generate());
148
+ } else {
149
+ addLocalIdToNode(pos, tr);
150
+ }
131
151
  modified = true;
132
152
  }
133
153
  }
134
154
  }
135
155
  }
156
+
157
+ // Apply local ID updates based on the improvements feature flag:
158
+ // - When enabled: Batch all updates into a single BatchAttrsStep
159
+ // - When disabled: Individual steps were already applied above during node processing
160
+ if (modified && nodesToUpdate.size > 0 && fg('platform_editor_localid_improvements')) {
161
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
162
+ }
136
163
  return modified ? tr : undefined;
137
164
  }
138
165
  });
@@ -148,4 +175,27 @@ export const createPlugin = () => {
148
175
  export const addLocalIdToNode = (pos, tr) => {
149
176
  tr.setNodeAttribute(pos, 'localId', uuid.generate());
150
177
  tr.setMeta('addToHistory', false);
178
+ };
179
+
180
+ /**
181
+ * Batch adds local IDs to nodes using a BatchAttrsStep
182
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
183
+ * @param tr
184
+ */
185
+ export const batchAddLocalIdToNodes = (nodesToUpdate, tr) => {
186
+ const batchData = Array.from(nodesToUpdate.entries()).map(([pos, localId]) => {
187
+ const node = tr.doc.nodeAt(pos);
188
+ if (!node) {
189
+ throw new Error(`Node does not exist at position ${pos}`);
190
+ }
191
+ return {
192
+ position: pos,
193
+ attrs: {
194
+ localId
195
+ },
196
+ nodeType: node.type.name
197
+ };
198
+ });
199
+ tr.step(new BatchAttrsStep(batchData));
200
+ tr.setMeta('addToHistory', false);
151
201
  };
@@ -0,0 +1,47 @@
1
+ export function findNodeByLocalId(tr, localId) {
2
+ var result;
3
+ tr.doc.descendants(function (node, pos) {
4
+ if (result) {
5
+ return false;
6
+ }
7
+ if (node.attrs.localId === localId) {
8
+ result = {
9
+ node: node,
10
+ pos: pos
11
+ };
12
+ }
13
+ return result === undefined;
14
+ });
15
+ return result;
16
+ }
17
+ export var replaceNode = function replaceNode(api) {
18
+ return function (_ref) {
19
+ var _api$core$actions$exe;
20
+ var localId = _ref.localId,
21
+ value = _ref.value;
22
+ var nodeWithPos = getNode(api)({
23
+ localId: localId
24
+ });
25
+ if (!nodeWithPos) {
26
+ return false;
27
+ }
28
+ var pos = nodeWithPos.pos,
29
+ node = nodeWithPos.node;
30
+ return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(function (_ref2) {
31
+ var tr = _ref2.tr;
32
+ return tr.replaceWith(pos, pos + node.nodeSize, value).scrollIntoView();
33
+ })) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false;
34
+ };
35
+ };
36
+ export var getNode = function getNode(api) {
37
+ return function (_ref3) {
38
+ var localId = _ref3.localId;
39
+ var result;
40
+ api === null || api === void 0 || api.core.actions.execute(function (_ref4) {
41
+ var tr = _ref4.tr;
42
+ result = findNodeByLocalId(tr, localId);
43
+ return null;
44
+ });
45
+ return result;
46
+ };
47
+ };
@@ -1,7 +1,13 @@
1
+ import { replaceNode, getNode } from './editor-actions';
1
2
  import { createPlugin } from './pm-plugins/main';
2
- export var localIdPlugin = function localIdPlugin() {
3
+ export var localIdPlugin = function localIdPlugin(_ref) {
4
+ var api = _ref.api;
3
5
  return {
4
6
  name: 'localId',
7
+ actions: {
8
+ replaceNode: replaceNode(api),
9
+ getNode: getNode(api)
10
+ },
5
11
  pmPlugins: function pmPlugins() {
6
12
  return [{
7
13
  name: 'localIdPlugin',
@@ -1,7 +1,9 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
1
2
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
2
3
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
5
  import { uuid } from '@atlaskit/adf-schema';
6
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
5
7
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
8
  import { stepHasSlice } from '@atlaskit/editor-common/utils';
7
9
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
@@ -29,6 +31,8 @@ export var createPlugin = function createPlugin() {
29
31
  requestIdleCallbackWithFallback(function () {
30
32
  var tr = editorView.state.tr;
31
33
  var localIdWasAdded = false;
34
+ var nodesToUpdate = new Map(); // position -> localId
35
+
32
36
  var _editorView$state$sch = editorView.state.schema.nodes,
33
37
  text = _editorView$state$sch.text,
34
38
  hardBreak = _editorView$state$sch.hardBreak,
@@ -39,14 +43,21 @@ export var createPlugin = function createPlugin() {
39
43
  editorView.state.doc.descendants(function (node, pos) {
40
44
  var _node$type$spec$attrs;
41
45
  if (!ignoredNodeTypes.includes(node.type.name) && !node.attrs.localId && !!((_node$type$spec$attrs = node.type.spec.attrs) !== null && _node$type$spec$attrs !== void 0 && _node$type$spec$attrs.localId)) {
42
- localIdWasAdded = true;
43
- addLocalIdToNode(pos, tr);
46
+ if (fg('platform_editor_localid_improvements')) {
47
+ nodesToUpdate.set(pos, uuid.generate());
48
+ } else {
49
+ localIdWasAdded = true;
50
+ addLocalIdToNode(pos, tr);
51
+ }
44
52
  }
45
53
  return true; // Continue traversing
46
54
  });
47
-
48
- // Only dispatch the transaction if we actually added local IDs
49
- if (localIdWasAdded) {
55
+ if (fg('platform_editor_localid_improvements')) {
56
+ if (nodesToUpdate.size > 0) {
57
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
58
+ editorView.dispatch(tr);
59
+ }
60
+ } else if (localIdWasAdded) {
50
61
  tr.setMeta('addToHistory', false);
51
62
  editorView.dispatch(tr);
52
63
  }
@@ -72,6 +83,7 @@ export var createPlugin = function createPlugin() {
72
83
  var addedNodes = new Set();
73
84
  var addedNodePos = new Map();
74
85
  var localIds = new Set();
86
+ var nodesToUpdate = new Map(); // position -> localId
75
87
 
76
88
  // Process only the nodes added in the transactions
77
89
  transactions.forEach(function (transaction) {
@@ -108,7 +120,12 @@ export var createPlugin = function createPlugin() {
108
120
  addedNodePos.set(node, pos);
109
121
  } else {
110
122
  if (!(node !== null && node !== void 0 && node.attrs.localId)) {
111
- addLocalIdToNode(pos, tr);
123
+ if (fg('platform_editor_localid_improvements')) {
124
+ nodesToUpdate.set(pos, uuid.generate());
125
+ } else {
126
+ // Legacy behavior - individual steps
127
+ addLocalIdToNode(pos, tr);
128
+ }
112
129
  }
113
130
  }
114
131
  return true;
@@ -132,7 +149,11 @@ export var createPlugin = function createPlugin() {
132
149
  if (!node.attrs.localId || localIds.has(node.attrs.localId)) {
133
150
  var pos = addedNodePos.get(node);
134
151
  if (pos !== undefined) {
135
- addLocalIdToNode(pos, tr);
152
+ if (fg('platform_editor_localid_improvements')) {
153
+ nodesToUpdate.set(pos, uuid.generate());
154
+ } else {
155
+ addLocalIdToNode(pos, tr);
156
+ }
136
157
  modified = true;
137
158
  }
138
159
  }
@@ -143,6 +164,13 @@ export var createPlugin = function createPlugin() {
143
164
  _iterator.f();
144
165
  }
145
166
  }
167
+
168
+ // Apply local ID updates based on the improvements feature flag:
169
+ // - When enabled: Batch all updates into a single BatchAttrsStep
170
+ // - When disabled: Individual steps were already applied above during node processing
171
+ if (modified && nodesToUpdate.size > 0 && fg('platform_editor_localid_improvements')) {
172
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
173
+ }
146
174
  return modified ? tr : undefined;
147
175
  }
148
176
  });
@@ -158,4 +186,30 @@ export var createPlugin = function createPlugin() {
158
186
  export var addLocalIdToNode = function addLocalIdToNode(pos, tr) {
159
187
  tr.setNodeAttribute(pos, 'localId', uuid.generate());
160
188
  tr.setMeta('addToHistory', false);
189
+ };
190
+
191
+ /**
192
+ * Batch adds local IDs to nodes using a BatchAttrsStep
193
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
194
+ * @param tr
195
+ */
196
+ export var batchAddLocalIdToNodes = function batchAddLocalIdToNodes(nodesToUpdate, tr) {
197
+ var batchData = Array.from(nodesToUpdate.entries()).map(function (_ref) {
198
+ var _ref2 = _slicedToArray(_ref, 2),
199
+ pos = _ref2[0],
200
+ localId = _ref2[1];
201
+ var node = tr.doc.nodeAt(pos);
202
+ if (!node) {
203
+ throw new Error("Node does not exist at position ".concat(pos));
204
+ }
205
+ return {
206
+ position: pos,
207
+ attrs: {
208
+ localId: localId
209
+ },
210
+ nodeType: node.type.name
211
+ };
212
+ });
213
+ tr.step(new BatchAttrsStep(batchData));
214
+ tr.setMeta('addToHistory', false);
161
215
  };
@@ -0,0 +1,12 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { Node } from '@atlaskit/editor-prosemirror/model';
3
+ import type { Transform } from '@atlaskit/editor-prosemirror/transform';
4
+ import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
5
+ import type { ActionProps, LocalIdPlugin } from '../localIdPluginType';
6
+ type EditorActionProps = ActionProps;
7
+ export declare function findNodeByLocalId(tr: Transform, localId: string): NodeWithPos | undefined;
8
+ export declare const replaceNode: (api: ExtractInjectionAPI<LocalIdPlugin> | undefined) => ({ localId, value }: EditorActionProps & {
9
+ value: Node;
10
+ }) => boolean;
11
+ export declare const getNode: (api: ExtractInjectionAPI<LocalIdPlugin> | undefined) => ({ localId }: EditorActionProps) => NodeWithPos | undefined;
12
+ export {};
@@ -1,2 +1,27 @@
1
1
  import type { NextEditorPlugin } from '@atlaskit/editor-common/types';
2
- export type LocalIdPlugin = NextEditorPlugin<'localId'>;
2
+ import type { Node } from '@atlaskit/editor-prosemirror/model';
3
+ import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
4
+ export type ActionProps = {
5
+ localId: string;
6
+ };
7
+ export type LocalIdPlugin = NextEditorPlugin<'localId', {
8
+ actions: {
9
+ /**
10
+ * Get the node with its position in the document
11
+ *
12
+ * @param props.localId Local id of the node in question
13
+ * @returns { node: ProsemirrorNode, pos: number } Object containing prosemirror node and position in the document
14
+ */
15
+ getNode: (props: ActionProps) => NodeWithPos | undefined;
16
+ /**
17
+ * Replace the node in the document by its local id
18
+ *
19
+ * @param props.localId Local id of the node in question
20
+ * @param props.value Prosemirror node to replace the node with
21
+ * @returns boolean if the replace was successful
22
+ */
23
+ replaceNode: (props: ActionProps & {
24
+ value: Node;
25
+ }) => boolean;
26
+ };
27
+ }>;
@@ -11,3 +11,9 @@ export declare const createPlugin: () => SafePlugin<any>;
11
11
  * @param tr - The transaction to apply the change to
12
12
  */
13
13
  export declare const addLocalIdToNode: (pos: number, tr: Transaction) => void;
14
+ /**
15
+ * Batch adds local IDs to nodes using a BatchAttrsStep
16
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
17
+ * @param tr
18
+ */
19
+ export declare const batchAddLocalIdToNodes: (nodesToUpdate: Map<number, string>, tr: Transaction) => void;
@@ -0,0 +1,12 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import type { Node } from '@atlaskit/editor-prosemirror/model';
3
+ import type { Transform } from '@atlaskit/editor-prosemirror/transform';
4
+ import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
5
+ import type { ActionProps, LocalIdPlugin } from '../localIdPluginType';
6
+ type EditorActionProps = ActionProps;
7
+ export declare function findNodeByLocalId(tr: Transform, localId: string): NodeWithPos | undefined;
8
+ export declare const replaceNode: (api: ExtractInjectionAPI<LocalIdPlugin> | undefined) => ({ localId, value }: EditorActionProps & {
9
+ value: Node;
10
+ }) => boolean;
11
+ export declare const getNode: (api: ExtractInjectionAPI<LocalIdPlugin> | undefined) => ({ localId }: EditorActionProps) => NodeWithPos | undefined;
12
+ export {};
@@ -1,2 +1,27 @@
1
1
  import type { NextEditorPlugin } from '@atlaskit/editor-common/types';
2
- export type LocalIdPlugin = NextEditorPlugin<'localId'>;
2
+ import type { Node } from '@atlaskit/editor-prosemirror/model';
3
+ import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
4
+ export type ActionProps = {
5
+ localId: string;
6
+ };
7
+ export type LocalIdPlugin = NextEditorPlugin<'localId', {
8
+ actions: {
9
+ /**
10
+ * Get the node with its position in the document
11
+ *
12
+ * @param props.localId Local id of the node in question
13
+ * @returns { node: ProsemirrorNode, pos: number } Object containing prosemirror node and position in the document
14
+ */
15
+ getNode: (props: ActionProps) => NodeWithPos | undefined;
16
+ /**
17
+ * Replace the node in the document by its local id
18
+ *
19
+ * @param props.localId Local id of the node in question
20
+ * @param props.value Prosemirror node to replace the node with
21
+ * @returns boolean if the replace was successful
22
+ */
23
+ replaceNode: (props: ActionProps & {
24
+ value: Node;
25
+ }) => boolean;
26
+ };
27
+ }>;
@@ -11,3 +11,9 @@ export declare const createPlugin: () => SafePlugin<any>;
11
11
  * @param tr - The transaction to apply the change to
12
12
  */
13
13
  export declare const addLocalIdToNode: (pos: number, tr: Transaction) => void;
14
+ /**
15
+ * Batch adds local IDs to nodes using a BatchAttrsStep
16
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
17
+ * @param tr
18
+ */
19
+ export declare const batchAddLocalIdToNodes: (nodesToUpdate: Map<number, string>, tr: Transaction) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-local-id",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "LocalId plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -28,14 +28,14 @@
28
28
  "sideEffects": false,
29
29
  "atlaskit:src": "src/index.ts",
30
30
  "dependencies": {
31
- "@atlaskit/adf-schema": "^51.2.0",
31
+ "@atlaskit/adf-schema": "^51.3.0",
32
32
  "@atlaskit/editor-prosemirror": "7.0.0",
33
33
  "@atlaskit/platform-feature-flags": "^1.1.0",
34
34
  "@babel/runtime": "^7.0.0",
35
35
  "raf-schd": "^4.0.3"
36
36
  },
37
37
  "peerDependencies": {
38
- "@atlaskit/editor-common": "^110.0.0",
38
+ "@atlaskit/editor-common": "^110.14.0",
39
39
  "react": "^18.2.0"
40
40
  },
41
41
  "devDependencies": {
@@ -80,6 +80,9 @@
80
80
  "platform-feature-flags": {
81
81
  "platform_editor_use_localid_dedupe": {
82
82
  "type": "boolean"
83
+ },
84
+ "platform_editor_localid_improvements": {
85
+ "type": "boolean"
83
86
  }
84
87
  }
85
88
  }