@atlaskit/editor-core 219.7.2 → 219.7.4

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.
@@ -175,7 +175,11 @@ var editorContentStyles = {
175
175
  expandStylesMixin_fg_platform_visual_refresh_icons: "_1ev7kb7n _1ocgttxp",
176
176
  expandStylesMixin_without_fg_platform_editor_nested_dnd_styles_changes: "_1w8qq98m _omzvglyw _bqvk1osq _1h9p16ux _19lestnw _14j01n1a _1pm0idpf _1p3gidpf _1d9kt94y _113e1o8l",
177
177
  expandDenseStyles: "_18mb3mia _rrwb3mia",
178
- extensionDiffStyles: "",
178
+ extensionStyles: "_1a64bimv _hdxx1gly _xxyv1rtt _1xxp1tmw _1yb8kb7n _1g5bglyw _15vp15s3 _s9d56x5g _efyrkb7n _bp3fglyw _1tfz1nu9 _14ao1nu9 _1hpkkb7n _1e6ukb7n _1wcvidpf _1pt1idpf _1iq2r4us _1j23bimv _17xs1rtt _7u261tmw _1oo0glyw _1sfk1j28 _z5jxclii _et601yvi _gwkf1j28 _ul13r4us _4kr1h2mm _1qyx1kdv _1clfstnw _pj5bb3bt _1q5aidpf _1mvvidpf _1r6qidpf _1o9tidpf _1g3g1osq _1mglglyw _1cx01ial _am787wq0 _11mi1j28 _bw1x1j28 _ucr81j28 _12mi1j28 _jn1o1osq _6bv41osq _1oxabimv _1qn21gly _f2dr1j28 _68b9clii _1wb01yvi _mwpb1j28 _yyxzr4us _1eah1j28 _thp91j28 _11vt1j28 _4t5m1j28 _lnnb1rtt _wwen1tmw _1uw8kb7n _1kckglyw _1y3y15s3 _w5kn6x5g _1nq1kb7n _1nl0glyw _itji1nu9 _1bby1nu9 _vy7vkb7n _1dtlkb7n _l3rpidpf _wwmdidpf _1r6wr4us _1we4bimv _1nx11rtt _iehe1tmw _7hj6glyw _1gw2oqnp _1nb7oqnp _1890oqnp _mxneidpf _nzqyidpf _1ey5idpf _10qboqnp _mkj8oqnp _1o70oqnp _1oaoidpf _d40vidpf _1xipidpf _pgy3idpf _1ft6idpf _1gfbidpf _fkv9idpf _18gqidpf _jchyidpf _16uk1j28 _1h9u1j28 _36v61j28 _gg19r4us _1g5dr4us _oackr4us _1jtp1j28 _1f311j28 _18rv1j28 _swvw1j28 _1j9x1j28 _1dva1j28 _1mnz1j28 _bq4v1j28 _hl5f1j28 _crev1j28 _1d631j28 _28m71j28 _vi00bimv _1b2sbimv _124rbimv _1hvp1gly _gu7z1gly _1otv1gly _vpzk1rtt _1cas1rtt _o16g1tmw _14ye1tmw _6bknkb7n _1u6pkb7n _1vx5glyw _b841glyw _1oek15s3 _cw2a15s3 _6qzd6x5g _1xbj6x5g _1oa1kb7n _14ookb7n _rst4glyw _31aeglyw _1mwo1nu9 _iahl1nu9 _1abbbimv _1td9bimv _61jobimv _pzvn1gly _1mqj1gly _11bn1gly _qyzc1sou _1cjx1sou _1ie21sou _11dk1nu9 _hle21nu9 _dtkmkb7n _jf2hkb7n _h7tgkb7n _dwq7kb7n _ujyhidpf _1upkidpf _1mrzidpf _1tsoidpf _ib8er4us _15wnr4us _ko3dbimv _v8pmbimv _1hux1rtt _10ke1rtt _a3hl1tmw _1yqx1tmw _1y96glyw _505cglyw _5l361j28 _1ryt1j28 _1n4tclii _1oztclii _qkq9clii _1n5a1yvi _jn3m1yvi _btw31yvi _13is15vq _8cmh15vq _1qmbewfl _14thewfl _190516cs _15z51osq _b4z71osq _1iizoqnp _1vsooqnp _o1s4idpf _1swgidpf _1oknoqnp _1bs5oqnp _13e0idpf _1mxyidpf _wwc7oqnp _8vqxoqnp _1wmeidpf _la9widpf _1yssoqnp _xxgeoqnp _mkvnidpf _1by3idpf _6yf3idpf _ibadidpf _oeksidpf _miq6idpf _9bm6idpf _1noyidpf _b6ceidpf _dlfnidpf",
179
+ extensionStylesDense: "_1s773mia _bqje3mia",
180
+ extensionStylesLegacyDense: "_1r7aqlaa",
181
+ extensionDiffStyles: "_ur7x49jj",
182
+ bodiedExtensionLayoutShiftFix: "_16ng1gkc _klqg1n1a _ptek1n1a _e1ae1n1a _13ey10ni _1bh8dik7 _1v7bia51 _1v3nfajl _1i6iidpf _gc15idpf _1utjidpf _csmsidpf _gogjidpf _gt60idpf _15kbidpf _sve5idpf _pmyyidpf _1jpsidpf _a3m4idpf _pfwgidpf _fo78glyw _1j2jidpf",
179
183
  findReplaceStyles: "_9laafajl _1trh7xuz _1h36j5v0 _1uddtdv8",
180
184
  findReplaceStylesNewWithA11Y: "_xph31b66 _rq281nka _1bk513ow _17vzi7uo _ar1b1b18 _1ybwjocv _1mni17v8 _tfy618hq _11gt15cr _1bx3vj2t _1j061dxm _oa091nka _1ybf1nka _u1hx1up9 _1rn91up9 _wn3j1up9 _1ydu1up9 _11wp1up9 _u12f1ypf _13q91ypf _or3e1s89 _gzgh1s89 _ipvl1s89 _15r21s89 _1cpz1s89 _1lh5kz84 _1pvf1xf3 _7pge1xf3 _1h271xf3 _1us91xf3 _mxi51xf3 _1o191dzh _b9gt1dzh _rdw3qlfy _11bbqlfy _v91uqlfy _1k4sqlfy _1ecxqlfy _7gsu17v8 _12xo17v8 _briz1wdg _1cis1wdg _midr1wdg _1kd91wdg _1t9u1wdg _1me2qxcq _r8mlqxcq _1im23ney _1r5e3ney _1oci3ney _13bv3ney _1kac3ney _h2391jcr _1r791fb9 _1ebn1fb9 _1s101fb9 _1p5e1fb9 _1bkc1fb9 _50231ph4 _1c101ph4 _1s5oiro1 _1w9miro1 _w8rkiro1 _u854iro1 _o9w6iro1 _1sch1b66 _ztqp1nka _4temv9ra _r79ei7uo _1e4d1b18 _hje11ckf _sopm17v8 _4q84eawv _1t2d15cr _12dfvj2t _cle21ok8",
181
185
  findReplaceStylesNewWithCodeblockColorContrastFix: "_64o84viv",
@@ -373,14 +377,7 @@ var EditorContentContainerCompiled = exports.EditorContentContainerCompiled = /*
373
377
  (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp')) && editorContentStyles.mediaCaptionStyles, (0, _platformFeatureFlags.fg)('platform_editor_fix_media_in_renderer') && editorContentStyles.firstWrappedMediaStyles, editorContentStyles.telepointerStyle, /* This needs to be after telepointer styles as some overlapping rules have equal specificity, and so the order is significant */
374
378
  editorContentStyles.telepointerColorAndCommonStyle, editorContentStyles.gapCursorStyles, (0, _experiments.editorExperiment)('platform_synced_block', true) && editorContentStyles.gapCursorStylesVisibilityFix, editorContentStyles.panelStyles, editorContentStyles.nestedPanelBorderStylesMixin, (0, _platformFeatureFlags.fg)('platform_editor_nested_dnd_styles_changes') && editorContentStyles.panelStylesMixin_fg_platform_editor_nested_dnd_styles_changes, editorContentStyles.panelStylesMixin, editorContentStyles.mentionsStyles, editorContentStyles.tasksAndDecisionsStyles, contentMode === 'compact' && ((0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) ||
375
379
  // eslint-disable-next-line @atlaskit/platform/no-preconditioning
376
- (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp')) && isDense && editorContentStyles.tasksAndDecisionsDenseStyles, editorContentStyles.gridStyles, editorContentStyles.blockMarksStyles, editorContentStyles.dateStyles,
377
- // eslint-disable-next-line @atlaskit/editor/enforce-todo-comment-format
378
- // TODO: uncomment and remove dynamic styles from getExtensionStyles
379
- // migrate this with packages/editor/editor-core/src/ui/EditorContentContainer/styles/extensionStyles.ts
380
- // suggest creating a new cssMap for the variant use case from the guide below
381
- // reference: https://atlassian.design/components/eslint-plugin-ui-styling-standard/no-dynamic-styles/usage
382
- // getExtensionStyles(contentMode),
383
- editorContentStyles.extensionDiffStyles, editorContentStyles.expandStylesBase, !useStandardNodeWidth && editorContentStyles.expandStyles, contentMode === 'compact' && ((0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) ||
380
+ (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp')) && isDense && editorContentStyles.tasksAndDecisionsDenseStyles, editorContentStyles.gridStyles, editorContentStyles.blockMarksStyles, editorContentStyles.dateStyles, editorContentStyles.extensionStyles, (contentMode === 'compact' && (0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) || (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp')) && editorContentStyles.extensionStylesDense, contentMode === 'compact' && (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && !(0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) && !(0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp') && editorContentStyles.extensionStylesLegacyDense, (0, _expValEquals.expValEquals)('platform_editor_bodiedextension_layoutshift_fix', 'isEnabled', true) && editorContentStyles.bodiedExtensionLayoutShiftFix, editorContentStyles.extensionDiffStyles, editorContentStyles.expandStylesBase, !useStandardNodeWidth && editorContentStyles.expandStyles, contentMode === 'compact' && ((0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) ||
384
381
  // eslint-disable-next-line @atlaskit/platform/no-preconditioning
385
382
  (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp')) && isDense && editorContentStyles.expandDenseStyles, (0, _platformFeatureFlags.fg)('platform_editor_nested_dnd_styles_changes') ? editorContentStyles.expandStylesMixin_fg_platform_editor_nested_dnd_styles_changes : editorContentStyles.expandStylesMixin_without_fg_platform_editor_nested_dnd_styles_changes, editorContentStyles.expandStylesMixin_fg_platform_visual_refresh_icons, isChromeless && (0, _expValEquals.expValEquals)('platform_editor_chromeless_expand_fix', 'isEnabled', true) && editorContentStyles.expandStylesMixin_experiment_platform_editor_chromeless_expand_fix, (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? editorContentStyles.findReplaceStylesNewWithA11Y : editorContentStyles.findReplaceStyles, (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true) && editorContentStyles.findReplaceStylesNewWithCodeblockColorContrastFix, !(0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true) && editorContentStyles.findReplaceStylesWithCodeblockColorContrastFix, editorContentStyles.textHighlightStyle, editorContentStyles.decisionStyles, (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_blocktaskitem_node_tenantid', 'isEnabled', true) ? editorContentStyles.taskItemStylesWithBlockTaskItem : editorContentStyles.taskItemStyles, editorContentStyles.taskItemCheckboxStyles, editorContentStyles.decisionIconWithVisualRefresh, editorContentStyles.statusStyles, (0, _platformFeatureFlags.fg)('platform-dst-lozenge-tag-badge-visual-uplifts') ? editorContentStyles.statusStylesTeam26 : (0, _platformFeatureFlags.fg)('platform-component-visual-refresh') ? (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? editorContentStyles.statusStylesMixin_fg_platform_component_visual_refresh_with_search_match : editorContentStyles.statusStylesMixin_fg_platform_component_visual_refresh : (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? editorContentStyles.statusStylesMixin_without_fg_platform_component_visual_refresh_with_search_match : editorContentStyles.statusStylesMixin_without_fg_platform_component_visual_refresh, editorContentStyles.annotationStyles, (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? (0, _experiments.editorExperiment)('platform_editor_block_menu', true) ? editorContentStyles.smartCardStylesWithSearchMatchAndBlockMenuDangerStyles : editorContentStyles.smartCardStylesWithSearchMatch : editorContentStyles.smartCardStyles, (0, _experiments.editorExperiment)('platform_editor_preview_panel_responsiveness', true) && editorContentStyles.smartCardStylesWithSearchMatchAndPreviewPanelResponsiveness, ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_controls', 'cohort', 'variant1') || (0, _experiments.editorExperiment)('platform_editor_preview_panel_linking_exp', true)) && editorContentStyles.editorControlsSmartCardStyles, editorContentStyles.embedCardStyles, editorContentStyles.unsupportedStyles, editorContentStyles.resizerStyles, editorContentStyles.layoutBaseStyles, (0, _expValEquals.expValEquals)('platform_editor_table_excerpts_fix', 'isEnabled', true) && editorContentStyles.layoutBaseStylesWithTableExcerptsFix, (0, _platformFeatureFlags.fg)('platform_editor_fix_media_in_renderer') && editorContentStyles.alignMultipleWrappedImageInLayoutStyles, (0, _experiments.editorExperiment)('platform_synced_block', true) && editorContentStyles.syncBlockStylesBase, (0, _experiments.editorExperiment)('platform_synced_block', true) &&
386
383
  // Apply sync block delta styles conditionally based on useStandardNodeWidth (negative margins or not)
@@ -18,6 +18,11 @@ var _analytics2 = require("@atlaskit/editor-common/utils/analytics");
18
18
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
19
19
  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; }
20
20
  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; }
21
+ // Structural shape of the markdown-mode plugin's slice of the injection API.
22
+ // Used to read `isMarkdownMode` without importing the `MarkdownModePlugin`
23
+ // type — that would pull editor-plugin-markdown-mode into editor-core's
24
+ // dependency graph and force every consuming product to rebuild.
25
+
21
26
  /**
22
27
  * Utils to send analytics event when a extension is inserted using quickInsert
23
28
  */
@@ -89,6 +94,15 @@ function _extensionProviderToQuickInsertProvider() {
89
94
  extensions = _context.sent;
90
95
  return _context.abrupt("return", {
91
96
  getItems: function getItems() {
97
+ var _apiRef$current;
98
+ // `extensionProvider` is supplied independently of the preset, so
99
+ // suppress its items in markdown mode where rich-only content cannot
100
+ // be inserted. See `MarkdownModeReader` above for why this is read
101
+ // via a structural cast rather than the typed plugin API.
102
+ var isMarkdownMode = (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || (_apiRef$current = _apiRef$current.markdownMode) === null || _apiRef$current === void 0 || (_apiRef$current = _apiRef$current.sharedState.currentState()) === null || _apiRef$current === void 0 ? void 0 : _apiRef$current.isMarkdownMode;
103
+ if (isMarkdownMode) {
104
+ return Promise.resolve([]);
105
+ }
92
106
  var quickInsertItems = (0, _extensions.getQuickInsertItemsFromModule)(extensions, function (item) {
93
107
  var Icon = (0, _reactLoadable.default)({
94
108
  loader: item.icon,
@@ -120,8 +134,8 @@ function _extensionProviderToQuickInsertProvider() {
120
134
  isDisabledOffline: true,
121
135
  action: function action(insert, state, source) {
122
136
  if (typeof item.node === 'function') {
123
- var _apiRef$current;
124
- var extensionAPI = apiRef === null || apiRef === void 0 || (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || (_apiRef$current = _apiRef$current.extension) === null || _apiRef$current === void 0 || (_apiRef$current = _apiRef$current.actions) === null || _apiRef$current === void 0 ? void 0 : _apiRef$current.api();
137
+ var _apiRef$current2;
138
+ var extensionAPI = apiRef === null || apiRef === void 0 || (_apiRef$current2 = apiRef.current) === null || _apiRef$current2 === void 0 || (_apiRef$current2 = _apiRef$current2.extension) === null || _apiRef$current2 === void 0 || (_apiRef$current2 = _apiRef$current2.actions) === null || _apiRef$current2 === void 0 ? void 0 : _apiRef$current2.api();
125
139
  // While this should only run when the extension some setups of editor
126
140
  // may not have the extension API
127
141
  if (extensionAPI) {
@@ -5,4 +5,4 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.version = exports.name = void 0;
7
7
  var name = exports.name = "@atlaskit/editor-core";
8
- var version = exports.version = "219.7.1";
8
+ var version = exports.version = "219.7.3";
@@ -17,6 +17,7 @@ import { processRawValue, processRawValueWithoutValidation } from '@atlaskit/edi
17
17
  import { ReactEditorViewContext } from '@atlaskit/editor-common/ui-react';
18
18
  import { analyticsEventKey, getAnalyticsEventSeverity } from '@atlaskit/editor-common/utils/analytics';
19
19
  import { isEmptyDocument } from '@atlaskit/editor-common/utils/document';
20
+ import { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
20
21
  import { EditorState, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
21
22
  import { EditorView } from '@atlaskit/editor-prosemirror/view';
22
23
  import { EditorSSRRenderer } from '@atlaskit/editor-ssr-renderer';
@@ -48,6 +49,24 @@ import { useFireFullWidthEvent } from './ReactEditorView/useFireFullWidthEvent';
48
49
  const EDIT_AREA_ID = 'ak-editor-textarea';
49
50
  const SSR_TRACE_SEGMENT_NAME = 'reactEditorView';
50
51
  const bootStartTime = isPerformanceAPIAvailable() ? performance.now() : undefined;
52
+ // `markdown↔rich` toggles drop different node/mark sets, so the unique
53
+ // name set is enough to detect when a destructive rebuild is needed.
54
+ function sameNames(a, b) {
55
+ const setA = new Set(a);
56
+ const setB = new Set(b);
57
+ if (setA.size !== setB.size) {
58
+ return false;
59
+ }
60
+ for (const name of setA) {
61
+ if (!setB.has(name)) {
62
+ return false;
63
+ }
64
+ }
65
+ return true;
66
+ }
67
+ function schemaShapeChanged(current, next) {
68
+ return !sameNames(Object.keys(current.nodes), next.nodes.map(n => n.name)) || !sameNames(Object.keys(current.marks), next.marks.map(m => m.name));
69
+ }
51
70
  export function ReactEditorView(props) {
52
71
  var _pluginInjectionAPI$c, _pluginInjectionAPI$c2, _pluginInjectionAPI$c3, _media, _linking, _linking$smartLinks, _document$querySelect, _props$render, _props$render2;
53
72
  // Should be always the first statement in the component
@@ -338,9 +357,10 @@ export function ReactEditorView(props) {
338
357
  // components from the rebuilt preset).
339
358
  const [, bumpConfigVersion] = useState(0);
340
359
 
341
- // Preset reference last processed by the schema/API reconciliation below.
342
- // Used to skip that work when reconfigure is called with the same preset.
343
- const lastFilteredPresetRef = useRef(null);
360
+ // Preset reference last processed by reconfigureState. Used to skip the
361
+ // destructive work (plugin filter, schema rebuild) when reconfigure is
362
+ // called with the same preset.
363
+ const lastProcessedPresetRef = useRef(null);
344
364
  const reconfigureState = useCallback(props => {
345
365
  if (!viewRef.current) {
346
366
  return;
@@ -357,6 +377,34 @@ export function ReactEditorView(props) {
357
377
  const previousPluginNames = new Set(pluginInjectionAPI.current.getRegisteredPluginNames());
358
378
  let editorPlugins = createPluginsList(props.preset, 'allowBlockType' in props.editorProps ? props.editorProps : {}, pluginInjectionAPI.current);
359
379
 
380
+ // Capture once, before either downstream block updates the ref —
381
+ // both the filter and the schema rebuild are destructive and only
382
+ // want to run when the preset has actually changed.
383
+ const presetChanged = lastProcessedPresetRef.current !== props.preset;
384
+
385
+ // Build a candidate config from the *unfiltered* plugin list so we can
386
+ // decide whether the schema rebuild path will run. Both the rebuild
387
+ // decision and the drop-filter decision below depend on this answer,
388
+ // so it has to be computed up-front.
389
+ const buildConfig = plugins => {
390
+ const c = processPluginsList(plugins);
391
+ if (expValEquals('platform_editor_appearance_shared_state', 'isEnabled', true)) {
392
+ c.pmPlugins.push(...pluginInjectionAPI.current.getInternalPMPlugins());
393
+ }
394
+ return c;
395
+ };
396
+ let nextConfig = buildConfig(editorPlugins);
397
+
398
+ // `state.reconfigure` preserves the original schema, so a preset
399
+ // toggle that should change schema (markdown↔rich) needs a fresh
400
+ // `EditorState`. Resets all plugin state including undo history.
401
+ //
402
+ // Compare schema *shape* (node + mark name sets) rather than preset
403
+ // identity: consumers commonly recreate the preset object on every
404
+ // parent re-render, and a destructive rebuild on a no-op identity
405
+ // change tears down all plugin state (e.g. unmounts the AI palette).
406
+ const shouldRebuildSchema = presetChanged && schemaShapeChanged(viewRef.current.state.schema, nextConfig) && expValEqualsNoExposure('cc-markdown-mode', 'isEnabled', true);
407
+
360
408
  // `state.reconfigure` keeps the original schema, so switching presets
361
409
  // can leave the editor inconsistent in two ways:
362
410
  // 1. The new preset may add plugins that reference schema nodes or
@@ -365,18 +413,26 @@ export function ReactEditorView(props) {
365
413
  // injection API even when the new preset doesn't re-register
366
414
  // them, so listeners still fire against a state that no longer
367
415
  // has their pmPlugin.
368
- if (lastFilteredPresetRef.current !== props.preset && fg('platform_editor_reconfigure_filter_plugins')) {
369
- const {
370
- kept,
371
- dropped
372
- } = filterPluginsForReconfigure(editorPlugins, viewRef.current.state.schema, previousPluginNames);
373
- editorPlugins = kept;
374
-
375
- // Reconcile the injection API with the post-filter plugin set.
376
- // This evicts both the plugins we just dropped above (re-registered
377
- // by createPluginsList but no longer in editorPlugins) AND any
378
- // plugin from a previous preset that the new preset doesn't
379
- // re-register.
416
+ //
417
+ // When the schema is being rebuilt below, the new schema is built
418
+ // from the *unfiltered* plugin list — so dropping plugins whose
419
+ // nodes/marks the OLD schema lacks would wrongly remove the very
420
+ // plugins the rebuild is meant to admit. Skip the drop step in that
421
+ // case (purpose 1) but always reconcile the injection API
422
+ // (purpose 2). When NOT rebuilding, run both — even under the
423
+ // `cc-markdown-mode` experiment, otherwise no-op preset identity
424
+ // changes would silently leave a broken plugin/schema mismatch.
425
+ if (presetChanged && fg('platform_editor_reconfigure_filter_plugins')) {
426
+ let dropped = [];
427
+ if (!shouldRebuildSchema) {
428
+ const result = filterPluginsForReconfigure(editorPlugins, viewRef.current.state.schema, previousPluginNames);
429
+ if (result.dropped.length > 0) {
430
+ editorPlugins = result.kept;
431
+ // Plugin list changed — rebuild candidate config to match.
432
+ nextConfig = buildConfig(editorPlugins);
433
+ }
434
+ dropped = result.dropped;
435
+ }
380
436
  const keptPluginNames = new Set(editorPlugins.map(p => p === null || p === void 0 ? void 0 : p.name).filter(n => Boolean(n)));
381
437
  const evictedFromApi = pluginInjectionAPI.current.retainPlugins(keptPluginNames);
382
438
  if (dropped.length > 0 || evictedFromApi.length > 0) {
@@ -386,30 +442,73 @@ export function ReactEditorView(props) {
386
442
  evictedFromApi
387
443
  });
388
444
  }
389
- lastFilteredPresetRef.current = props.preset;
390
- }
391
- config.current = processPluginsList(editorPlugins);
392
- if (expValEquals('platform_editor_appearance_shared_state', 'isEnabled', true)) {
393
- config.current.pmPlugins.push(...pluginInjectionAPI.current.getInternalPMPlugins());
394
445
  }
446
+ config.current = nextConfig;
395
447
  const state = viewRef.current.state;
396
- const plugins = createPMPlugins({
397
- schema: state.schema,
398
- dispatch: dispatch,
399
- errorReporter: errorReporter,
400
- editorConfig: config.current,
401
- eventDispatcher: eventDispatcher,
402
- providerFactory: props.providerFactory,
403
- portalProviderAPI: props.portalProviderAPI,
404
- nodeViewPortalProviderAPI: props.nodeViewPortalProviderAPI,
405
- dispatchAnalyticsEvent: dispatchAnalyticsEvent,
406
- featureFlags,
407
- getIntl: () => props.intl,
408
- onEditorStateUpdated: pluginInjectionAPI.current.onEditorViewUpdated
409
- });
410
- const newState = state.reconfigure({
411
- plugins: plugins
412
- });
448
+ let newState;
449
+ if (shouldRebuildSchema) {
450
+ const newSchema = createSchema(config.current);
451
+ let newDoc;
452
+ try {
453
+ newDoc = PMNode.fromJSON(newSchema, state.doc.toJSON());
454
+ } catch (e) {
455
+ // eslint-disable-next-line no-console
456
+ console.error('[reconfigureState] Failed to migrate doc to new schema; resetting to empty doc', e);
457
+ const empty = newSchema.topNodeType.createAndFill();
458
+ if (!empty) {
459
+ throw new Error('reconfigureState: doc migration failed and new schema cannot create an empty top node');
460
+ }
461
+ newDoc = empty;
462
+ }
463
+ let newSelection;
464
+ try {
465
+ newSelection = Selection.fromJSON(newDoc, state.selection.toJSON());
466
+ } catch {
467
+ // Old selection's positions / node types may not map onto the new schema.
468
+ newSelection = Selection.atStart(newDoc);
469
+ }
470
+ const plugins = createPMPlugins({
471
+ schema: newSchema,
472
+ dispatch: dispatch,
473
+ errorReporter: errorReporter,
474
+ editorConfig: config.current,
475
+ eventDispatcher: eventDispatcher,
476
+ providerFactory: props.providerFactory,
477
+ portalProviderAPI: props.portalProviderAPI,
478
+ nodeViewPortalProviderAPI: props.nodeViewPortalProviderAPI,
479
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
480
+ featureFlags,
481
+ getIntl: () => props.intl,
482
+ onEditorStateUpdated: pluginInjectionAPI.current.onEditorViewUpdated
483
+ });
484
+ newState = EditorState.create({
485
+ schema: newSchema,
486
+ doc: newDoc,
487
+ selection: newSelection,
488
+ plugins: plugins
489
+ });
490
+ } else {
491
+ const plugins = createPMPlugins({
492
+ schema: state.schema,
493
+ dispatch: dispatch,
494
+ errorReporter: errorReporter,
495
+ editorConfig: config.current,
496
+ eventDispatcher: eventDispatcher,
497
+ providerFactory: props.providerFactory,
498
+ portalProviderAPI: props.portalProviderAPI,
499
+ nodeViewPortalProviderAPI: props.nodeViewPortalProviderAPI,
500
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent,
501
+ featureFlags,
502
+ getIntl: () => props.intl,
503
+ onEditorStateUpdated: pluginInjectionAPI.current.onEditorViewUpdated
504
+ });
505
+ newState = state.reconfigure({
506
+ plugins: plugins
507
+ });
508
+ }
509
+ if (presetChanged) {
510
+ lastProcessedPresetRef.current = props.preset;
511
+ }
413
512
 
414
513
  // need to update the state first so when the view builds the nodeviews it is
415
514
  // using the latest plugins
@@ -419,9 +518,32 @@ export function ReactEditorView(props) {
419
518
  state: newState
420
519
  });
421
520
 
521
+ // The new collab-edit plugin instance starts with `isReady=false`.
522
+ // The rebind path in editor-plugin-collab-edit's initialize.ts is
523
+ // gated on `provider.getInitPayload`, which the Confluence NCS
524
+ // provider does not implement, so the placeholder spinner would
525
+ // never clear. Re-seeding here is safe: the prior state must have
526
+ // had `isReady=true` for the user to have triggered the toggle.
527
+ //
528
+ // Must run AFTER `view.update({ state: newState })`: that call resets
529
+ // the view's state to the captured `newState` reference, so a
530
+ // dispatch placed before it would advance `view.state` to a value
531
+ // that `update` then silently overwrites — discarding the meta and
532
+ // leaving `isReady=false`.
533
+ if (shouldRebuildSchema) {
534
+ // `state.collabEditPlugin$` is the property PM derives from the
535
+ // collab plugin's PluginKey; cast through `unknown` to read it.
536
+ const collabState = viewRef.current.state.collabEditPlugin$;
537
+ if (collabState && collabState.isReady !== true) {
538
+ viewRef.current.dispatch(viewRef.current.state.tr.setMeta('collabInitialised', true));
539
+ }
540
+ }
541
+
422
542
  // EDITOR-6702: gated until we have a broader gate; reconfigure is a
423
543
  // low-level path so use NoExposure.
424
544
  if (expValEqualsNoExposure('cc-markdown-mode', 'isEnabled', true)) {
545
+ // Force a render so PluginSlot picks up the new preset's content
546
+ // components against the new state.
425
547
  bumpConfigVersion(v => v + 1);
426
548
  }
427
549
  return result;