@atlaskit/editor-core 203.11.6 → 203.11.7

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/composable-editor/editor-internal.js +2 -94
  3. package/dist/cjs/create-editor/ReactEditorViewNext.js +1 -0
  4. package/dist/cjs/ui/ContentStyles/code-block.js +1 -1
  5. package/dist/cjs/ui/ContentStyles/index.js +3 -3
  6. package/dist/cjs/version-wrapper.js +1 -1
  7. package/dist/es2019/composable-editor/editor-internal.js +3 -93
  8. package/dist/es2019/create-editor/ReactEditorViewNext.js +1 -1
  9. package/dist/es2019/ui/ContentStyles/code-block.js +2 -1
  10. package/dist/es2019/ui/ContentStyles/index.js +13 -0
  11. package/dist/es2019/version-wrapper.js +1 -1
  12. package/dist/esm/composable-editor/editor-internal.js +3 -95
  13. package/dist/esm/create-editor/ReactEditorViewNext.js +1 -1
  14. package/dist/esm/ui/ContentStyles/code-block.js +1 -1
  15. package/dist/esm/ui/ContentStyles/index.js +3 -3
  16. package/dist/esm/version-wrapper.js +1 -1
  17. package/dist/types/create-editor/ReactEditorViewNext.d.ts +1 -0
  18. package/dist/types/create-editor/create-universal-preset.d.ts +2 -6
  19. package/dist/types/presets/default.d.ts +4 -12
  20. package/dist/types/presets/universal.d.ts +2 -6
  21. package/dist/types/presets/useUniversalPreset.d.ts +2 -6
  22. package/dist/types-ts4.5/create-editor/ReactEditorViewNext.d.ts +1 -0
  23. package/dist/types-ts4.5/create-editor/create-universal-preset.d.ts +2 -6
  24. package/dist/types-ts4.5/presets/default.d.ts +4 -12
  25. package/dist/types-ts4.5/presets/universal.d.ts +2 -6
  26. package/dist/types-ts4.5/presets/useUniversalPreset.d.ts +2 -6
  27. package/package.json +5 -5
  28. package/dist/cjs/create-editor/ReactEditorView.js +0 -712
  29. package/dist/es2019/create-editor/ReactEditorView.js +0 -658
  30. package/dist/esm/create-editor/ReactEditorView.js +0 -705
  31. package/dist/types/create-editor/ReactEditorView.d.ts +0 -117
  32. package/dist/types-ts4.5/create-editor/ReactEditorView.d.ts +0 -117
@@ -1,658 +0,0 @@
1
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- import React from 'react';
3
- import { injectIntl } from 'react-intl-next';
4
- import uuid from 'uuid/v4';
5
- import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent, FULL_WIDTH_MODE, getAnalyticsEventsFromTransaction, PLATFORMS } from '@atlaskit/editor-common/analytics';
6
- import { browser } from '@atlaskit/editor-common/browser';
7
- import { getDocStructure } from '@atlaskit/editor-common/core-utils';
8
- import { countNodes } from '@atlaskit/editor-common/count-nodes';
9
- import { createDispatch, EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
10
- import { getEnabledFeatureFlagKeys } from '@atlaskit/editor-common/normalize-feature-flags';
11
- import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
12
- import { measureRender } from '@atlaskit/editor-common/performance/measure-render';
13
- import { getResponseEndTime } from '@atlaskit/editor-common/performance/navigation';
14
- import { EditorPluginInjectionAPI } from '@atlaskit/editor-common/preset';
15
- import { processRawValue, processRawValueWithoutValidation } from '@atlaskit/editor-common/process-raw-value';
16
- import { ReactEditorViewContext } from '@atlaskit/editor-common/ui-react';
17
- import { analyticsEventKey, getAnalyticsEventSeverity } from '@atlaskit/editor-common/utils/analytics';
18
- import { EditorState, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
19
- import { EditorView } from '@atlaskit/editor-prosemirror/view';
20
- import { fg } from '@atlaskit/platform-feature-flags';
21
- import { findChangedNodesFromTransaction } from '../utils/findChangedNodesFromTransaction';
22
- import { getNodesCount } from '../utils/getNodesCount';
23
- import { isFullPage } from '../utils/is-full-page';
24
- import { RenderTracking } from '../utils/performance/components/RenderTracking';
25
- import measurements from '../utils/performance/measure-enum';
26
- import { PluginPerformanceObserver } from '../utils/performance/plugin-performance-observer';
27
- import { freezeUnsafeTransactionProperties } from '../utils/performance/safer-transactions';
28
- import { EVENT_NAME_ON_CHANGE } from '../utils/performance/track-transactions';
29
- import { validateNodes, validNode } from '../utils/validateNodes';
30
- import { PROSEMIRROR_RENDERED_DEGRADED_SEVERITY_THRESHOLD, PROSEMIRROR_RENDERED_NORMAL_SEVERITY_THRESHOLD } from './consts';
31
- import { createErrorReporter, createPMPlugins, processPluginsList } from './create-editor';
32
- import createPluginsList from './create-plugins-list';
33
- import { createSchema } from './create-schema';
34
- import { createFeatureFlagsFromProps } from './feature-flags-from-props';
35
- import { editorMessages } from './messages';
36
- const EDIT_AREA_ID = 'ak-editor-textarea';
37
- function handleEditorFocus(view) {
38
- if (view.hasFocus()) {
39
- return;
40
- }
41
- return window.setTimeout(() => {
42
- if (view.hasFocus()) {
43
- return;
44
- }
45
- if (!window.getSelection) {
46
- view.focus();
47
- return;
48
- }
49
- const domSelection = window.getSelection();
50
- if (!domSelection || domSelection.rangeCount === 0) {
51
- view.focus();
52
- return;
53
- }
54
- const range = domSelection.getRangeAt(0);
55
- // if selection is outside editor focus and exit
56
- if (range.startContainer.contains(view.dom)) {
57
- view.focus();
58
- return;
59
- }
60
- // set cursor/selection and focus
61
- const anchor = view.posAtDOM(range.startContainer, range.startOffset);
62
- const head = view.posAtDOM(range.endContainer, range.endOffset);
63
- // if anchor or head < 0 focus and exit
64
- if (anchor < 0 || head < 0) {
65
- view.focus();
66
- return;
67
- }
68
- const selection = TextSelection.create(view.state.doc, anchor, head);
69
- const tr = view.state.tr.setSelection(selection);
70
- view.dispatch(tr);
71
- view.focus();
72
- }, 0);
73
- }
74
- // Ignored via go/ees005
75
- // eslint-disable-next-line @repo/internal/react/no-class-components
76
- export class ReactEditorView extends React.Component {
77
- //TODO: clean up
78
- get transactionTracking() {
79
- return {
80
- enabled: false
81
- };
82
- }
83
- getPluginNames() {
84
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
- return this.editorState.plugins.map(p => p.key);
86
- }
87
- countNodes() {
88
- return countNodes(this.editorState);
89
- }
90
- constructor(props) {
91
- var _this$props$editorPro3, _props$setEditorAPI;
92
- super(props);
93
- _defineProperty(this, "editorRef", /*#__PURE__*/React.createRef());
94
- // ProseMirror is instantiated prior to the initial React render cycle,
95
- // so we allow transactions by default, to avoid discarding the initial one.
96
- _defineProperty(this, "canDispatchTransactions", true);
97
- _defineProperty(this, "onPluginObservation", report => {
98
- var _this$pluginInjection, _this$pluginInjection2, _this$pluginInjection3;
99
- this.dispatchAnalyticsEvent({
100
- action: ACTION.TRANSACTION_DISPATCHED,
101
- actionSubject: ACTION_SUBJECT.EDITOR,
102
- eventType: EVENT_TYPE.OPERATIONAL,
103
- attributes: {
104
- report,
105
- participants: ((_this$pluginInjection = this.pluginInjectionAPI.api().collabEdit) === null || _this$pluginInjection === void 0 ? void 0 : (_this$pluginInjection2 = _this$pluginInjection.sharedState.currentState()) === null || _this$pluginInjection2 === void 0 ? void 0 : (_this$pluginInjection3 = _this$pluginInjection2.participants) === null || _this$pluginInjection3 === void 0 ? void 0 : _this$pluginInjection3.size()) || 1
106
- }
107
- });
108
- });
109
- _defineProperty(this, "getEditorState", () => {
110
- var _this$view;
111
- return (_this$view = this.view) === null || _this$view === void 0 ? void 0 : _this$view.state;
112
- });
113
- _defineProperty(this, "getEditorView", () => this.view);
114
- _defineProperty(this, "formatFullWidthAppearance", appearance => {
115
- if (appearance === 'full-width') {
116
- return FULL_WIDTH_MODE.FULL_WIDTH;
117
- }
118
- return FULL_WIDTH_MODE.FIXED_WIDTH;
119
- });
120
- _defineProperty(this, "resetEditorState", ({
121
- doc,
122
- shouldScrollToBottom
123
- }) => {
124
- var _this$props$editorPro, _this$props$editorPro2;
125
- if (!this.view) {
126
- return;
127
- }
128
-
129
- // We cannot currently guarentee when all the portals will have re-rendered during a reconfigure
130
- // so we blur here to stop ProseMirror from trying to apply selection to detached nodes or
131
- // nodes that haven't been re-rendered to the document yet.
132
- this.blur();
133
- this.featureFlags = createFeatureFlagsFromProps(this.props.editorProps.featureFlags);
134
- this.editorState = this.createEditorState({
135
- props: this.props,
136
- doc: doc,
137
- resetting: true,
138
- selectionAtStart: !shouldScrollToBottom
139
- });
140
- this.view.updateState(this.editorState);
141
- (_this$props$editorPro = (_this$props$editorPro2 = this.props.editorProps).onChange) === null || _this$props$editorPro === void 0 ? void 0 : _this$props$editorPro.call(_this$props$editorPro2, this.view, {
142
- source: 'local'
143
- });
144
- });
145
- _defineProperty(this, "blur", () => {
146
- if (!this.view) {
147
- return;
148
- }
149
- if (this.view.dom instanceof HTMLElement && this.view.hasFocus()) {
150
- this.view.dom.blur();
151
- }
152
-
153
- // The selectionToDOM method uses the document selection to determine currently selected node
154
- // We need to mimic blurring this as it seems doing the above is not enough.
155
- // @ts-expect-error
156
- const sel = this.view.root.getSelection();
157
- if (sel) {
158
- sel.removeAllRanges();
159
- }
160
- });
161
- _defineProperty(this, "handleAnalyticsEvent", payload => {
162
- fireAnalyticsEvent(this.props.createAnalyticsEvent)(payload);
163
- });
164
- _defineProperty(this, "editorPlugins", []);
165
- _defineProperty(this, "createEditorState", options => {
166
- var _api$editorViewMode;
167
- let schema;
168
- if (this.view) {
169
- if (options.resetting) {
170
- /**
171
- * ReactEditorView currently does NOT handle dynamic schema,
172
- * We are reusing the existing schema, and rely on #reconfigureState
173
- * to update `this.config`
174
- */
175
- schema = this.view.state.schema;
176
- } else {
177
- /**
178
- * There's presently a number of issues with changing the schema of a
179
- * editor inflight. A significant issue is that we lose the ability
180
- * to keep track of a user's history as the internal plugin state
181
- * keeps a list of Steps to undo/redo (which are tied to the schema).
182
- * Without a good way to do work around this, we prevent this for now.
183
- */
184
- // eslint-disable-next-line no-console
185
- console.warn('The editor does not support changing the schema dynamically.');
186
- return this.editorState;
187
- }
188
- } else {
189
- this.config = processPluginsList(this.getPlugins(options.props.preset));
190
- schema = createSchema(this.config);
191
- }
192
- const {
193
- contentTransformerProvider
194
- } = options.props.editorProps;
195
- const plugins = createPMPlugins({
196
- schema,
197
- dispatch: this.dispatch,
198
- errorReporter: this.errorReporter,
199
- editorConfig: this.config,
200
- eventDispatcher: this.eventDispatcher,
201
- providerFactory: options.props.providerFactory,
202
- portalProviderAPI: this.props.portalProviderAPI,
203
- nodeViewPortalProviderAPI: this.props.nodeViewPortalProviderAPI,
204
- dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
205
- featureFlags: this.featureFlags,
206
- getIntl: () => this.props.intl,
207
- onEditorStateUpdated: fg('platform_editor_catch_missing_injection_states') ? this.pluginInjectionAPI.onEditorViewUpdated : undefined
208
- });
209
- this.contentTransformer = contentTransformerProvider ? contentTransformerProvider(schema) : undefined;
210
- let doc;
211
- const api = this.pluginInjectionAPI.api();
212
- // If we have a doc prop, we need to process it into a PMNode
213
-
214
- if (options.doc) {
215
- // if the collabEdit API is set, skip this validation due to potential pm validation errors
216
- // from docs that end up with invalid marks after processing (See #hot-111702 for more details)
217
-
218
- if ((api === null || api === void 0 ? void 0 : api.collabEdit) !== undefined && fg('editor_load_conf_collab_docs_without_checks') || options.props.editorProps.skipValidation) {
219
- doc = processRawValueWithoutValidation(schema, options.doc, this.dispatchAnalyticsEvent);
220
- } else {
221
- doc = processRawValue(schema, options.doc, options.props.providerFactory, options.props.editorProps.sanitizePrivateContent, this.contentTransformer, this.dispatchAnalyticsEvent);
222
- }
223
- }
224
- const isViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.sharedState.currentState().mode) === 'view';
225
- let selection;
226
- if (doc) {
227
- if (isViewMode) {
228
- const emptySelection = new TextSelection(doc.resolve(0));
229
- return EditorState.create({
230
- schema,
231
- plugins: plugins,
232
- doc,
233
- selection: emptySelection
234
- });
235
- } else {
236
- selection = options.selectionAtStart ? Selection.atStart(doc) : Selection.atEnd(doc);
237
- }
238
- }
239
- // Workaround for ED-3507: When media node is the last element, scrollIntoView throws an error
240
- const patchedSelection = selection ? Selection.findFrom(selection.$head, -1, true) || undefined : undefined;
241
- return EditorState.create({
242
- schema,
243
- plugins: plugins,
244
- doc,
245
- selection: patchedSelection
246
- });
247
- });
248
- _defineProperty(this, "onEditorViewStateUpdated", ({
249
- originalTransaction,
250
- transactions,
251
- oldEditorState,
252
- newEditorState
253
- }) => {
254
- this.config.onEditorViewStateUpdatedCallbacks.forEach(entry => {
255
- entry.callback({
256
- originalTransaction,
257
- transactions,
258
- oldEditorState,
259
- newEditorState
260
- });
261
- });
262
- });
263
- _defineProperty(this, "dispatchTransaction", unsafeTransaction => {
264
- if (!this.view) {
265
- return;
266
- }
267
- const nodes = findChangedNodesFromTransaction(unsafeTransaction);
268
- const changedNodesValid = validateNodes(nodes);
269
- const transaction = new Proxy(unsafeTransaction, freezeUnsafeTransactionProperties({
270
- dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
271
- pluginKey: 'unknown-reacteditorview'
272
- }));
273
- if (changedNodesValid) {
274
- const oldEditorState = this.view.state;
275
-
276
- // go ahead and update the state now we know the transaction is good
277
- const {
278
- state: editorState,
279
- transactions
280
- } = this.view.state.applyTransaction(transaction);
281
- if (editorState === oldEditorState) {
282
- return;
283
- }
284
- this.view.updateState(editorState);
285
- if (!fg('platform_editor_catch_missing_injection_states')) {
286
- this.pluginInjectionAPI.onEditorViewUpdated({
287
- newEditorState: editorState,
288
- oldEditorState
289
- });
290
- }
291
-
292
- // ED-25839: Investigate if we also want to migrate this API to use `onEditorStateUpdated` in `createPMPlugins`
293
- this.onEditorViewStateUpdated({
294
- originalTransaction: transaction,
295
- transactions,
296
- oldEditorState,
297
- newEditorState: editorState
298
- });
299
- if (this.props.editorProps.onChange && transaction.docChanged) {
300
- const source = transaction.getMeta('isRemote') ? 'remote' : 'local';
301
- startMeasure(EVENT_NAME_ON_CHANGE);
302
- this.props.editorProps.onChange(this.view, {
303
- source
304
- });
305
- stopMeasure(EVENT_NAME_ON_CHANGE, (duration, startTime) => {
306
- this.dispatchAnalyticsEvent({
307
- action: ACTION.ON_CHANGE_CALLBACK,
308
- actionSubject: ACTION_SUBJECT.EDITOR,
309
- eventType: EVENT_TYPE.OPERATIONAL,
310
- attributes: {
311
- duration,
312
- startTime
313
- }
314
- });
315
- });
316
- }
317
- this.editorState = editorState;
318
- } else {
319
- const invalidNodes = nodes.filter(node => !validNode(node)).map(node => getDocStructure(node, {
320
- compact: true
321
- }));
322
- this.dispatchAnalyticsEvent({
323
- action: ACTION.DISPATCHED_INVALID_TRANSACTION,
324
- actionSubject: ACTION_SUBJECT.EDITOR,
325
- eventType: EVENT_TYPE.OPERATIONAL,
326
- attributes: {
327
- analyticsEventPayloads: getAnalyticsEventsFromTransaction(transaction),
328
- invalidNodes
329
- }
330
- });
331
- }
332
- });
333
- _defineProperty(this, "getDirectEditorProps", state => {
334
- return {
335
- state: state || this.editorState,
336
- dispatchTransaction: tr => {
337
- // Block stale transactions:
338
- // Prevent runtime exeptions from async transactions that would attempt to
339
- // update the DOM after React has unmounted the Editor.
340
- if (this.canDispatchTransactions) {
341
- this.dispatchTransaction(tr);
342
- }
343
- },
344
- // Disables the contentEditable attribute of the editor if the editor is disabled
345
- editable: _state => !this.props.editorProps.disabled,
346
- attributes: {
347
- 'data-gramm': 'false'
348
- }
349
- };
350
- });
351
- _defineProperty(this, "createEditorView", node => {
352
- measureRender(measurements.PROSEMIRROR_RENDERED, ({
353
- duration,
354
- startTime,
355
- distortedDuration
356
- }) => {
357
- this.proseMirrorRenderedSeverity = getAnalyticsEventSeverity(duration, PROSEMIRROR_RENDERED_NORMAL_SEVERITY_THRESHOLD, PROSEMIRROR_RENDERED_DEGRADED_SEVERITY_THRESHOLD);
358
- if (this.view) {
359
- var _this$pluginInjection4;
360
- const nodes = getNodesCount(this.view.state.doc);
361
- const ttfb = getResponseEndTime();
362
- const contextIdentifier = (_this$pluginInjection4 = this.pluginInjectionAPI.api().base) === null || _this$pluginInjection4 === void 0 ? void 0 : _this$pluginInjection4.sharedState.currentState();
363
- this.dispatchAnalyticsEvent({
364
- action: ACTION.PROSEMIRROR_RENDERED,
365
- actionSubject: ACTION_SUBJECT.EDITOR,
366
- attributes: {
367
- duration,
368
- startTime,
369
- nodes,
370
- ttfb,
371
- severity: this.proseMirrorRenderedSeverity,
372
- objectId: contextIdentifier === null || contextIdentifier === void 0 ? void 0 : contextIdentifier.objectId,
373
- distortedDuration
374
- },
375
- eventType: EVENT_TYPE.OPERATIONAL
376
- });
377
- }
378
- });
379
-
380
- // Creates the editor-view from this.editorState. If an editor has been mounted
381
- // previously, this will contain the previous state of the editor.
382
- this.view = new EditorView({
383
- mount: node
384
- }, this.getDirectEditorProps());
385
- this.pluginInjectionAPI.onEditorViewUpdated({
386
- newEditorState: this.view.state,
387
- oldEditorState: undefined
388
- });
389
- });
390
- _defineProperty(this, "handleEditorViewRef", node => {
391
- if (!this.view && node) {
392
- this.createEditorView(node);
393
- // Ignored via go/ees005
394
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
395
- const view = this.view;
396
- this.props.onEditorCreated({
397
- view,
398
- config: this.config,
399
- eventDispatcher: this.eventDispatcher,
400
- transformer: this.contentTransformer
401
- });
402
- if (this.props.editorProps.shouldFocus && view.props.editable && view.props.editable(view.state)) {
403
- this.focusTimeoutId = handleEditorFocus(view);
404
- }
405
-
406
- // Force React to re-render so consumers get a reference to the editor view
407
- this.forceUpdate();
408
- } else if (this.view && !node) {
409
- // When the appearance is changed, React will call handleEditorViewRef with node === null
410
- // to destroy the old EditorView, before calling this method again with node === div to
411
- // create the new EditorView
412
- this.props.onEditorDestroyed({
413
- view: this.view,
414
- config: this.config,
415
- eventDispatcher: this.eventDispatcher,
416
- transformer: this.contentTransformer
417
- });
418
-
419
- // Allows us to dispatch analytics within the plugin view.destory methods
420
- const analyticsConnected = this.eventDispatcher.has(analyticsEventKey, this.handleAnalyticsEvent);
421
- if (!analyticsConnected) {
422
- this.eventDispatcher.on(analyticsEventKey, this.handleAnalyticsEvent);
423
- }
424
- this.view.destroy(); // Destroys the dom node & all node views
425
-
426
- if (!analyticsConnected) {
427
- this.eventDispatcher.off(analyticsEventKey, this.handleAnalyticsEvent);
428
- }
429
- this.view = undefined;
430
- }
431
- });
432
- _defineProperty(this, "dispatchAnalyticsEvent", payload => {
433
- if (this.eventDispatcher) {
434
- const dispatch = createDispatch(this.eventDispatcher);
435
- dispatch(analyticsEventKey, {
436
- payload
437
- });
438
- }
439
- });
440
- _defineProperty(this, "editorId", uuid());
441
- _defineProperty(this, "createEditor", (assistiveLabel, assistiveDescribedBy) => {
442
- return /*#__PURE__*/React.createElement("div", {
443
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
444
- className: getUAPrefix(),
445
- key: "ProseMirror",
446
- ref: this.handleEditorViewRef,
447
- "aria-label": assistiveLabel || this.props.intl.formatMessage(editorMessages.editorAssistiveLabel)
448
- // setting aria-multiline to true when not mobile appearance.
449
- // because somehow mobile tests are failing when it set.
450
- // don't know why that is happening.
451
- // Created https://product-fabric.atlassian.net/jira/servicedesk/projects/DTR/queues/issue/DTR-1675
452
- // to investigate further.
453
- ,
454
- "aria-multiline": true,
455
- role: "textbox",
456
- id: EDIT_AREA_ID,
457
- "aria-describedby": assistiveDescribedBy,
458
- "data-editor-id": this.editorId
459
- });
460
- });
461
- _defineProperty(this, "editor", this.createEditor(this.props.editorProps.assistiveLabel, (_this$props$editorPro3 = this.props.editorProps) === null || _this$props$editorPro3 === void 0 ? void 0 : _this$props$editorPro3.assistiveDescribedBy));
462
- this.pluginInjectionAPI = new EditorPluginInjectionAPI({
463
- getEditorState: this.getEditorState,
464
- getEditorView: this.getEditorView,
465
- fireAnalyticsEvent: this.handleAnalyticsEvent
466
- });
467
- const _api = this.pluginInjectionAPI.api();
468
- (_props$setEditorAPI = props.setEditorAPI) === null || _props$setEditorAPI === void 0 ? void 0 : _props$setEditorAPI.call(props, _api);
469
- this.eventDispatcher = new EventDispatcher();
470
- this.dispatch = createDispatch(this.eventDispatcher);
471
- this.errorReporter = createErrorReporter(props.editorProps.errorReporterHandler);
472
- this.pluginPerformanceObserver = new PluginPerformanceObserver(report => this.onPluginObservation(report)).withPlugins(() => this.getPluginNames()).withNodeCounts(() => this.countNodes());
473
- this.featureFlags = createFeatureFlagsFromProps(this.props.editorProps.featureFlags);
474
- const featureFlagsEnabled = this.featureFlags ? getEnabledFeatureFlagKeys(this.featureFlags) : [];
475
-
476
- // This needs to be before initialising editorState because
477
- // we dispatch analytics events in plugin initialisation
478
- this.eventDispatcher.on(analyticsEventKey, this.handleAnalyticsEvent);
479
- this.eventDispatcher.on('resetEditorState', this.resetEditorState);
480
- this.editorState = this.createEditorState({
481
- props,
482
- doc: props.editorProps.defaultValue,
483
- // ED-4759: Don't set selection at end for full-page editor - should be at start.
484
- selectionAtStart: isFullPage(props.editorProps.appearance)
485
- });
486
- this.dispatchAnalyticsEvent({
487
- action: ACTION.STARTED,
488
- actionSubject: ACTION_SUBJECT.EDITOR,
489
- attributes: {
490
- platform: PLATFORMS.WEB,
491
- featureFlags: featureFlagsEnabled
492
- },
493
- eventType: EVENT_TYPE.UI
494
- });
495
- }
496
- // Ignored via go/ees005
497
- // eslint-disable-next-line react/no-unsafe
498
- UNSAFE_componentWillReceiveProps(nextProps) {
499
- var _nextProps$editorProp, _this$props$editorPro4;
500
- if (this.view && this.props.editorProps.disabled !== nextProps.editorProps.disabled) {
501
- // Disables the contentEditable attribute of the editor if the editor is disabled
502
- this.view.setProps({
503
- editable: _state => !nextProps.editorProps.disabled
504
- });
505
- if (!nextProps.editorProps.disabled && nextProps.editorProps.shouldFocus) {
506
- this.focusTimeoutId = handleEditorFocus(this.view);
507
- }
508
- }
509
- const {
510
- appearance
511
- } = this.props.editorProps;
512
- const {
513
- appearance: nextAppearance
514
- } = nextProps.editorProps;
515
- if (this.props.preset !== nextProps.preset) {
516
- this.reconfigureState(nextProps);
517
- }
518
- if (nextAppearance !== appearance) {
519
- if (nextAppearance === 'full-width' || appearance === 'full-width') {
520
- this.dispatchAnalyticsEvent({
521
- action: ACTION.CHANGED_FULL_WIDTH_MODE,
522
- actionSubject: ACTION_SUBJECT.EDITOR,
523
- eventType: EVENT_TYPE.TRACK,
524
- attributes: {
525
- previousMode: this.formatFullWidthAppearance(appearance),
526
- newMode: this.formatFullWidthAppearance(nextAppearance)
527
- }
528
- });
529
- }
530
- }
531
- if (nextProps.editorProps.assistiveLabel !== this.props.editorProps.assistiveLabel || ((_nextProps$editorProp = nextProps.editorProps) === null || _nextProps$editorProp === void 0 ? void 0 : _nextProps$editorProp.assistiveDescribedBy) !== ((_this$props$editorPro4 = this.props.editorProps) === null || _this$props$editorPro4 === void 0 ? void 0 : _this$props$editorPro4.assistiveDescribedBy)) {
532
- var _nextProps$editorProp2;
533
- this.editor = this.createEditor(nextProps.editorProps.assistiveLabel, (_nextProps$editorProp2 = nextProps.editorProps) === null || _nextProps$editorProp2 === void 0 ? void 0 : _nextProps$editorProp2.assistiveDescribedBy);
534
- }
535
- }
536
- reconfigureState(props) {
537
- if (!this.view) {
538
- return;
539
- }
540
-
541
- // We cannot currently guarentee when all the portals will have re-rendered during a reconfigure
542
- // so we blur here to stop ProseMirror from trying to apply selection to detached nodes or
543
- // nodes that haven't been re-rendered to the document yet.
544
- this.blur();
545
- const editorPlugins = this.getPlugins(props.preset);
546
- this.config = processPluginsList(editorPlugins);
547
- const state = this.editorState;
548
- const plugins = createPMPlugins({
549
- schema: state.schema,
550
- dispatch: this.dispatch,
551
- errorReporter: this.errorReporter,
552
- editorConfig: this.config,
553
- eventDispatcher: this.eventDispatcher,
554
- providerFactory: props.providerFactory,
555
- portalProviderAPI: props.portalProviderAPI,
556
- nodeViewPortalProviderAPI: props.nodeViewPortalProviderAPI,
557
- dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
558
- featureFlags: createFeatureFlagsFromProps(props.editorProps.featureFlags),
559
- getIntl: () => this.props.intl,
560
- onEditorStateUpdated: fg('platform_editor_catch_missing_injection_states') ? this.pluginInjectionAPI.onEditorViewUpdated : undefined
561
- });
562
- const newState = state.reconfigure({
563
- plugins: plugins
564
- });
565
-
566
- // need to update the state first so when the view builds the nodeviews it is
567
- // using the latest plugins
568
- this.view.updateState(newState);
569
- return this.view.update({
570
- ...this.view.props,
571
- state: newState
572
- });
573
- }
574
- componentDidMount() {
575
- // Transaction dispatching is already enabled by default prior to
576
- // mounting, but we reset it here, just in case the editor view
577
- // instance is ever recycled (mounted again after unmounting) with
578
- // the same key.
579
- // Although storing mounted state is an anti-pattern in React,
580
- // we do so here so that we can intercept and abort asynchronous
581
- // ProseMirror transactions when a dismount is imminent.
582
- this.canDispatchTransactions = true;
583
- }
584
-
585
- /**
586
- * Clean up any non-PM resources when the editor is unmounted
587
- */
588
- componentWillUnmount() {
589
- // We can ignore any transactions from this point onwards.
590
- // This serves to avoid potential runtime exceptions which could arise
591
- // from an async dispatched transaction after it's unmounted.
592
- this.canDispatchTransactions = false;
593
- clearTimeout(this.focusTimeoutId);
594
- if (this.reliabilityInterval) {
595
- clearInterval(this.reliabilityInterval);
596
- }
597
- this.pluginPerformanceObserver.disconnect();
598
- if (this.view) {
599
- // Destroy the state if the Editor is being unmounted
600
- const editorState = this.view.state;
601
- editorState.plugins.forEach(plugin => {
602
- const state = plugin.getState(editorState);
603
- if (state && state.destroy) {
604
- state.destroy();
605
- }
606
- });
607
- }
608
- this.eventDispatcher.destroy();
609
- // this.view will be destroyed when React unmounts in handleEditorViewRef
610
- }
611
- // Helper to allow tests to inject plugins directly
612
- getPlugins(preset) {
613
- const plugins = createPluginsList(preset, this.props.editorProps, this.pluginInjectionAPI);
614
- this.editorPlugins = plugins;
615
- return this.editorPlugins;
616
- }
617
- render() {
618
- var _this$props$render, _this$props$render2, _this$props;
619
- // Render tracking is firing too many events in Jira so we are disabling them for now. See - https://product-fabric.atlassian.net/browse/ED-25616
620
- const renderTrackingEnabled = !fg('platform_editor_disable_rerender_tracking_jira');
621
- const useShallow = true;
622
- return /*#__PURE__*/React.createElement(ReactEditorViewContext.Provider, {
623
- value: {
624
- editorRef: this.editorRef,
625
- editorView: this.view,
626
- popupsMountPoint: this.props.editorProps.popupsMountPoint
627
- }
628
- }, renderTrackingEnabled && /*#__PURE__*/React.createElement(RenderTracking, {
629
- componentProps: this.props,
630
- action: ACTION.RE_RENDERED,
631
- actionSubject: ACTION_SUBJECT.REACT_EDITOR_VIEW,
632
- handleAnalyticsEvent: this.handleAnalyticsEvent,
633
- useShallow: useShallow
634
- }), this.props.render ? (_this$props$render = (_this$props$render2 = (_this$props = this.props).render) === null || _this$props$render2 === void 0 ? void 0 : _this$props$render2.call(_this$props, {
635
- editor: this.editor,
636
- view: this.view,
637
- config: this.config,
638
- eventDispatcher: this.eventDispatcher,
639
- transformer: this.contentTransformer,
640
- dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
641
- editorRef: this.editorRef,
642
- editorAPI: this.props.editorAPI
643
- })) !== null && _this$props$render !== void 0 ? _this$props$render : this.editor : this.editor);
644
- }
645
- }
646
- function getUAPrefix() {
647
- if (browser.chrome) {
648
- return 'ua-chrome';
649
- } else if (browser.ie) {
650
- return 'ua-ie';
651
- } else if (browser.gecko) {
652
- return 'ua-firefox';
653
- } else if (browser.safari) {
654
- return 'ua-safari';
655
- }
656
- return '';
657
- }
658
- export default injectIntl(ReactEditorView);