@atlaskit/editor-plugin-expand 15.0.5 → 15.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,34 @@
1
1
  # @atlaskit/editor-plugin-expand
2
2
 
3
+ ## 15.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`da5eaf0bc37da`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/da5eaf0bc37da) -
8
+ Clean up the platform_editor_editor_ssr_streaming experiment. The SSR streaming code paths are now
9
+ permanent and the isSSRStreaming() utility has been removed from
10
+ @atlaskit/editor-common/core-utils.
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+
16
+ ## 15.1.0
17
+
18
+ ### Minor Changes
19
+
20
+ - [`2d23b40eed4f0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2d23b40eed4f0) -
21
+ Add gated content-visibility:auto to tables, expands and media singles to improve editor rendering
22
+ performance on large documents. Applied only to nodes whose rendered size can be estimated closely
23
+ — structurally (row/child counts) for tables and expands, and from the media's own dimensions and
24
+ the renderer's width calculation for media singles. Behind the
25
+ cc_editor_limited_mode_perf_improvements experiment and only active when limited mode is enabled
26
+ for the document (shared large-document detection with the limited-mode plugin).
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies
31
+
3
32
  ## 15.0.5
4
33
 
5
34
  ### Patch Changes
package/compass.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  configVersion: 1
2
2
  id: ari:cloud:compass:a436116f-02ce-4520-8fbb-7301462a1674:component/c5751cc6-3513-4070-9deb-af31e86aed34/abb2d576-3082-4a86-ade1-4659d5e66889
3
3
  name: '@atlaskit/editor-plugin-expand'
4
- ownerId: ari:cloud:identity::team/2484e1f6-f62c-4a70-95f1-8e5695c51b6b # Editor Jenga
4
+ ownerId: ari:cloud:identity::team/cf6a670b-5252-4c68-a769-9207de366beb # Editor Developers
5
5
  labels:
6
6
  - platform-code
7
7
  - platform-afm
@@ -16,14 +16,14 @@ links:
16
16
  url: https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/master
17
17
  - name: Slack Channel
18
18
  type: CHAT_CHANNEL
19
- url: https://atlassian.enterprise.slack.com/archives/C061GUMN3NY # #team-cc-editor-exp-cloud-native
19
+ url: https://atlassian.enterprise.slack.com/archives/CFG3PSQ9E # #help-editor
20
20
  - name: Editor Plugin Expand
21
21
  type: REPOSITORY
22
22
  url: https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/master/platform/packages/editor/editor-plugin-expand
23
23
  customFields:
24
24
  - name: Department
25
25
  type: text
26
- value: Eng - Editor Autonomy - Jenga
26
+ value: Editor Developers
27
27
  - name: Trusted Reviewer Teams
28
28
  type: text
29
29
  value: ari:cloud:identity::team/cf6a670b-5252-4c68-a769-9207de366beb
@@ -16,6 +16,7 @@ var _selection = require("@atlaskit/editor-common/selection");
16
16
  var _styles = require("@atlaskit/editor-common/styles");
17
17
  var _ui = require("@atlaskit/editor-common/ui");
18
18
  var _utils = require("@atlaskit/editor-common/utils");
19
+ var _contentVisibility = require("@atlaskit/editor-common/utils/content-visibility");
19
20
  var _model = require("@atlaskit/editor-prosemirror/model");
20
21
  var _state = require("@atlaskit/editor-prosemirror/state");
21
22
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
@@ -535,6 +536,11 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
535
536
  this.input = this.dom.querySelector(".".concat(_styles.expandClassNames.titleInput));
536
537
  this.titleContainer = this.dom.querySelector(".".concat(_styles.expandClassNames.titleContainer));
537
538
  this.content = this.dom.querySelector(".".concat(_styles.expandClassNames.content));
539
+ (0, _contentVisibility.applyContentVisibility)(this.dom, this.isLimitedModeEnabled(), function () {
540
+ return {
541
+ height: (0, _contentVisibility.estimateExpandIntrinsicHeight)(_this.node, !_this.isCollapsed())
542
+ };
543
+ });
538
544
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
539
545
  this.renderKey = (0, _v.default)();
540
546
  if ((0, _expValEquals.expValEquals)('platform_editor_vc90_transition_expand_icon', 'isEnabled', true)) {
@@ -623,14 +629,31 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
623
629
  }, {
624
630
  key: "updateDisplayStyle",
625
631
  value: function updateDisplayStyle(node) {
632
+ var isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
626
633
  if (this.content) {
627
- var isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
628
634
  if (isCollapsed) {
629
635
  this.content.classList.add(_styles.expandClassNames.contentCollapsed);
630
636
  } else {
631
637
  this.content.classList.remove(_styles.expandClassNames.contentCollapsed);
632
638
  }
633
639
  }
640
+ // Collapsed vs expanded changes the reserved height, so re-apply the intrinsic-size estimate.
641
+ if (this.dom) {
642
+ (0, _contentVisibility.applyContentVisibility)(this.dom, this.isLimitedModeEnabled(), function () {
643
+ return {
644
+ height: (0, _contentVisibility.estimateExpandIntrinsicHeight)(node, !isCollapsed)
645
+ };
646
+ });
647
+ }
648
+ }
649
+ }, {
650
+ key: "isLimitedModeEnabled",
651
+ value: function isLimitedModeEnabled() {
652
+ var _this$api9;
653
+ // Read from `this.view.state` via the exposed plugin key rather than the shared state's
654
+ // `enabled`, which reads a stale `false` during initial EditorView construction (the injection
655
+ // API's editor state isn't wired up yet).
656
+ return Boolean((_this$api9 = this.api) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedMode) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.sharedState.currentState()) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedModePluginKey) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.getState(this.view.state)) === null || _this$api9 === void 0 ? void 0 : _this$api9.documentSizeBreachesThreshold);
634
657
  }
635
658
  }, {
636
659
  key: "stopEvent",
@@ -658,6 +681,14 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
658
681
  value: function update(node, _decorations) {
659
682
  var _this4 = this;
660
683
  if (this.node.type === node.type) {
684
+ // Re-apply in case limited mode flipped from disabled→enabled after the document loaded
685
+ // (the flip is transaction-driven, so this update() fires once it becomes enabled).
686
+ var isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
687
+ (0, _contentVisibility.applyContentVisibility)(this.dom, this.isLimitedModeEnabled(), function () {
688
+ return {
689
+ height: (0, _contentVisibility.estimateExpandIntrinsicHeight)(node, !isCollapsed)
690
+ };
691
+ });
661
692
  if (this.node.attrs.__expanded !== node.attrs.__expanded) {
662
693
  // Instead of re-rendering the view on an expand toggle
663
694
  // we toggle a class name to hide the content and animate the chevron.
@@ -12,13 +12,14 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
12
12
  var _react = _interopRequireDefault(require("react"));
13
13
  var _v = _interopRequireDefault(require("uuid/v4"));
14
14
  var _w3cKeyname = require("w3c-keyname");
15
- var _coreUtils = require("@atlaskit/editor-common/core-utils");
16
15
  var _expand = require("@atlaskit/editor-common/expand");
17
16
  var _selection = require("@atlaskit/editor-common/selection");
18
17
  var _styles = require("@atlaskit/editor-common/styles");
19
18
  var _utils = require("@atlaskit/editor-common/utils");
19
+ var _contentVisibility = require("@atlaskit/editor-common/utils/content-visibility");
20
20
  var _model = require("@atlaskit/editor-prosemirror/model");
21
21
  var _state = require("@atlaskit/editor-prosemirror/state");
22
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
22
23
  var _prosemirrorHistory = require("@atlaskit/prosemirror-history");
23
24
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
24
25
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
@@ -496,7 +497,7 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
496
497
  this.isExpanded.localId = _node.attrs.localId;
497
498
  }
498
499
  var editorDisabled = api === null || api === void 0 || (_api$editorDisabled = api.editorDisabled) === null || _api$editorDisabled === void 0 || (_api$editorDisabled = _api$editorDisabled.sharedState.currentState()) === null || _api$editorDisabled === void 0 ? void 0 : _api$editorDisabled.editorDisabled;
499
- var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, (0, _NodeView.toDOM)(_node, this.__livePage, this.intl, editorDisabled, (0, _coreUtils.isSSRStreaming)() ? !editorDisabled && !(0, _expand.isExpandCollapsed)(_node) : undefined)),
500
+ var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, (0, _NodeView.toDOM)(_node, this.__livePage, this.intl, editorDisabled, !editorDisabled && !(0, _expand.isExpandCollapsed)(_node))),
500
501
  _dom = _DOMSerializer$render.dom,
501
502
  contentDOM = _DOMSerializer$render.contentDOM;
502
503
  // Ignored via go/ees005
@@ -516,6 +517,11 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
516
517
  if (!_expand.expandedState.has(this.node)) {
517
518
  _expand.expandedState.set(this.node, false);
518
519
  }
520
+ (0, _contentVisibility.applyContentVisibility)(this.dom, this.isLimitedModeEnabled(), function () {
521
+ return {
522
+ height: (0, _contentVisibility.estimateExpandIntrinsicHeight)(_this.node, !(0, _expand.isExpandCollapsed)(_this.node))
523
+ };
524
+ });
519
525
  if ((0, _expValEquals.expValEquals)('platform_editor_vc90_transition_expand_icon', 'isEnabled', true)) {
520
526
  this.renderNativeIcon(this.node);
521
527
  } else {
@@ -537,19 +543,39 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
537
543
  this.titleContainer.addEventListener('focus', this.handleFocus);
538
544
  this.icon.addEventListener('keydown', this.handleIconKeyDown);
539
545
  if ((_this$api8 = this.api) !== null && _this$api8 !== void 0 && _this$api8.editorDisabled) {
540
- this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(function (sharedState) {
541
- var editorDisabled = sharedState.nextSharedState.editorDisabled;
542
- if (_this.input) {
543
- if (editorDisabled) {
544
- _this.input.setAttribute('readonly', 'true');
545
- } else {
546
- _this.input.removeAttribute('readonly');
547
- }
548
- }
549
- if (_this.content) {
550
- _this.content.setAttribute('contenteditable', _this.getContentEditable(_this.node) ? 'true' : 'false');
546
+ if ((0, _isExperimentEnabled.isExperimentEnabled)('cc_editor_limited_mode_perf_improvements')) {
547
+ if (this.content) {
548
+ this.content.setAttribute('contenteditable', this.getContentEditable(this.node) ? 'true' : 'false');
551
549
  }
552
- });
550
+ this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(function (sharedState) {
551
+ var editorDisabled = sharedState.nextSharedState.editorDisabled;
552
+ if (_this.input) {
553
+ if (editorDisabled) {
554
+ _this.input.setAttribute('readonly', 'true');
555
+ } else {
556
+ _this.input.removeAttribute('readonly');
557
+ }
558
+ }
559
+ var nextContentEditableValue = _this.getContentEditable(_this.node) ? 'true' : 'false';
560
+ if (_this.content && _this.content.getAttribute('contenteditable') !== nextContentEditableValue) {
561
+ _this.content.setAttribute('contenteditable', nextContentEditableValue);
562
+ }
563
+ });
564
+ } else {
565
+ this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(function (sharedState) {
566
+ var editorDisabled = sharedState.nextSharedState.editorDisabled;
567
+ if (_this.input) {
568
+ if (editorDisabled) {
569
+ _this.input.setAttribute('readonly', 'true');
570
+ } else {
571
+ _this.input.removeAttribute('readonly');
572
+ }
573
+ }
574
+ if (_this.content) {
575
+ _this.content.setAttribute('contenteditable', _this.getContentEditable(_this.node) ? 'true' : 'false');
576
+ }
577
+ });
578
+ }
553
579
  }
554
580
  }
555
581
  return (0, _createClass2.default)(ExpandNodeView, [{
@@ -599,6 +625,13 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
599
625
  }
600
626
  }
601
627
  this.node = node;
628
+ // Re-apply in case limited mode flipped from disabled→enabled after the document loaded
629
+ // (the flip is transaction-driven, so this update() fires once it becomes enabled).
630
+ (0, _contentVisibility.applyContentVisibility)(this.dom, this.isLimitedModeEnabled(), function () {
631
+ return {
632
+ height: (0, _contentVisibility.estimateExpandIntrinsicHeight)(_this2.node, !(0, _expand.isExpandCollapsed)(_this2.node))
633
+ };
634
+ });
602
635
  var currentExpanded = (_expandedState$get2 = _expand.expandedState.get(node)) !== null && _expandedState$get2 !== void 0 ? _expandedState$get2 : false;
603
636
  var hasChanged = (0, _experiments.editorExperiment)('platform_editor_block_menu', true, {
604
637
  exposure: true
@@ -640,6 +673,15 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
640
673
  expanded: expanded !== null && expanded !== void 0 ? expanded : false
641
674
  };
642
675
  }
676
+ }, {
677
+ key: "isLimitedModeEnabled",
678
+ value: function isLimitedModeEnabled() {
679
+ var _this$api9;
680
+ // Read from `this.view.state` via the exposed plugin key rather than the shared state's
681
+ // `enabled`, which reads a stale `false` during initial EditorView construction (the injection
682
+ // API's editor state isn't wired up yet).
683
+ return Boolean((_this$api9 = this.api) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedMode) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.sharedState.currentState()) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedModePluginKey) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.getState(this.view.state)) === null || _this$api9 === void 0 ? void 0 : _this$api9.documentSizeBreachesThreshold);
684
+ }
643
685
  }, {
644
686
  key: "updateDisplayStyle",
645
687
  value: function updateDisplayStyle(node) {
@@ -650,6 +692,12 @@ var ExpandNodeView = exports.ExpandNodeView = /*#__PURE__*/function () {
650
692
  this.content.classList.remove(_styles.expandClassNames.contentCollapsed);
651
693
  }
652
694
  }
695
+ // Collapsed vs expanded changes the reserved height, so re-apply the intrinsic-size estimate.
696
+ (0, _contentVisibility.applyContentVisibility)(this.dom, this.isLimitedModeEnabled(), function () {
697
+ return {
698
+ height: (0, _contentVisibility.estimateExpandIntrinsicHeight)(node, !(0, _expand.isExpandCollapsed)(node))
699
+ };
700
+ });
653
701
  }
654
702
  }, {
655
703
  key: "updateExpandBodyContentEditable",
@@ -7,6 +7,7 @@ import { GapCursorSelection, RelativeSelectionPos, Side } from '@atlaskit/editor
7
7
  import { expandClassNames } from '@atlaskit/editor-common/styles';
8
8
  import { expandMessages } from '@atlaskit/editor-common/ui';
9
9
  import { closestElement, isEmptyNode } from '@atlaskit/editor-common/utils';
10
+ import { applyContentVisibility, estimateExpandIntrinsicHeight } from '@atlaskit/editor-common/utils/content-visibility';
10
11
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
11
12
  import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
12
13
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -543,6 +544,9 @@ export class ExpandNodeView {
543
544
  this.input = this.dom.querySelector(`.${expandClassNames.titleInput}`);
544
545
  this.titleContainer = this.dom.querySelector(`.${expandClassNames.titleContainer}`);
545
546
  this.content = this.dom.querySelector(`.${expandClassNames.content}`);
547
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), () => ({
548
+ height: estimateExpandIntrinsicHeight(this.node, !this.isCollapsed())
549
+ }));
546
550
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
547
551
  this.renderKey = uuid();
548
552
  if (expValEquals('platform_editor_vc90_transition_expand_icon', 'isEnabled', true)) {
@@ -622,14 +626,27 @@ export class ExpandNodeView {
622
626
  }), this.icon, this.renderKey);
623
627
  }
624
628
  updateDisplayStyle(node) {
629
+ const isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
625
630
  if (this.content) {
626
- const isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
627
631
  if (isCollapsed) {
628
632
  this.content.classList.add(expandClassNames.contentCollapsed);
629
633
  } else {
630
634
  this.content.classList.remove(expandClassNames.contentCollapsed);
631
635
  }
632
636
  }
637
+ // Collapsed vs expanded changes the reserved height, so re-apply the intrinsic-size estimate.
638
+ if (this.dom) {
639
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), () => ({
640
+ height: estimateExpandIntrinsicHeight(node, !isCollapsed)
641
+ }));
642
+ }
643
+ }
644
+ isLimitedModeEnabled() {
645
+ var _this$api9, _this$api9$limitedMod, _this$api9$limitedMod2, _this$api9$limitedMod3, _this$api9$limitedMod4;
646
+ // Read from `this.view.state` via the exposed plugin key rather than the shared state's
647
+ // `enabled`, which reads a stale `false` during initial EditorView construction (the injection
648
+ // API's editor state isn't wired up yet).
649
+ return Boolean((_this$api9 = this.api) === null || _this$api9 === void 0 ? void 0 : (_this$api9$limitedMod = _this$api9.limitedMode) === null || _this$api9$limitedMod === void 0 ? void 0 : (_this$api9$limitedMod2 = _this$api9$limitedMod.sharedState.currentState()) === null || _this$api9$limitedMod2 === void 0 ? void 0 : (_this$api9$limitedMod3 = _this$api9$limitedMod2.limitedModePluginKey) === null || _this$api9$limitedMod3 === void 0 ? void 0 : (_this$api9$limitedMod4 = _this$api9$limitedMod3.getState(this.view.state)) === null || _this$api9$limitedMod4 === void 0 ? void 0 : _this$api9$limitedMod4.documentSizeBreachesThreshold);
633
650
  }
634
651
  stopEvent(event) {
635
652
  // Ignored via go/ees005
@@ -650,6 +667,12 @@ export class ExpandNodeView {
650
667
  }
651
668
  update(node, _decorations) {
652
669
  if (this.node.type === node.type) {
670
+ // Re-apply in case limited mode flipped from disabled→enabled after the document loaded
671
+ // (the flip is transaction-driven, so this update() fires once it becomes enabled).
672
+ const isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
673
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), () => ({
674
+ height: estimateExpandIntrinsicHeight(node, !isCollapsed)
675
+ }));
653
676
  if (this.node.attrs.__expanded !== node.attrs.__expanded) {
654
677
  // Instead of re-rendering the view on an expand toggle
655
678
  // we toggle a class name to hide the content and animate the chevron.
@@ -3,13 +3,14 @@ import React from 'react';
3
3
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
4
4
  import uuid from 'uuid/v4';
5
5
  import { keyName } from 'w3c-keyname';
6
- import { isSSRStreaming } from '@atlaskit/editor-common/core-utils';
7
6
  import { expandedState, isExpandCollapsed } from '@atlaskit/editor-common/expand';
8
7
  import { GapCursorSelection, RelativeSelectionPos, Side } from '@atlaskit/editor-common/selection';
9
8
  import { expandClassNames } from '@atlaskit/editor-common/styles';
10
9
  import { closestElement, isEmptyNode } from '@atlaskit/editor-common/utils';
10
+ import { applyContentVisibility, estimateExpandIntrinsicHeight } from '@atlaskit/editor-common/utils/content-visibility';
11
11
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
12
12
  import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
13
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
13
14
  import { redo, undo } from '@atlaskit/prosemirror-history';
14
15
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
15
16
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
@@ -502,7 +503,7 @@ export class ExpandNodeView {
502
503
  const {
503
504
  dom: _dom,
504
505
  contentDOM
505
- } = DOMSerializer.renderSpec(document, toDOM(_node, this.__livePage, this.intl, editorDisabled, isSSRStreaming() ? !editorDisabled && !isExpandCollapsed(_node) : undefined));
506
+ } = DOMSerializer.renderSpec(document, toDOM(_node, this.__livePage, this.intl, editorDisabled, !editorDisabled && !isExpandCollapsed(_node)));
506
507
  // Ignored via go/ees005
507
508
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
508
509
  this.dom = _dom;
@@ -520,6 +521,9 @@ export class ExpandNodeView {
520
521
  if (!expandedState.has(this.node)) {
521
522
  expandedState.set(this.node, false);
522
523
  }
524
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), () => ({
525
+ height: estimateExpandIntrinsicHeight(this.node, !isExpandCollapsed(this.node))
526
+ }));
523
527
  if (expValEquals('platform_editor_vc90_transition_expand_icon', 'isEnabled', true)) {
524
528
  this.renderNativeIcon(this.node);
525
529
  } else {
@@ -541,19 +545,39 @@ export class ExpandNodeView {
541
545
  this.titleContainer.addEventListener('focus', this.handleFocus);
542
546
  this.icon.addEventListener('keydown', this.handleIconKeyDown);
543
547
  if ((_this$api8 = this.api) !== null && _this$api8 !== void 0 && _this$api8.editorDisabled) {
544
- this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(sharedState => {
545
- const editorDisabled = sharedState.nextSharedState.editorDisabled;
546
- if (this.input) {
547
- if (editorDisabled) {
548
- this.input.setAttribute('readonly', 'true');
549
- } else {
550
- this.input.removeAttribute('readonly');
551
- }
552
- }
548
+ if (isExperimentEnabled('cc_editor_limited_mode_perf_improvements')) {
553
549
  if (this.content) {
554
550
  this.content.setAttribute('contenteditable', this.getContentEditable(this.node) ? 'true' : 'false');
555
551
  }
556
- });
552
+ this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(sharedState => {
553
+ const editorDisabled = sharedState.nextSharedState.editorDisabled;
554
+ if (this.input) {
555
+ if (editorDisabled) {
556
+ this.input.setAttribute('readonly', 'true');
557
+ } else {
558
+ this.input.removeAttribute('readonly');
559
+ }
560
+ }
561
+ const nextContentEditableValue = this.getContentEditable(this.node) ? 'true' : 'false';
562
+ if (this.content && this.content.getAttribute('contenteditable') !== nextContentEditableValue) {
563
+ this.content.setAttribute('contenteditable', nextContentEditableValue);
564
+ }
565
+ });
566
+ } else {
567
+ this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(sharedState => {
568
+ const editorDisabled = sharedState.nextSharedState.editorDisabled;
569
+ if (this.input) {
570
+ if (editorDisabled) {
571
+ this.input.setAttribute('readonly', 'true');
572
+ } else {
573
+ this.input.removeAttribute('readonly');
574
+ }
575
+ }
576
+ if (this.content) {
577
+ this.content.setAttribute('contenteditable', this.getContentEditable(this.node) ? 'true' : 'false');
578
+ }
579
+ });
580
+ }
557
581
  }
558
582
  }
559
583
  stopEvent(event) {
@@ -596,6 +620,11 @@ export class ExpandNodeView {
596
620
  }
597
621
  }
598
622
  this.node = node;
623
+ // Re-apply in case limited mode flipped from disabled→enabled after the document loaded
624
+ // (the flip is transaction-driven, so this update() fires once it becomes enabled).
625
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), () => ({
626
+ height: estimateExpandIntrinsicHeight(this.node, !isExpandCollapsed(this.node))
627
+ }));
599
628
  const currentExpanded = (_expandedState$get2 = expandedState.get(node)) !== null && _expandedState$get2 !== void 0 ? _expandedState$get2 : false;
600
629
  const hasChanged = editorExperiment('platform_editor_block_menu', true, {
601
630
  exposure: true
@@ -633,6 +662,13 @@ export class ExpandNodeView {
633
662
  expanded: expanded !== null && expanded !== void 0 ? expanded : false
634
663
  };
635
664
  }
665
+ isLimitedModeEnabled() {
666
+ var _this$api9, _this$api9$limitedMod, _this$api9$limitedMod2, _this$api9$limitedMod3, _this$api9$limitedMod4;
667
+ // Read from `this.view.state` via the exposed plugin key rather than the shared state's
668
+ // `enabled`, which reads a stale `false` during initial EditorView construction (the injection
669
+ // API's editor state isn't wired up yet).
670
+ return Boolean((_this$api9 = this.api) === null || _this$api9 === void 0 ? void 0 : (_this$api9$limitedMod = _this$api9.limitedMode) === null || _this$api9$limitedMod === void 0 ? void 0 : (_this$api9$limitedMod2 = _this$api9$limitedMod.sharedState.currentState()) === null || _this$api9$limitedMod2 === void 0 ? void 0 : (_this$api9$limitedMod3 = _this$api9$limitedMod2.limitedModePluginKey) === null || _this$api9$limitedMod3 === void 0 ? void 0 : (_this$api9$limitedMod4 = _this$api9$limitedMod3.getState(this.view.state)) === null || _this$api9$limitedMod4 === void 0 ? void 0 : _this$api9$limitedMod4.documentSizeBreachesThreshold);
671
+ }
636
672
  updateDisplayStyle(node) {
637
673
  if (this.content) {
638
674
  if (isExpandCollapsed(node)) {
@@ -641,6 +677,10 @@ export class ExpandNodeView {
641
677
  this.content.classList.remove(expandClassNames.contentCollapsed);
642
678
  }
643
679
  }
680
+ // Collapsed vs expanded changes the reserved height, so re-apply the intrinsic-size estimate.
681
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), () => ({
682
+ height: estimateExpandIntrinsicHeight(node, !isExpandCollapsed(node))
683
+ }));
644
684
  }
645
685
  updateExpandBodyContentEditable() {
646
686
  // Disallow interaction/selection inside expand body when collapsed.
@@ -11,6 +11,7 @@ import { GapCursorSelection, RelativeSelectionPos, Side } from '@atlaskit/editor
11
11
  import { expandClassNames } from '@atlaskit/editor-common/styles';
12
12
  import { expandMessages } from '@atlaskit/editor-common/ui';
13
13
  import { closestElement, isEmptyNode } from '@atlaskit/editor-common/utils';
14
+ import { applyContentVisibility, estimateExpandIntrinsicHeight } from '@atlaskit/editor-common/utils/content-visibility';
14
15
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
15
16
  import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
16
17
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -528,6 +529,11 @@ export var ExpandNodeView = /*#__PURE__*/function () {
528
529
  this.input = this.dom.querySelector(".".concat(expandClassNames.titleInput));
529
530
  this.titleContainer = this.dom.querySelector(".".concat(expandClassNames.titleContainer));
530
531
  this.content = this.dom.querySelector(".".concat(expandClassNames.content));
532
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), function () {
533
+ return {
534
+ height: estimateExpandIntrinsicHeight(_this.node, !_this.isCollapsed())
535
+ };
536
+ });
531
537
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
532
538
  this.renderKey = uuid();
533
539
  if (expValEquals('platform_editor_vc90_transition_expand_icon', 'isEnabled', true)) {
@@ -616,14 +622,31 @@ export var ExpandNodeView = /*#__PURE__*/function () {
616
622
  }, {
617
623
  key: "updateDisplayStyle",
618
624
  value: function updateDisplayStyle(node) {
625
+ var isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
619
626
  if (this.content) {
620
- var isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
621
627
  if (isCollapsed) {
622
628
  this.content.classList.add(expandClassNames.contentCollapsed);
623
629
  } else {
624
630
  this.content.classList.remove(expandClassNames.contentCollapsed);
625
631
  }
626
632
  }
633
+ // Collapsed vs expanded changes the reserved height, so re-apply the intrinsic-size estimate.
634
+ if (this.dom) {
635
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), function () {
636
+ return {
637
+ height: estimateExpandIntrinsicHeight(node, !isCollapsed)
638
+ };
639
+ });
640
+ }
641
+ }
642
+ }, {
643
+ key: "isLimitedModeEnabled",
644
+ value: function isLimitedModeEnabled() {
645
+ var _this$api9;
646
+ // Read from `this.view.state` via the exposed plugin key rather than the shared state's
647
+ // `enabled`, which reads a stale `false` during initial EditorView construction (the injection
648
+ // API's editor state isn't wired up yet).
649
+ return Boolean((_this$api9 = this.api) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedMode) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.sharedState.currentState()) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedModePluginKey) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.getState(this.view.state)) === null || _this$api9 === void 0 ? void 0 : _this$api9.documentSizeBreachesThreshold);
627
650
  }
628
651
  }, {
629
652
  key: "stopEvent",
@@ -651,6 +674,14 @@ export var ExpandNodeView = /*#__PURE__*/function () {
651
674
  value: function update(node, _decorations) {
652
675
  var _this4 = this;
653
676
  if (this.node.type === node.type) {
677
+ // Re-apply in case limited mode flipped from disabled→enabled after the document loaded
678
+ // (the flip is transaction-driven, so this update() fires once it becomes enabled).
679
+ var isCollapsed = this.__livePage ? node.attrs.__expanded : !node.attrs.__expanded;
680
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), function () {
681
+ return {
682
+ height: estimateExpandIntrinsicHeight(node, !isCollapsed)
683
+ };
684
+ });
654
685
  if (this.node.attrs.__expanded !== node.attrs.__expanded) {
655
686
  // Instead of re-rendering the view on an expand toggle
656
687
  // we toggle a class name to hide the content and animate the chevron.
@@ -5,13 +5,14 @@ import React from 'react';
5
5
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
6
6
  import uuid from 'uuid/v4';
7
7
  import { keyName } from 'w3c-keyname';
8
- import { isSSRStreaming } from '@atlaskit/editor-common/core-utils';
9
8
  import { expandedState, isExpandCollapsed } from '@atlaskit/editor-common/expand';
10
9
  import { GapCursorSelection, RelativeSelectionPos, Side } from '@atlaskit/editor-common/selection';
11
10
  import { expandClassNames } from '@atlaskit/editor-common/styles';
12
11
  import { closestElement, isEmptyNode } from '@atlaskit/editor-common/utils';
12
+ import { applyContentVisibility, estimateExpandIntrinsicHeight } from '@atlaskit/editor-common/utils/content-visibility';
13
13
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
14
14
  import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
15
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
15
16
  import { redo, undo } from '@atlaskit/prosemirror-history';
16
17
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
17
18
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
@@ -488,7 +489,7 @@ export var ExpandNodeView = /*#__PURE__*/function () {
488
489
  this.isExpanded.localId = _node.attrs.localId;
489
490
  }
490
491
  var editorDisabled = api === null || api === void 0 || (_api$editorDisabled = api.editorDisabled) === null || _api$editorDisabled === void 0 || (_api$editorDisabled = _api$editorDisabled.sharedState.currentState()) === null || _api$editorDisabled === void 0 ? void 0 : _api$editorDisabled.editorDisabled;
491
- var _DOMSerializer$render = DOMSerializer.renderSpec(document, toDOM(_node, this.__livePage, this.intl, editorDisabled, isSSRStreaming() ? !editorDisabled && !isExpandCollapsed(_node) : undefined)),
492
+ var _DOMSerializer$render = DOMSerializer.renderSpec(document, toDOM(_node, this.__livePage, this.intl, editorDisabled, !editorDisabled && !isExpandCollapsed(_node))),
492
493
  _dom = _DOMSerializer$render.dom,
493
494
  contentDOM = _DOMSerializer$render.contentDOM;
494
495
  // Ignored via go/ees005
@@ -508,6 +509,11 @@ export var ExpandNodeView = /*#__PURE__*/function () {
508
509
  if (!expandedState.has(this.node)) {
509
510
  expandedState.set(this.node, false);
510
511
  }
512
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), function () {
513
+ return {
514
+ height: estimateExpandIntrinsicHeight(_this.node, !isExpandCollapsed(_this.node))
515
+ };
516
+ });
511
517
  if (expValEquals('platform_editor_vc90_transition_expand_icon', 'isEnabled', true)) {
512
518
  this.renderNativeIcon(this.node);
513
519
  } else {
@@ -529,19 +535,39 @@ export var ExpandNodeView = /*#__PURE__*/function () {
529
535
  this.titleContainer.addEventListener('focus', this.handleFocus);
530
536
  this.icon.addEventListener('keydown', this.handleIconKeyDown);
531
537
  if ((_this$api8 = this.api) !== null && _this$api8 !== void 0 && _this$api8.editorDisabled) {
532
- this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(function (sharedState) {
533
- var editorDisabled = sharedState.nextSharedState.editorDisabled;
534
- if (_this.input) {
535
- if (editorDisabled) {
536
- _this.input.setAttribute('readonly', 'true');
537
- } else {
538
- _this.input.removeAttribute('readonly');
539
- }
540
- }
541
- if (_this.content) {
542
- _this.content.setAttribute('contenteditable', _this.getContentEditable(_this.node) ? 'true' : 'false');
538
+ if (isExperimentEnabled('cc_editor_limited_mode_perf_improvements')) {
539
+ if (this.content) {
540
+ this.content.setAttribute('contenteditable', this.getContentEditable(this.node) ? 'true' : 'false');
543
541
  }
544
- });
542
+ this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(function (sharedState) {
543
+ var editorDisabled = sharedState.nextSharedState.editorDisabled;
544
+ if (_this.input) {
545
+ if (editorDisabled) {
546
+ _this.input.setAttribute('readonly', 'true');
547
+ } else {
548
+ _this.input.removeAttribute('readonly');
549
+ }
550
+ }
551
+ var nextContentEditableValue = _this.getContentEditable(_this.node) ? 'true' : 'false';
552
+ if (_this.content && _this.content.getAttribute('contenteditable') !== nextContentEditableValue) {
553
+ _this.content.setAttribute('contenteditable', nextContentEditableValue);
554
+ }
555
+ });
556
+ } else {
557
+ this.cleanUpEditorDisabledOnChange = this.api.editorDisabled.sharedState.onChange(function (sharedState) {
558
+ var editorDisabled = sharedState.nextSharedState.editorDisabled;
559
+ if (_this.input) {
560
+ if (editorDisabled) {
561
+ _this.input.setAttribute('readonly', 'true');
562
+ } else {
563
+ _this.input.removeAttribute('readonly');
564
+ }
565
+ }
566
+ if (_this.content) {
567
+ _this.content.setAttribute('contenteditable', _this.getContentEditable(_this.node) ? 'true' : 'false');
568
+ }
569
+ });
570
+ }
545
571
  }
546
572
  }
547
573
  return _createClass(ExpandNodeView, [{
@@ -591,6 +617,13 @@ export var ExpandNodeView = /*#__PURE__*/function () {
591
617
  }
592
618
  }
593
619
  this.node = node;
620
+ // Re-apply in case limited mode flipped from disabled→enabled after the document loaded
621
+ // (the flip is transaction-driven, so this update() fires once it becomes enabled).
622
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), function () {
623
+ return {
624
+ height: estimateExpandIntrinsicHeight(_this2.node, !isExpandCollapsed(_this2.node))
625
+ };
626
+ });
594
627
  var currentExpanded = (_expandedState$get2 = expandedState.get(node)) !== null && _expandedState$get2 !== void 0 ? _expandedState$get2 : false;
595
628
  var hasChanged = editorExperiment('platform_editor_block_menu', true, {
596
629
  exposure: true
@@ -632,6 +665,15 @@ export var ExpandNodeView = /*#__PURE__*/function () {
632
665
  expanded: expanded !== null && expanded !== void 0 ? expanded : false
633
666
  };
634
667
  }
668
+ }, {
669
+ key: "isLimitedModeEnabled",
670
+ value: function isLimitedModeEnabled() {
671
+ var _this$api9;
672
+ // Read from `this.view.state` via the exposed plugin key rather than the shared state's
673
+ // `enabled`, which reads a stale `false` during initial EditorView construction (the injection
674
+ // API's editor state isn't wired up yet).
675
+ return Boolean((_this$api9 = this.api) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedMode) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.sharedState.currentState()) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.limitedModePluginKey) === null || _this$api9 === void 0 || (_this$api9 = _this$api9.getState(this.view.state)) === null || _this$api9 === void 0 ? void 0 : _this$api9.documentSizeBreachesThreshold);
676
+ }
635
677
  }, {
636
678
  key: "updateDisplayStyle",
637
679
  value: function updateDisplayStyle(node) {
@@ -642,6 +684,12 @@ export var ExpandNodeView = /*#__PURE__*/function () {
642
684
  this.content.classList.remove(expandClassNames.contentCollapsed);
643
685
  }
644
686
  }
687
+ // Collapsed vs expanded changes the reserved height, so re-apply the intrinsic-size estimate.
688
+ applyContentVisibility(this.dom, this.isLimitedModeEnabled(), function () {
689
+ return {
690
+ height: estimateExpandIntrinsicHeight(node, !isExpandCollapsed(node))
691
+ };
692
+ });
645
693
  }
646
694
  }, {
647
695
  key: "updateExpandBodyContentEditable",
@@ -50,6 +50,7 @@ export declare class ExpandNodeView implements NodeView {
50
50
  private handleRedoFromTitle;
51
51
  private getContentEditable;
52
52
  private updateDisplayStyle;
53
+ private isLimitedModeEnabled;
53
54
  stopEvent(event: Event): boolean;
54
55
  ignoreMutation(mutationRecord: MutationRecord | {
55
56
  target: Node;
@@ -57,6 +57,7 @@ export declare class ExpandNodeView implements NodeView {
57
57
  }): boolean;
58
58
  update(node: PmNode, _decorations: readonly Decoration[]): boolean;
59
59
  updateExpandToggleIcon(node: PmNode): void;
60
+ private isLimitedModeEnabled;
60
61
  private updateDisplayStyle;
61
62
  updateExpandBodyContentEditable(): void;
62
63
  private renderNativeIcon;
@@ -7,6 +7,7 @@ import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
7
7
  import type { EditorDisabledPlugin } from '@atlaskit/editor-plugin-editor-disabled';
8
8
  import type { EditorViewModePlugin } from '@atlaskit/editor-plugin-editor-viewmode';
9
9
  import type { FeatureFlagsPlugin } from '@atlaskit/editor-plugin-feature-flags';
10
+ import type { LimitedModePlugin } from '@atlaskit/editor-plugin-limited-mode/limited-mode-plugin-type';
10
11
  import type { LocalIdPlugin } from '@atlaskit/editor-plugin-local-id';
11
12
  import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
12
13
  import type { SelectionMarkerPlugin } from '@atlaskit/editor-plugin-selection-marker';
@@ -53,6 +54,7 @@ export type ExpandPluginDependencies = [
53
54
  OptionalPlugin<EditorDisabledPlugin>,
54
55
  OptionalPlugin<FeatureFlagsPlugin>,
55
56
  OptionalPlugin<EditorViewModePlugin>,
57
+ OptionalPlugin<LimitedModePlugin>,
56
58
  OptionalPlugin<BlockMenuPlugin>,
57
59
  OptionalPlugin<LocalIdPlugin>,
58
60
  OptionalPlugin<BlockControlsPlugin>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-expand",
3
- "version": "15.0.5",
3
+ "version": "15.2.0",
4
4
  "description": "Expand plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -29,6 +29,7 @@
29
29
  "@atlaskit/editor-plugin-decorations": "^14.0.0",
30
30
  "@atlaskit/editor-plugin-editor-disabled": "^14.0.0",
31
31
  "@atlaskit/editor-plugin-editor-viewmode": "^16.0.0",
32
+ "@atlaskit/editor-plugin-limited-mode": "^11.0.0",
32
33
  "@atlaskit/editor-plugin-local-id": "^12.0.0",
33
34
  "@atlaskit/editor-plugin-selection": "^14.0.0",
34
35
  "@atlaskit/editor-plugin-selection-marker": "^14.0.0",
@@ -38,9 +39,10 @@
38
39
  "@atlaskit/editor-toolbar": "^2.4.0",
39
40
  "@atlaskit/icon": "^37.3.0",
40
41
  "@atlaskit/icon-lab": "^7.5.0",
42
+ "@atlaskit/platform-feature-experiments": "^0.3.0",
41
43
  "@atlaskit/platform-feature-flags": "^2.1.0",
42
44
  "@atlaskit/prosemirror-history": "^1.1.0",
43
- "@atlaskit/tmp-editor-statsig": "^147.0.0",
45
+ "@atlaskit/tmp-editor-statsig": "^147.1.0",
44
46
  "@atlaskit/tokens": "^16.7.0",
45
47
  "@atlaskit/tooltip": "^24.0.0",
46
48
  "@babel/runtime": "^7.0.0",
@@ -49,7 +51,7 @@
49
51
  "w3c-keyname": "^2.1.8"
50
52
  },
51
53
  "peerDependencies": {
52
- "@atlaskit/editor-common": "^118.10.0",
54
+ "@atlaskit/editor-common": "^118.12.0",
53
55
  "react": "^18.2.0 || ^19.2.0",
54
56
  "react-dom": "^18.2.0 || ^19.2.0",
55
57
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"