@ckeditor/ckeditor5-typing 45.0.0 → 45.1.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-typing",
3
- "version": "45.0.0",
3
+ "version": "45.1.0-alpha.0",
4
4
  "description": "Typing feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -13,9 +13,9 @@
13
13
  "type": "module",
14
14
  "main": "src/index.js",
15
15
  "dependencies": {
16
- "@ckeditor/ckeditor5-core": "45.0.0",
17
- "@ckeditor/ckeditor5-engine": "45.0.0",
18
- "@ckeditor/ckeditor5-utils": "45.0.0",
16
+ "@ckeditor/ckeditor5-core": "45.1.0-alpha.0",
17
+ "@ckeditor/ckeditor5-engine": "45.1.0-alpha.0",
18
+ "@ckeditor/ckeditor5-utils": "45.1.0-alpha.0",
19
19
  "es-toolkit": "1.32.0"
20
20
  },
21
21
  "author": "CKSource (http://cksource.com/)",
package/src/delete.js CHANGED
@@ -2,6 +2,10 @@
2
2
  * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
+ /**
6
+ * @module typing/delete
7
+ */
8
+ import { BubblingEventInfo, DomEventData } from '@ckeditor/ckeditor5-engine';
5
9
  import { Plugin } from '@ckeditor/ckeditor5-core';
6
10
  import { keyCodes } from '@ckeditor/ckeditor5-utils';
7
11
  import DeleteCommand from './deletecommand.js';
@@ -73,7 +77,22 @@ export default class Delete extends Plugin {
73
77
  const ancestorLimit = editor.model.schema.getLimitElement(modelDocument.selection);
74
78
  const limitStartPosition = editor.model.createPositionAt(ancestorLimit, 0);
75
79
  if (limitStartPosition.isTouching(modelDocument.selection.getFirstPosition())) {
80
+ // Stop the beforeinput event as it could be invalid.
76
81
  data.preventDefault();
82
+ // Create a fake delete event so all features can act on it and the target range is proper.
83
+ const modelRange = editor.model.schema.getNearestSelectionRange(limitStartPosition, 'forward');
84
+ if (!modelRange) {
85
+ return;
86
+ }
87
+ const viewSelection = view.createSelection(editor.editing.mapper.toViewRange(modelRange));
88
+ const targetRange = viewSelection.getFirstRange();
89
+ const eventInfo = new BubblingEventInfo(document, 'delete', targetRange);
90
+ const deleteData = {
91
+ unit: 'selection',
92
+ direction: 'backward',
93
+ selectionToRemove: viewSelection
94
+ };
95
+ viewDocument.fire(eventInfo, new DomEventData(view, data.domEvent, deleteData));
77
96
  }
78
97
  });
79
98
  if (this.editor.plugins.has('UndoEditing')) {
package/src/input.d.ts CHANGED
@@ -13,7 +13,7 @@ export default class Input extends Plugin {
13
13
  /**
14
14
  * The queue of `insertText` command executions that are waiting for the DOM to get updated after beforeinput event.
15
15
  */
16
- private _compositionQueue;
16
+ private _typingQueue;
17
17
  /**
18
18
  * @inheritDoc
19
19
  */
package/src/input.js CHANGED
@@ -19,7 +19,7 @@ export default class Input extends Plugin {
19
19
  /**
20
20
  * The queue of `insertText` command executions that are waiting for the DOM to get updated after beforeinput event.
21
21
  */
22
- _compositionQueue;
22
+ _typingQueue;
23
23
  /**
24
24
  * @inheritDoc
25
25
  */
@@ -41,25 +41,34 @@ export default class Input extends Plugin {
41
41
  const view = editor.editing.view;
42
42
  const mapper = editor.editing.mapper;
43
43
  const modelSelection = model.document.selection;
44
- this._compositionQueue = new CompositionQueue(editor);
44
+ this._typingQueue = new TypingQueue(editor);
45
45
  view.addObserver(InsertTextObserver);
46
46
  // TODO The above default configuration value should be defined using editor.config.define() once it's fixed.
47
47
  const insertTextCommand = new InsertTextCommand(editor, editor.config.get('typing.undoStep') || 20);
48
48
  // Register `insertText` command and add `input` command as an alias for backward compatibility.
49
49
  editor.commands.add('insertText', insertTextCommand);
50
50
  editor.commands.add('input', insertTextCommand);
51
+ this.listenTo(view.document, 'beforeinput', () => {
52
+ // Flush queue on the next beforeinput event because it could happen
53
+ // that the mutation observer does not notice the DOM change in time.
54
+ this._typingQueue.flush('next beforeinput');
55
+ }, { priority: 'high' });
51
56
  this.listenTo(view.document, 'insertText', (evt, data) => {
52
- // Rendering is disabled while composing so prevent events that will be rendered by the engine
53
- // and should not be applied by the browser.
54
- if (!view.document.isComposing) {
57
+ const { text, selection: viewSelection } = data;
58
+ // In case of a synthetic event, make sure that selection is not fake.
59
+ if (view.document.selection.isFake && viewSelection && view.document.selection.isSimilar(viewSelection)) {
55
60
  data.preventDefault();
56
61
  }
57
- // Flush queue on the next beforeinput event because it could happen
58
- // that the mutation observer does not notice the DOM change in time.
59
- if (env.isAndroid && view.document.isComposing) {
60
- this._compositionQueue.flush('next beforeinput');
62
+ if (!insertTextCommand.isEnabled) {
63
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
64
+ // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
65
+ // @if CK_DEBUG_TYPING // '%cInsertText command is disabled - prevent DOM change.',
66
+ // @if CK_DEBUG_TYPING // 'font-style: italic'
67
+ // @if CK_DEBUG_TYPING // ) );
68
+ // @if CK_DEBUG_TYPING // }
69
+ data.preventDefault();
70
+ return;
61
71
  }
62
- const { text, selection: viewSelection } = data;
63
72
  let modelRanges;
64
73
  // If view selection was specified, translate it to model selection.
65
74
  if (viewSelection) {
@@ -100,41 +109,31 @@ export default class Input extends Plugin {
100
109
  return;
101
110
  }
102
111
  }
112
+ // Note: the TypingQueue stores live-ranges internally as RTC could change the model while waiting for mutations.
103
113
  const commandData = {
104
114
  text: insertText,
105
115
  selection: model.createSelection(modelRanges)
106
116
  };
107
- // This is a composition event and those are not cancellable, so we need to wait until browser updates the DOM
117
+ // This is a beforeinput event, so we need to wait until the browser updates the DOM,
108
118
  // and we could apply changes to the model and verify if the DOM is valid.
109
119
  // The browser applies changes to the DOM not immediately on beforeinput event.
110
120
  // We just wait for mutation observer to notice changes or as a fallback a timeout.
111
- if (env.isAndroid && view.document.isComposing) {
112
- // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
113
- // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
114
- // @if CK_DEBUG_TYPING // `%cQueue insertText:%c "${ commandData.text }"%c ` +
115
- // @if CK_DEBUG_TYPING // `[${ commandData.selection.getFirstPosition().path }]-` +
116
- // @if CK_DEBUG_TYPING // `[${ commandData.selection.getLastPosition().path }]` +
117
- // @if CK_DEBUG_TYPING // ` queue size: ${ this._compositionQueue.length + 1 }`,
118
- // @if CK_DEBUG_TYPING // 'font-weight: bold',
119
- // @if CK_DEBUG_TYPING // 'color: blue',
120
- // @if CK_DEBUG_TYPING // ''
121
- // @if CK_DEBUG_TYPING // ) );
122
- // @if CK_DEBUG_TYPING // }
123
- this._compositionQueue.push(commandData);
124
- }
125
- else {
126
- // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
127
- // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
128
- // @if CK_DEBUG_TYPING // `%cExecute insertText:%c "${ commandData.text }"%c ` +
129
- // @if CK_DEBUG_TYPING // `[${ commandData.selection.getFirstPosition().path }]-` +
130
- // @if CK_DEBUG_TYPING // `[${ commandData.selection.getLastPosition().path }]`,
131
- // @if CK_DEBUG_TYPING // 'font-weight: bold',
132
- // @if CK_DEBUG_TYPING // 'color: blue',
133
- // @if CK_DEBUG_TYPING // ''
134
- // @if CK_DEBUG_TYPING // ) );
135
- // @if CK_DEBUG_TYPING // }
136
- editor.execute('insertText', commandData);
137
- view.scrollToTheSelection();
121
+ //
122
+ // Previously we were cancelling the non-composition events, but it caused issues especially in Safari.
123
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
124
+ // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
125
+ // @if CK_DEBUG_TYPING // `%cQueue insertText:%c "${ commandData.text }"%c ` +
126
+ // @if CK_DEBUG_TYPING // `[${ commandData.selection.getFirstPosition().path }]-` +
127
+ // @if CK_DEBUG_TYPING // `[${ commandData.selection.getLastPosition().path }]` +
128
+ // @if CK_DEBUG_TYPING // ` queue size: ${ this._typingQueue.length + 1 }`,
129
+ // @if CK_DEBUG_TYPING // 'font-weight: bold',
130
+ // @if CK_DEBUG_TYPING // 'color: blue',
131
+ // @if CK_DEBUG_TYPING // ''
132
+ // @if CK_DEBUG_TYPING // ) );
133
+ // @if CK_DEBUG_TYPING // }
134
+ this._typingQueue.push(commandData, Boolean(data.isComposing));
135
+ if (data.domEvent.defaultPrevented) {
136
+ this._typingQueue.flush('beforeinput default prevented');
138
137
  }
139
138
  });
140
139
  // Delete selected content on composition start.
@@ -177,102 +176,91 @@ export default class Input extends Plugin {
177
176
  // @if CK_DEBUG_TYPING // ) );
178
177
  // @if CK_DEBUG_TYPING // }
179
178
  deleteSelectionContent(model, insertTextCommand);
180
- });
179
+ }, { priority: 'high' });
181
180
  }
182
- // Apply composed changes to the model.
183
- if (env.isAndroid) {
184
- // Apply changes to the model as they are applied to the DOM by the browser.
185
- // On beforeinput event, the DOM is not yet modified. We wait for detected mutations to apply model changes.
186
- this.listenTo(view.document, 'mutations', (evt, { mutations }) => {
187
- if (!view.document.isComposing) {
188
- return;
189
- }
190
- // Check if mutations are relevant for queued changes.
181
+ // Apply changes to the model as they are applied to the DOM by the browser.
182
+ // On beforeinput event, the DOM is not yet modified. We wait for detected mutations to apply model changes.
183
+ this.listenTo(view.document, 'mutations', (evt, { mutations }) => {
184
+ // Check if mutations are relevant for queued changes.
185
+ if (this._typingQueue.hasAffectedElements()) {
191
186
  for (const { node } of mutations) {
192
187
  const viewElement = findMappedViewAncestor(node, mapper);
193
188
  const modelElement = mapper.toModelElement(viewElement);
194
- if (this._compositionQueue.isComposedElement(modelElement)) {
195
- this._compositionQueue.flush('mutations');
189
+ if (this._typingQueue.isElementAffected(modelElement)) {
190
+ this._typingQueue.flush('mutations');
196
191
  return;
197
192
  }
198
193
  }
199
- // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
200
- // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
201
- // @if CK_DEBUG_TYPING // '%cMutations not related to the composition.',
202
- // @if CK_DEBUG_TYPING // 'font-style: italic'
203
- // @if CK_DEBUG_TYPING // ) );
204
- // @if CK_DEBUG_TYPING // }
205
- });
206
- // Make sure that all changes are applied to the model before the end of composition.
207
- this.listenTo(view.document, 'compositionend', () => {
208
- this._compositionQueue.flush('composition end');
209
- });
210
- // Trigger mutations check after the composition completes to fix all DOM changes that got ignored during composition.
211
- // On Android the Renderer is not disabled while composing. While updating DOM nodes we ignore some changes
212
- // that are not that important (like NBSP vs plain space character) and could break the composition flow.
213
- // After composition is completed we trigger additional `mutations` event for elements affected by the composition
214
- // so the Renderer can adjust the DOM to the expected structure without breaking the composition.
215
- this.listenTo(view.document, 'compositionend', () => {
216
- const mutations = [];
217
- for (const element of this._compositionQueue.flushComposedElements()) {
194
+ }
195
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
196
+ // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
197
+ // @if CK_DEBUG_TYPING // '%cMutations not related to the composition.',
198
+ // @if CK_DEBUG_TYPING // 'font-style: italic'
199
+ // @if CK_DEBUG_TYPING // ) );
200
+ // @if CK_DEBUG_TYPING // }
201
+ });
202
+ // Make sure that all changes are applied to the model before the end of composition.
203
+ this.listenTo(view.document, 'compositionend', () => {
204
+ this._typingQueue.flush('before composition end');
205
+ }, { priority: 'high' });
206
+ // Trigger mutations check after the composition completes to fix all DOM changes that got ignored during composition.
207
+ // On Android, the Renderer is not disabled while composing. While updating DOM nodes, we ignore some changes
208
+ // that are not that important (like NBSP vs. plain space character) and could break the composition flow.
209
+ // After composition is completed, we trigger additional `mutations` event for elements affected by the composition
210
+ // so the Renderer can adjust the DOM to the expected structure without breaking the composition.
211
+ this.listenTo(view.document, 'compositionend', () => {
212
+ // There could be new item queued on the composition end, so flush it.
213
+ this._typingQueue.flush('after composition end');
214
+ const mutations = [];
215
+ if (this._typingQueue.hasAffectedElements()) {
216
+ for (const element of this._typingQueue.flushAffectedElements()) {
218
217
  const viewElement = mapper.toViewElement(element);
219
218
  if (!viewElement) {
220
219
  continue;
221
220
  }
222
221
  mutations.push({ type: 'children', node: viewElement });
223
222
  }
224
- if (mutations.length) {
225
- // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
226
- // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'Input',
227
- // @if CK_DEBUG_TYPING // '%cFire post-composition mutation fixes.',
228
- // @if CK_DEBUG_TYPING // 'font-weight: bold'
229
- // @if CK_DEBUG_TYPING // ) );
230
- // @if CK_DEBUG_TYPING // }
231
- view.document.fire('mutations', { mutations });
232
- // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
233
- // @if CK_DEBUG_TYPING // console.groupEnd();
234
- // @if CK_DEBUG_TYPING // }
235
- }
236
- }, { priority: 'lowest' });
237
- }
238
- else {
239
- // After composition end we need to verify if there are no left-overs.
240
- // Listening at the lowest priority so after the `InsertTextObserver` added above (all composed text
223
+ }
224
+ // Fire composition mutations, if any.
225
+ //
226
+ // For non-Android:
227
+ // After the composition end, we need to verify if there are no left-overs.
228
+ // Listening at the lowest priority, so after the `InsertTextObserver` added above (all composed text
241
229
  // should already be applied to the model, view, and DOM).
242
- // On non-Android the `Renderer` is blocked while user is composing but the `MutationObserver` still collects
230
+ // On non-Android the `Renderer` is blocked while the user is composing, but the `MutationObserver` still collects
243
231
  // mutated nodes and fires `mutations` events.
244
232
  // Those events are recorded by the `Renderer` but not applied to the DOM while composing.
245
233
  // We need to trigger those checks (and fixes) once again but this time without specifying the exact mutations
246
234
  // since they are already recorded by the `Renderer`.
247
- // It in the most cases just clears the internal record of mutated text nodes
235
+ // It in most cases just clears the internal record of mutated text nodes
248
236
  // since all changes should already be applied to the DOM.
249
- // This is especially needed when user cancels composition, so we can clear nodes marked to sync.
250
- this.listenTo(view.document, 'compositionend', () => {
237
+ // This is especially needed when a user cancels composition, so we can clear nodes marked to sync.
238
+ if (mutations.length || !env.isAndroid) {
251
239
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
252
240
  // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'Input',
253
- // @if CK_DEBUG_TYPING // '%cForce render after composition end.',
241
+ // @if CK_DEBUG_TYPING // '%cFire post-composition mutation fixes.',
254
242
  // @if CK_DEBUG_TYPING // 'font-weight: bold'
255
243
  // @if CK_DEBUG_TYPING // ) );
256
244
  // @if CK_DEBUG_TYPING // }
257
- view.document.fire('mutations', { mutations: [] });
245
+ view.document.fire('mutations', { mutations });
258
246
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
259
247
  // @if CK_DEBUG_TYPING // console.groupEnd();
260
248
  // @if CK_DEBUG_TYPING // }
261
- }, { priority: 'lowest' });
262
- }
249
+ }
250
+ }, { priority: 'lowest' });
263
251
  }
264
252
  /**
265
253
  * @inheritDoc
266
254
  */
267
255
  destroy() {
268
256
  super.destroy();
269
- this._compositionQueue.destroy();
257
+ this._typingQueue.destroy();
270
258
  }
271
259
  }
272
260
  /**
273
261
  * The queue of `insertText` command executions that are waiting for the DOM to get updated after beforeinput event.
274
262
  */
275
- class CompositionQueue {
263
+ class TypingQueue {
276
264
  /**
277
265
  * The editor instance.
278
266
  */
@@ -286,9 +274,13 @@ class CompositionQueue {
286
274
  */
287
275
  _queue = [];
288
276
  /**
289
- * A set of model elements. The composition happened in those elements. It's used for mutations check.
277
+ * Whether there is any composition enqueued or plain typing only.
278
+ */
279
+ _isComposing = false;
280
+ /**
281
+ * A set of model elements. The typing happened in those elements. It's used for mutations check.
290
282
  */
291
- _compositionElements = new Set();
283
+ _affectedElements = new Set();
292
284
  /**
293
285
  * @inheritDoc
294
286
  */
@@ -300,7 +292,7 @@ class CompositionQueue {
300
292
  */
301
293
  destroy() {
302
294
  this.flushDebounced.cancel();
303
- this._compositionElements.clear();
295
+ this._affectedElements.clear();
304
296
  while (this._queue.length) {
305
297
  this.shift();
306
298
  }
@@ -314,7 +306,7 @@ class CompositionQueue {
314
306
  /**
315
307
  * Push next insertText command data to the queue.
316
308
  */
317
- push(commandData) {
309
+ push(commandData, isComposing) {
318
310
  const commandLiveData = {
319
311
  text: commandData.text
320
312
  };
@@ -323,10 +315,11 @@ class CompositionQueue {
323
315
  for (const range of commandData.selection.getRanges()) {
324
316
  commandLiveData.selectionRanges.push(LiveRange.fromRange(range));
325
317
  // Keep reference to the model element for later mutation checks.
326
- this._compositionElements.add(range.start.parent);
318
+ this._affectedElements.add(range.start.parent);
327
319
  }
328
320
  }
329
321
  this._queue.push(commandLiveData);
322
+ this._isComposing ||= isComposing;
330
323
  this.flushDebounced();
331
324
  }
332
325
  /**
@@ -385,6 +378,15 @@ class CompositionQueue {
385
378
  editor.execute('insertText', commandData);
386
379
  }
387
380
  buffer.unlock();
381
+ if (!this._isComposing) {
382
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
383
+ // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'Input',
384
+ // @if CK_DEBUG_TYPING // 'Clear affected elements set'
385
+ // @if CK_DEBUG_TYPING // ) );
386
+ // @if CK_DEBUG_TYPING // }
387
+ this._affectedElements.clear();
388
+ }
389
+ this._isComposing = false;
388
390
  });
389
391
  view.scrollToTheSelection();
390
392
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
@@ -392,17 +394,23 @@ class CompositionQueue {
392
394
  // @if CK_DEBUG_TYPING // }
393
395
  }
394
396
  /**
395
- * Returns `true` if the given model element is related to recent composition.
397
+ * Returns `true` if the given model element is related to recent typing.
398
+ */
399
+ isElementAffected(element) {
400
+ return this._affectedElements.has(element);
401
+ }
402
+ /**
403
+ * Returns `true` if there are any affected elements in the queue.
396
404
  */
397
- isComposedElement(element) {
398
- return this._compositionElements.has(element);
405
+ hasAffectedElements() {
406
+ return this._affectedElements.size > 0;
399
407
  }
400
408
  /**
401
- * Returns an array of composition-related elements and clears the internal list.
409
+ * Returns an array of typing-related elements and clears the internal list.
402
410
  */
403
- flushComposedElements() {
404
- const result = Array.from(this._compositionElements);
405
- this._compositionElements.clear();
411
+ flushAffectedElements() {
412
+ const result = Array.from(this._affectedElements);
413
+ this._affectedElements.clear();
406
414
  return result;
407
415
  }
408
416
  }
@@ -52,4 +52,13 @@ export interface InsertTextEventData extends DomEventData {
52
52
  * If not specified, the insertion should occur at the current view selection.
53
53
  */
54
54
  selection?: ViewSelection | ViewDocumentSelection;
55
+ /**
56
+ * A flag indicating that event was fired during composition.
57
+ *
58
+ * Corresponds to the
59
+ * {@link module:engine/view/document~Document#event:compositionstart},
60
+ * {@link module:engine/view/document~Document#event:compositionupdate},
61
+ * and {@link module:engine/view/document~Document#event:compositionend } trio.
62
+ */
63
+ isComposing?: boolean;
55
64
  }
@@ -48,7 +48,7 @@ export default class InsertTextObserver extends Observer {
48
48
  if (!this.isEnabled) {
49
49
  return;
50
50
  }
51
- const { data: text, targetRanges, inputType, domEvent } = data;
51
+ const { data: text, targetRanges, inputType, domEvent, isComposing } = data;
52
52
  if (!typingInputTypes.includes(inputType)) {
53
53
  return;
54
54
  }
@@ -58,7 +58,8 @@ export default class InsertTextObserver extends Observer {
58
58
  const eventInfo = new EventInfo(viewDocument, 'insertText');
59
59
  viewDocument.fire(eventInfo, new DomEventData(view, domEvent, {
60
60
  text,
61
- selection: view.createSelection(targetRanges)
61
+ selection: view.createSelection(targetRanges),
62
+ isComposing
62
63
  }));
63
64
  // Stop the beforeinput event if `delete` event was stopped.
64
65
  // https://github.com/ckeditor/ckeditor5/issues/753
@@ -92,11 +93,12 @@ export default class InsertTextObserver extends Observer {
92
93
  // 1. The SelectionObserver is blocked and the view is not updated with the composition changes.
93
94
  // 2. The last moment before it's locked is the `compositionstart` event.
94
95
  // 3. The `SelectionObserver` is listening for `compositionstart` event and immediately converts
95
- // the selection. Handles this at the lowest priority so after the rendering is blocked.
96
+ // the selection. Handle this at the low priority so after the rendering is blocked.
96
97
  viewDocument.fire('insertText', new DomEventData(view, domEvent, {
97
- text: data
98
+ text: data,
99
+ isComposing: true
98
100
  }));
99
- }, { priority: 'lowest' });
101
+ }, { priority: 'low' });
100
102
  }
101
103
  }
102
104
  /**