@atlaskit/editor-plugin-block-controls 1.12.10 → 1.13.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,18 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 1.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#137234](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/137234)
8
+ [`e80c81de138e9`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/e80c81de138e9) -
9
+ [ux] [ED-24803] Experiment for editor block controls which adds a button to insert quickInsert
10
+ elements
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+
3
16
  ## 1.12.10
4
17
 
5
18
  ### Patch Changes
@@ -5,8 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.blockControlsPlugin = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
8
9
  var _react = _interopRequireDefault(require("react"));
10
+ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
9
11
  var _moveNode = require("./commands/move-node");
12
+ var _emptyBlockExperiment = require("./pm-plugins/empty-block-experiment");
10
13
  var _main = require("./pm-plugins/main");
11
14
  var _dragHandleMenu = require("./ui/drag-handle-menu");
12
15
  var _globalStyles = require("./ui/global-styles");
@@ -22,13 +25,21 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
22
25
  var getIntl = _ref2.getIntl;
23
26
  return (0, _main.createPlugin)(api, getIntl);
24
27
  }
25
- }];
28
+ }].concat((0, _toConsumableArray2.default)((0, _experiments.editorExperiment)('platform_editor_empty_line_prompt', true, {
29
+ exposure: true
30
+ }) ? [{
31
+ name: 'emptyBlockExperimentPlugin',
32
+ plugin: function plugin(_ref3) {
33
+ var getIntl = _ref3.getIntl;
34
+ return (0, _emptyBlockExperiment.createEmptyBlockExperimentPlugin)(api, getIntl);
35
+ }
36
+ }] : []));
26
37
  },
27
38
  commands: {
28
39
  moveNode: (0, _moveNode.moveNode)(api),
29
40
  showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions) {
30
- return function (_ref3) {
31
- var tr = _ref3.tr;
41
+ return function (_ref4) {
42
+ var tr = _ref4.tr;
32
43
  tr.setMeta(_main.key, {
33
44
  activeNode: {
34
45
  pos: pos,
@@ -41,8 +52,8 @@ var blockControlsPlugin = exports.blockControlsPlugin = function blockControlsPl
41
52
  };
42
53
  },
43
54
  setNodeDragged: function setNodeDragged(pos, anchorName, nodeType) {
44
- return function (_ref4) {
45
- var tr = _ref4.tr;
55
+ return function (_ref5) {
56
+ var tr = _ref5.tr;
46
57
  if (pos === undefined) {
47
58
  return tr;
48
59
  }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.emptyBlockExperimentPluginKey = exports.createEmptyBlockExperimentPlugin = void 0;
7
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
8
+ var _state = require("@atlaskit/editor-prosemirror/state");
9
+ var _view = require("@atlaskit/editor-prosemirror/view");
10
+ var _widget = require("../ui/empty-block-experiment/widget");
11
+ var emptyBlockExperimentPluginKey = exports.emptyBlockExperimentPluginKey = new _state.PluginKey('emptyBlockExperiment');
12
+ var getDecorations = function getDecorations(tr, api, getIntl) {
13
+ var widget = (0, _widget.createEmptyBlockWidgetDecoration)(tr.selection, api, getIntl);
14
+ if (widget) {
15
+ return _view.DecorationSet.create(tr.doc, [widget]);
16
+ }
17
+ return _view.DecorationSet.empty;
18
+ };
19
+ var createEmptyBlockExperimentPlugin = exports.createEmptyBlockExperimentPlugin = function createEmptyBlockExperimentPlugin(api, getIntl) {
20
+ return new _safePlugin.SafePlugin({
21
+ key: emptyBlockExperimentPluginKey,
22
+ state: {
23
+ init: function init(_, _editorState) {
24
+ return {
25
+ decorations: _view.DecorationSet.empty
26
+ };
27
+ },
28
+ apply: function apply(tr, _currentState) {
29
+ return {
30
+ decorations: getDecorations(tr, api, getIntl)
31
+ };
32
+ }
33
+ },
34
+ props: {
35
+ decorations: function decorations(state) {
36
+ var _emptyBlockExperiment;
37
+ return (_emptyBlockExperiment = emptyBlockExperimentPluginKey.getState(state)) === null || _emptyBlockExperiment === void 0 ? void 0 : _emptyBlockExperiment.decorations;
38
+ }
39
+ }
40
+ });
41
+ };
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.emptyBlockExperimentGlobalStyles = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _react = require("@emotion/react");
10
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
+ /* eslint-disable @atlaskit/ui-styling-standard/no-exported-styles */
12
+ /* eslint-disable @atlaskit/ui-styling-standard/no-unsafe-values */
13
+ /* eslint-disable @atlaskit/ui-styling-standard/no-nested-selectors */
14
+ /* eslint-disable @atlaskit/ui-styling-standard/no-important-styles */
15
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled
16
+
17
+ var emptyBlockExperimentWidget = '.ProseMirror-widget[data-empty-block-experiment="true"]';
18
+ var quickInsertWidget = '.ProseMirror-widget[data-type-ahead="typeaheadDecoration"]';
19
+ var formattingElement = 'div.fabric-editor-block-mark';
20
+ var elementWithEmptyBlockExperiment = "+ p > ".concat(emptyBlockExperimentWidget, ", + h1 > ").concat(emptyBlockExperimentWidget, ", + h2 > ").concat(emptyBlockExperimentWidget, ", + h3 > ").concat(emptyBlockExperimentWidget, ", + h4 > ").concat(emptyBlockExperimentWidget, ", + h5 > ").concat(emptyBlockExperimentWidget, ", + h6 > ").concat(emptyBlockExperimentWidget);
21
+ // Selectors for when contained withing a formatting container mark (eg. indent, centering, right-align)
22
+ var elementWithEmptyBlockExperimentFormatted = "+ ".concat(formattingElement, " > p > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h1 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h2 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h3 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h4 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h5 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h6 > ").concat(emptyBlockExperimentWidget);
23
+ var dragHandleContainer = '.ProseMirror-widget[data-blocks-drag-handle-container="true"]';
24
+ var dragHandleSelector = 'button[data-testid="block-ctrl-drag-handle"]';
25
+
26
+ // Hides the drag handle when the block contains the empty block experiment
27
+ // Override is consistent with how the drag handle is hidden when the block contains a placeholder
28
+ var dragHandleWithInlineNodeStyle = (0, _react.css)((0, _defineProperty2.default)({}, ".ProseMirror-widget[data-blocks-drag-handle-container=\"true\"]:has(".concat(elementWithEmptyBlockExperiment, "), .ProseMirror-widget[data-blocks-drag-handle-container=\"true\"]:has(").concat(elementWithEmptyBlockExperimentFormatted, ")"), {
29
+ display: 'none !important'
30
+ }));
31
+
32
+ // Alternate styling for hiding the drag handle when the block contains the empty block experiment
33
+ // Override is consistent with a feature-gated bugfix that hides the drag handle when the block contains a placeholder
34
+ /**
35
+ * Please do not change change transform to display:none, or visibility:hidden
36
+ * Otherwise it might break composition input for Chrome
37
+ * https://product-fabric.atlassian.net/browse/ED-24136
38
+ */
39
+ var dragHandleWithInlineNodeStyleWithChromeFix = (0, _react.css)((0, _defineProperty2.default)({}, "".concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperiment, ") ").concat(dragHandleSelector, ", ").concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperimentFormatted, ") ").concat(dragHandleSelector), {
40
+ transform: 'scale(0)'
41
+ }));
42
+ var getDragHandleOverrides = function getDragHandleOverrides() {
43
+ return (0, _platformFeatureFlags.fg)('platform_editor_element_controls_chrome_input_fix') ? dragHandleWithInlineNodeStyleWithChromeFix : dragHandleWithInlineNodeStyle;
44
+ };
45
+
46
+ /**
47
+ * Hide the experiment button when it has been activated. (contains quick-insert decoration widget)
48
+ */
49
+ var emptyBlockExperimentGlobalStyles = exports.emptyBlockExperimentGlobalStyles = (0, _react.css)((0, _defineProperty2.default)({}, "".concat(emptyBlockExperimentWidget, ":has(+ ").concat(quickInsertWidget, ") button"), {
50
+ transform: 'scale(0)'
51
+ }), getDragHandleOverrides());
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.createEmptyBlockWidgetDecoration = exports.TypeAheadControl = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactDom = _interopRequireDefault(require("react-dom"));
11
+ var _reactIntlNext = require("react-intl-next");
12
+ var _keymaps = require("@atlaskit/editor-common/keymaps");
13
+ var _messages = require("@atlaskit/editor-common/messages");
14
+ var _whitespace = require("@atlaskit/editor-common/whitespace");
15
+ var _state = require("@atlaskit/editor-prosemirror/state");
16
+ var _view2 = require("@atlaskit/editor-prosemirror/view");
17
+ var _add = _interopRequireDefault(require("@atlaskit/icon/glyph/editor/add"));
18
+ var _primitives = require("@atlaskit/primitives");
19
+ var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
20
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
21
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
22
+ var wrapperStyles = (0, _primitives.xcss)({
23
+ position: 'absolute',
24
+ top: "calc('50%' - ".concat("var(--ds-space-150, 12px)", ")"),
25
+ left: "calc(".concat("var(--ds-space-negative-300, -24px)", " + ", "var(--ds-space-negative-100, -8px)", ")")
26
+ });
27
+ var buttonStyles = (0, _primitives.xcss)({
28
+ boxSizing: 'border-box',
29
+ display: 'flex',
30
+ flexDirection: 'column',
31
+ justifyContent: 'center',
32
+ alignItems: 'center',
33
+ height: "var(--ds-space-300, 24px)",
34
+ width: "var(--ds-space-300, 24px)",
35
+ border: 'none',
36
+ backgroundColor: 'color.background.neutral',
37
+ borderRadius: '50%',
38
+ color: 'color.text',
39
+ zIndex: 'card',
40
+ outline: 'none',
41
+ ':hover': {
42
+ backgroundColor: 'color.background.neutral.hovered'
43
+ },
44
+ ':active': {
45
+ backgroundColor: 'color.background.neutral.pressed'
46
+ },
47
+ ':focus': {
48
+ outline: "2px solid ".concat("var(--ds-border-focused, #388BFF)")
49
+ }
50
+ });
51
+ var TypeAheadControl = exports.TypeAheadControl = function TypeAheadControl(_ref) {
52
+ var api = _ref.api,
53
+ getPos = _ref.getPos,
54
+ formatMessage = _ref.intl.formatMessage;
55
+ return /*#__PURE__*/_react.default.createElement(_primitives.Box, {
56
+ xcss: [wrapperStyles]
57
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
58
+ content: /*#__PURE__*/_react.default.createElement(_keymaps.ToolTipContent, {
59
+ description: formatMessage(_messages.blockControlsMessages.insert),
60
+ shortcutOverride: "/"
61
+ })
62
+ }, /*#__PURE__*/_react.default.createElement(_primitives.Pressable, {
63
+ type: "button",
64
+ "aria-label": formatMessage(_messages.blockControlsMessages.insert),
65
+ xcss: [buttonStyles],
66
+ onClick: function onClick() {
67
+ var _api$core, _api$quickInsert;
68
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
69
+ var tr = _ref2.tr;
70
+ var start = getPos();
71
+ if (!start) {
72
+ return null;
73
+ }
74
+ return tr.setSelection(_state.TextSelection.create(tr.doc, start));
75
+ });
76
+ api === null || api === void 0 || (_api$quickInsert = api.quickInsert) === null || _api$quickInsert === void 0 || _api$quickInsert.actions.openTypeAhead('blockControl');
77
+ }
78
+ }, /*#__PURE__*/_react.default.createElement(_add.default, {
79
+ label: "add",
80
+ size: "medium"
81
+ }))));
82
+ };
83
+ var TypeAheadControlWithIntl = (0, _reactIntlNext.injectIntl)(TypeAheadControl);
84
+ var toDOM = function toDOM(api, getPos, getIntl) {
85
+ var element = document.createElement('span');
86
+ element.contentEditable = 'false';
87
+ element.setAttribute('style', 'position: relative');
88
+ element.setAttribute('class', 'empty-block-experiment');
89
+ element.setAttribute('data-empty-block-experiment', 'true');
90
+ _reactDom.default.render( /*#__PURE__*/(0, _react.createElement)(_reactIntlNext.RawIntlProvider, {
91
+ value: getIntl()
92
+ }, /*#__PURE__*/(0, _react.createElement)(TypeAheadControlWithIntl, {
93
+ api: api,
94
+ getPos: getPos
95
+ })), element);
96
+
97
+ // // This is a hack to ensure that the cursor in Chrome does not take on the height of the widget button.
98
+ // // Cursor height cannot be controlled via CSS and is handled by the browser.
99
+ // // see Prosemirror forum: https://discuss.prosemirror.net/t/chrome-caret-cursor-larger-than-the-text-with-inlined-items/5946
100
+ var cursorHack = document.createTextNode(_whitespace.ZERO_WIDTH_SPACE);
101
+ element.appendChild(cursorHack);
102
+ return element;
103
+ };
104
+ var createEmptyBlockWidgetDecoration = exports.createEmptyBlockWidgetDecoration = function createEmptyBlockWidgetDecoration(selection, api, getIntl) {
105
+ if (selection instanceof _state.TextSelection && selection.$cursor) {
106
+ var _$cursor$parent, _$cursor$parent2;
107
+ var $cursor = selection.$cursor;
108
+ var depth = $cursor.depth;
109
+ var cursorAtRoot = depth === 1;
110
+ var nodeIsEmpty = ((_$cursor$parent = $cursor.parent) === null || _$cursor$parent === void 0 ? void 0 : _$cursor$parent.nodeSize) === 2;
111
+ var supportedNodeTypes = ['paragraph', 'heading'];
112
+ if (cursorAtRoot && nodeIsEmpty && supportedNodeTypes.includes((_$cursor$parent2 = $cursor.parent) === null || _$cursor$parent2 === void 0 ? void 0 : _$cursor$parent2.type.name)) {
113
+ return _view2.Decoration.widget(selection.$cursor.posAtIndex($cursor.depth - 1), function (_view, getPos) {
114
+ return toDOM(api, getPos, getIntl);
115
+ }, {
116
+ key: 'emptyBlockWidgetDecoration',
117
+ side: -1
118
+ });
119
+ }
120
+ }
121
+ };
@@ -10,6 +10,7 @@ var _react = require("@emotion/react");
10
10
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
11
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
12
12
  var _consts = require("./consts");
13
+ var _globalStyles = require("./empty-block-experiment/global-styles");
13
14
  /**
14
15
  * @jsxRuntime classic
15
16
  * @jsx jsx
@@ -85,7 +86,7 @@ var extendedHoverZoneNested = (0, _react.css)({
85
86
  'hr[data-drag-handler-anchor-name]': {
86
87
  overflow: 'visible'
87
88
  },
88
- //Hide psudeo element at top depth level. Leave for nested depths to prevent mouseover loop.
89
+ //Hide pseudo element at top depth level. Leave for nested depths to prevent mouseover loop.
89
90
  //eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors
90
91
  '[data-blocks-drag-handle-container="true"] + [data-drag-handler-anchor-depth="0"]::after': {
91
92
  display: 'none'
@@ -131,6 +132,8 @@ var getTextNodeStyle = function getTextNodeStyle() {
131
132
  };
132
133
  var GlobalStylesWrapper = exports.GlobalStylesWrapper = function GlobalStylesWrapper() {
133
134
  return (0, _react.jsx)(_react.Global, {
134
- styles: [globalStyles, (0, _experiments.editorExperiment)('nested-dnd', true) ? extendedHoverZoneNested : extendedHoverZone, getTextNodeStyle(), withDeleteLinesStyleFix, withMediaSingleStyleFix]
135
+ styles: [globalStyles, (0, _experiments.editorExperiment)('nested-dnd', true) ? extendedHoverZoneNested : extendedHoverZone, getTextNodeStyle(), withDeleteLinesStyleFix, withMediaSingleStyleFix, (0, _experiments.editorExperiment)('platform_editor_empty_line_prompt', true, {
136
+ exposure: false
137
+ }) ? _globalStyles.emptyBlockExperimentGlobalStyles : undefined]
135
138
  });
136
139
  };
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
2
3
  import { moveNode } from './commands/move-node';
4
+ import { createEmptyBlockExperimentPlugin } from './pm-plugins/empty-block-experiment';
3
5
  import { createPlugin, key } from './pm-plugins/main';
4
6
  import { DragHandleMenu } from './ui/drag-handle-menu';
5
7
  import { GlobalStylesWrapper } from './ui/global-styles';
@@ -14,7 +16,14 @@ export const blockControlsPlugin = ({
14
16
  plugin: ({
15
17
  getIntl
16
18
  }) => createPlugin(api, getIntl)
17
- }];
19
+ }, ...(editorExperiment('platform_editor_empty_line_prompt', true, {
20
+ exposure: true
21
+ }) ? [{
22
+ name: 'emptyBlockExperimentPlugin',
23
+ plugin: ({
24
+ getIntl
25
+ }) => createEmptyBlockExperimentPlugin(api, getIntl)
26
+ }] : [])];
18
27
  },
19
28
  commands: {
20
29
  moveNode: moveNode(api),
@@ -0,0 +1,33 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
4
+ import { createEmptyBlockWidgetDecoration } from '../ui/empty-block-experiment/widget';
5
+ export const emptyBlockExperimentPluginKey = new PluginKey('emptyBlockExperiment');
6
+ const getDecorations = (tr, api, getIntl) => {
7
+ const widget = createEmptyBlockWidgetDecoration(tr.selection, api, getIntl);
8
+ if (widget) {
9
+ return DecorationSet.create(tr.doc, [widget]);
10
+ }
11
+ return DecorationSet.empty;
12
+ };
13
+ export const createEmptyBlockExperimentPlugin = (api, getIntl) => {
14
+ return new SafePlugin({
15
+ key: emptyBlockExperimentPluginKey,
16
+ state: {
17
+ init: (_, _editorState) => ({
18
+ decorations: DecorationSet.empty
19
+ }),
20
+ apply: (tr, _currentState) => {
21
+ return {
22
+ decorations: getDecorations(tr, api, getIntl)
23
+ };
24
+ }
25
+ },
26
+ props: {
27
+ decorations: state => {
28
+ var _emptyBlockExperiment;
29
+ return (_emptyBlockExperiment = emptyBlockExperimentPluginKey.getState(state)) === null || _emptyBlockExperiment === void 0 ? void 0 : _emptyBlockExperiment.decorations;
30
+ }
31
+ }
32
+ });
33
+ };
@@ -0,0 +1,48 @@
1
+ /* eslint-disable @atlaskit/ui-styling-standard/no-exported-styles */
2
+ /* eslint-disable @atlaskit/ui-styling-standard/no-unsafe-values */
3
+ /* eslint-disable @atlaskit/ui-styling-standard/no-nested-selectors */
4
+ /* eslint-disable @atlaskit/ui-styling-standard/no-important-styles */
5
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled
6
+ import { css } from '@emotion/react';
7
+ import { fg } from '@atlaskit/platform-feature-flags';
8
+ const emptyBlockExperimentWidget = '.ProseMirror-widget[data-empty-block-experiment="true"]';
9
+ const quickInsertWidget = '.ProseMirror-widget[data-type-ahead="typeaheadDecoration"]';
10
+ const formattingElement = 'div.fabric-editor-block-mark';
11
+ const elementWithEmptyBlockExperiment = `+ p > ${emptyBlockExperimentWidget}, + h1 > ${emptyBlockExperimentWidget}, + h2 > ${emptyBlockExperimentWidget}, + h3 > ${emptyBlockExperimentWidget}, + h4 > ${emptyBlockExperimentWidget}, + h5 > ${emptyBlockExperimentWidget}, + h6 > ${emptyBlockExperimentWidget}`;
12
+ // Selectors for when contained withing a formatting container mark (eg. indent, centering, right-align)
13
+ const elementWithEmptyBlockExperimentFormatted = `+ ${formattingElement} > p > ${emptyBlockExperimentWidget}, + ${formattingElement} > h1 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h2 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h3 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h4 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h5 > ${emptyBlockExperimentWidget}, + ${formattingElement} > h6 > ${emptyBlockExperimentWidget}`;
14
+ const dragHandleContainer = '.ProseMirror-widget[data-blocks-drag-handle-container="true"]';
15
+ const dragHandleSelector = 'button[data-testid="block-ctrl-drag-handle"]';
16
+
17
+ // Hides the drag handle when the block contains the empty block experiment
18
+ // Override is consistent with how the drag handle is hidden when the block contains a placeholder
19
+ const dragHandleWithInlineNodeStyle = css({
20
+ [`.ProseMirror-widget[data-blocks-drag-handle-container="true"]:has(${elementWithEmptyBlockExperiment}), .ProseMirror-widget[data-blocks-drag-handle-container="true"]:has(${elementWithEmptyBlockExperimentFormatted})`]: {
21
+ display: 'none !important'
22
+ }
23
+ });
24
+
25
+ // Alternate styling for hiding the drag handle when the block contains the empty block experiment
26
+ // Override is consistent with a feature-gated bugfix that hides the drag handle when the block contains a placeholder
27
+ /**
28
+ * Please do not change change transform to display:none, or visibility:hidden
29
+ * Otherwise it might break composition input for Chrome
30
+ * https://product-fabric.atlassian.net/browse/ED-24136
31
+ */
32
+ const dragHandleWithInlineNodeStyleWithChromeFix = css({
33
+ [`${dragHandleContainer}:has(${elementWithEmptyBlockExperiment}) ${dragHandleSelector}, ${dragHandleContainer}:has(${elementWithEmptyBlockExperimentFormatted}) ${dragHandleSelector}`]: {
34
+ transform: 'scale(0)'
35
+ }
36
+ });
37
+ const getDragHandleOverrides = () => {
38
+ return fg('platform_editor_element_controls_chrome_input_fix') ? dragHandleWithInlineNodeStyleWithChromeFix : dragHandleWithInlineNodeStyle;
39
+ };
40
+
41
+ /**
42
+ * Hide the experiment button when it has been activated. (contains quick-insert decoration widget)
43
+ */
44
+ export const emptyBlockExperimentGlobalStyles = css({
45
+ [`${emptyBlockExperimentWidget}:has(+ ${quickInsertWidget}) button`]: {
46
+ transform: 'scale(0)'
47
+ }
48
+ }, getDragHandleOverrides());
@@ -0,0 +1,117 @@
1
+ import React, { createElement } from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { injectIntl, RawIntlProvider } from 'react-intl-next';
4
+ import { ToolTipContent } from '@atlaskit/editor-common/keymaps';
5
+ import { blockControlsMessages as messages } from '@atlaskit/editor-common/messages';
6
+ import { ZERO_WIDTH_SPACE } from '@atlaskit/editor-common/whitespace';
7
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
9
+ import EditorAddIcon from '@atlaskit/icon/glyph/editor/add';
10
+ import { Box, Pressable, xcss } from '@atlaskit/primitives';
11
+ import Tooltip from '@atlaskit/tooltip';
12
+ const wrapperStyles = xcss({
13
+ position: 'absolute',
14
+ top: `calc('50%' - ${"var(--ds-space-150, 12px)"})`,
15
+ left: `calc(${"var(--ds-space-negative-300, -24px)"} + ${"var(--ds-space-negative-100, -8px)"})`
16
+ });
17
+ const buttonStyles = xcss({
18
+ boxSizing: 'border-box',
19
+ display: 'flex',
20
+ flexDirection: 'column',
21
+ justifyContent: 'center',
22
+ alignItems: 'center',
23
+ height: "var(--ds-space-300, 24px)",
24
+ width: "var(--ds-space-300, 24px)",
25
+ border: 'none',
26
+ backgroundColor: 'color.background.neutral',
27
+ borderRadius: '50%',
28
+ color: 'color.text',
29
+ zIndex: 'card',
30
+ outline: 'none',
31
+ ':hover': {
32
+ backgroundColor: 'color.background.neutral.hovered'
33
+ },
34
+ ':active': {
35
+ backgroundColor: 'color.background.neutral.pressed'
36
+ },
37
+ ':focus': {
38
+ outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
39
+ }
40
+ });
41
+ export const TypeAheadControl = ({
42
+ api,
43
+ getPos,
44
+ intl: {
45
+ formatMessage
46
+ }
47
+ }) => {
48
+ return /*#__PURE__*/React.createElement(Box, {
49
+ xcss: [wrapperStyles]
50
+ }, /*#__PURE__*/React.createElement(Tooltip, {
51
+ content: /*#__PURE__*/React.createElement(ToolTipContent, {
52
+ description: formatMessage(messages.insert),
53
+ shortcutOverride: "/"
54
+ })
55
+ }, /*#__PURE__*/React.createElement(Pressable, {
56
+ type: "button",
57
+ "aria-label": formatMessage(messages.insert),
58
+ xcss: [buttonStyles],
59
+ onClick: () => {
60
+ var _api$core, _api$quickInsert;
61
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
62
+ tr
63
+ }) => {
64
+ const start = getPos();
65
+ if (!start) {
66
+ return null;
67
+ }
68
+ return tr.setSelection(TextSelection.create(tr.doc, start));
69
+ });
70
+ api === null || api === void 0 ? void 0 : (_api$quickInsert = api.quickInsert) === null || _api$quickInsert === void 0 ? void 0 : _api$quickInsert.actions.openTypeAhead('blockControl');
71
+ }
72
+ }, /*#__PURE__*/React.createElement(EditorAddIcon, {
73
+ label: "add",
74
+ size: "medium"
75
+ }))));
76
+ };
77
+ const TypeAheadControlWithIntl = injectIntl(TypeAheadControl);
78
+ const toDOM = (api, getPos, getIntl) => {
79
+ const element = document.createElement('span');
80
+ element.contentEditable = 'false';
81
+ element.setAttribute('style', 'position: relative');
82
+ element.setAttribute('class', 'empty-block-experiment');
83
+ element.setAttribute('data-empty-block-experiment', 'true');
84
+ ReactDOM.render( /*#__PURE__*/createElement(RawIntlProvider, {
85
+ value: getIntl()
86
+ }, /*#__PURE__*/createElement(TypeAheadControlWithIntl, {
87
+ api,
88
+ getPos
89
+ })), element);
90
+
91
+ // // This is a hack to ensure that the cursor in Chrome does not take on the height of the widget button.
92
+ // // Cursor height cannot be controlled via CSS and is handled by the browser.
93
+ // // see Prosemirror forum: https://discuss.prosemirror.net/t/chrome-caret-cursor-larger-than-the-text-with-inlined-items/5946
94
+ const cursorHack = document.createTextNode(ZERO_WIDTH_SPACE);
95
+ element.appendChild(cursorHack);
96
+ return element;
97
+ };
98
+ export const createEmptyBlockWidgetDecoration = (selection, api, getIntl) => {
99
+ if (selection instanceof TextSelection && selection.$cursor) {
100
+ var _$cursor$parent, _$cursor$parent2;
101
+ const {
102
+ $cursor
103
+ } = selection;
104
+ const {
105
+ depth
106
+ } = $cursor;
107
+ const cursorAtRoot = depth === 1;
108
+ const nodeIsEmpty = ((_$cursor$parent = $cursor.parent) === null || _$cursor$parent === void 0 ? void 0 : _$cursor$parent.nodeSize) === 2;
109
+ const supportedNodeTypes = ['paragraph', 'heading'];
110
+ if (cursorAtRoot && nodeIsEmpty && supportedNodeTypes.includes((_$cursor$parent2 = $cursor.parent) === null || _$cursor$parent2 === void 0 ? void 0 : _$cursor$parent2.type.name)) {
111
+ return Decoration.widget(selection.$cursor.posAtIndex($cursor.depth - 1), (_view, getPos) => toDOM(api, getPos, getIntl), {
112
+ key: 'emptyBlockWidgetDecoration',
113
+ side: -1
114
+ });
115
+ }
116
+ }
117
+ };
@@ -7,6 +7,7 @@ import { css, Global, jsx } from '@emotion/react';
7
7
  import { fg } from '@atlaskit/platform-feature-flags';
8
8
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
9
9
  import { DRAG_HANDLE_MAX_WIDTH_PLUS_GAP } from './consts';
10
+ import { emptyBlockExperimentGlobalStyles } from './empty-block-experiment/global-styles';
10
11
  const extendedHoverZone = css({
11
12
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors
12
13
  '.block-ctrl-drag-preview [data-drag-handler-anchor-name]::after': {
@@ -76,7 +77,7 @@ const extendedHoverZoneNested = css({
76
77
  'hr[data-drag-handler-anchor-name]': {
77
78
  overflow: 'visible'
78
79
  },
79
- //Hide psudeo element at top depth level. Leave for nested depths to prevent mouseover loop.
80
+ //Hide pseudo element at top depth level. Leave for nested depths to prevent mouseover loop.
80
81
  //eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors
81
82
  '[data-blocks-drag-handle-container="true"] + [data-drag-handler-anchor-depth="0"]::after': {
82
83
  display: 'none'
@@ -135,6 +136,8 @@ const getTextNodeStyle = () => {
135
136
  };
136
137
  export const GlobalStylesWrapper = () => {
137
138
  return jsx(Global, {
138
- styles: [globalStyles, editorExperiment('nested-dnd', true) ? extendedHoverZoneNested : extendedHoverZone, getTextNodeStyle(), withDeleteLinesStyleFix, withMediaSingleStyleFix]
139
+ styles: [globalStyles, editorExperiment('nested-dnd', true) ? extendedHoverZoneNested : extendedHoverZone, getTextNodeStyle(), withDeleteLinesStyleFix, withMediaSingleStyleFix, editorExperiment('platform_editor_empty_line_prompt', true, {
140
+ exposure: false
141
+ }) ? emptyBlockExperimentGlobalStyles : undefined]
139
142
  });
140
143
  };
@@ -1,5 +1,8 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import React from 'react';
3
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
2
4
  import { moveNode } from './commands/move-node';
5
+ import { createEmptyBlockExperimentPlugin } from './pm-plugins/empty-block-experiment';
3
6
  import { createPlugin, key } from './pm-plugins/main';
4
7
  import { DragHandleMenu } from './ui/drag-handle-menu';
5
8
  import { GlobalStylesWrapper } from './ui/global-styles';
@@ -15,13 +18,21 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
15
18
  var getIntl = _ref2.getIntl;
16
19
  return createPlugin(api, getIntl);
17
20
  }
18
- }];
21
+ }].concat(_toConsumableArray(editorExperiment('platform_editor_empty_line_prompt', true, {
22
+ exposure: true
23
+ }) ? [{
24
+ name: 'emptyBlockExperimentPlugin',
25
+ plugin: function plugin(_ref3) {
26
+ var getIntl = _ref3.getIntl;
27
+ return createEmptyBlockExperimentPlugin(api, getIntl);
28
+ }
29
+ }] : []));
19
30
  },
20
31
  commands: {
21
32
  moveNode: moveNode(api),
22
33
  showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions) {
23
- return function (_ref3) {
24
- var tr = _ref3.tr;
34
+ return function (_ref4) {
35
+ var tr = _ref4.tr;
25
36
  tr.setMeta(key, {
26
37
  activeNode: {
27
38
  pos: pos,
@@ -34,8 +45,8 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
34
45
  };
35
46
  },
36
47
  setNodeDragged: function setNodeDragged(pos, anchorName, nodeType) {
37
- return function (_ref4) {
38
- var tr = _ref4.tr;
48
+ return function (_ref5) {
49
+ var tr = _ref5.tr;
39
50
  if (pos === undefined) {
40
51
  return tr;
41
52
  }
@@ -0,0 +1,35 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
4
+ import { createEmptyBlockWidgetDecoration } from '../ui/empty-block-experiment/widget';
5
+ export var emptyBlockExperimentPluginKey = new PluginKey('emptyBlockExperiment');
6
+ var getDecorations = function getDecorations(tr, api, getIntl) {
7
+ var widget = createEmptyBlockWidgetDecoration(tr.selection, api, getIntl);
8
+ if (widget) {
9
+ return DecorationSet.create(tr.doc, [widget]);
10
+ }
11
+ return DecorationSet.empty;
12
+ };
13
+ export var createEmptyBlockExperimentPlugin = function createEmptyBlockExperimentPlugin(api, getIntl) {
14
+ return new SafePlugin({
15
+ key: emptyBlockExperimentPluginKey,
16
+ state: {
17
+ init: function init(_, _editorState) {
18
+ return {
19
+ decorations: DecorationSet.empty
20
+ };
21
+ },
22
+ apply: function apply(tr, _currentState) {
23
+ return {
24
+ decorations: getDecorations(tr, api, getIntl)
25
+ };
26
+ }
27
+ },
28
+ props: {
29
+ decorations: function decorations(state) {
30
+ var _emptyBlockExperiment;
31
+ return (_emptyBlockExperiment = emptyBlockExperimentPluginKey.getState(state)) === null || _emptyBlockExperiment === void 0 ? void 0 : _emptyBlockExperiment.decorations;
32
+ }
33
+ }
34
+ });
35
+ };
@@ -0,0 +1,43 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ /* eslint-disable @atlaskit/ui-styling-standard/no-exported-styles */
3
+ /* eslint-disable @atlaskit/ui-styling-standard/no-unsafe-values */
4
+ /* eslint-disable @atlaskit/ui-styling-standard/no-nested-selectors */
5
+ /* eslint-disable @atlaskit/ui-styling-standard/no-important-styles */
6
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled
7
+ import { css } from '@emotion/react';
8
+ import { fg } from '@atlaskit/platform-feature-flags';
9
+ var emptyBlockExperimentWidget = '.ProseMirror-widget[data-empty-block-experiment="true"]';
10
+ var quickInsertWidget = '.ProseMirror-widget[data-type-ahead="typeaheadDecoration"]';
11
+ var formattingElement = 'div.fabric-editor-block-mark';
12
+ var elementWithEmptyBlockExperiment = "+ p > ".concat(emptyBlockExperimentWidget, ", + h1 > ").concat(emptyBlockExperimentWidget, ", + h2 > ").concat(emptyBlockExperimentWidget, ", + h3 > ").concat(emptyBlockExperimentWidget, ", + h4 > ").concat(emptyBlockExperimentWidget, ", + h5 > ").concat(emptyBlockExperimentWidget, ", + h6 > ").concat(emptyBlockExperimentWidget);
13
+ // Selectors for when contained withing a formatting container mark (eg. indent, centering, right-align)
14
+ var elementWithEmptyBlockExperimentFormatted = "+ ".concat(formattingElement, " > p > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h1 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h2 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h3 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h4 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h5 > ").concat(emptyBlockExperimentWidget, ", + ").concat(formattingElement, " > h6 > ").concat(emptyBlockExperimentWidget);
15
+ var dragHandleContainer = '.ProseMirror-widget[data-blocks-drag-handle-container="true"]';
16
+ var dragHandleSelector = 'button[data-testid="block-ctrl-drag-handle"]';
17
+
18
+ // Hides the drag handle when the block contains the empty block experiment
19
+ // Override is consistent with how the drag handle is hidden when the block contains a placeholder
20
+ var dragHandleWithInlineNodeStyle = css(_defineProperty({}, ".ProseMirror-widget[data-blocks-drag-handle-container=\"true\"]:has(".concat(elementWithEmptyBlockExperiment, "), .ProseMirror-widget[data-blocks-drag-handle-container=\"true\"]:has(").concat(elementWithEmptyBlockExperimentFormatted, ")"), {
21
+ display: 'none !important'
22
+ }));
23
+
24
+ // Alternate styling for hiding the drag handle when the block contains the empty block experiment
25
+ // Override is consistent with a feature-gated bugfix that hides the drag handle when the block contains a placeholder
26
+ /**
27
+ * Please do not change change transform to display:none, or visibility:hidden
28
+ * Otherwise it might break composition input for Chrome
29
+ * https://product-fabric.atlassian.net/browse/ED-24136
30
+ */
31
+ var dragHandleWithInlineNodeStyleWithChromeFix = css(_defineProperty({}, "".concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperiment, ") ").concat(dragHandleSelector, ", ").concat(dragHandleContainer, ":has(").concat(elementWithEmptyBlockExperimentFormatted, ") ").concat(dragHandleSelector), {
32
+ transform: 'scale(0)'
33
+ }));
34
+ var getDragHandleOverrides = function getDragHandleOverrides() {
35
+ return fg('platform_editor_element_controls_chrome_input_fix') ? dragHandleWithInlineNodeStyleWithChromeFix : dragHandleWithInlineNodeStyle;
36
+ };
37
+
38
+ /**
39
+ * Hide the experiment button when it has been activated. (contains quick-insert decoration widget)
40
+ */
41
+ export var emptyBlockExperimentGlobalStyles = css(_defineProperty({}, "".concat(emptyBlockExperimentWidget, ":has(+ ").concat(quickInsertWidget, ") button"), {
42
+ transform: 'scale(0)'
43
+ }), getDragHandleOverrides());
@@ -0,0 +1,111 @@
1
+ import React, { createElement } from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { injectIntl, RawIntlProvider } from 'react-intl-next';
4
+ import { ToolTipContent } from '@atlaskit/editor-common/keymaps';
5
+ import { blockControlsMessages as messages } from '@atlaskit/editor-common/messages';
6
+ import { ZERO_WIDTH_SPACE } from '@atlaskit/editor-common/whitespace';
7
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
9
+ import EditorAddIcon from '@atlaskit/icon/glyph/editor/add';
10
+ import { Box, Pressable, xcss } from '@atlaskit/primitives';
11
+ import Tooltip from '@atlaskit/tooltip';
12
+ var wrapperStyles = xcss({
13
+ position: 'absolute',
14
+ top: "calc('50%' - ".concat("var(--ds-space-150, 12px)", ")"),
15
+ left: "calc(".concat("var(--ds-space-negative-300, -24px)", " + ", "var(--ds-space-negative-100, -8px)", ")")
16
+ });
17
+ var buttonStyles = xcss({
18
+ boxSizing: 'border-box',
19
+ display: 'flex',
20
+ flexDirection: 'column',
21
+ justifyContent: 'center',
22
+ alignItems: 'center',
23
+ height: "var(--ds-space-300, 24px)",
24
+ width: "var(--ds-space-300, 24px)",
25
+ border: 'none',
26
+ backgroundColor: 'color.background.neutral',
27
+ borderRadius: '50%',
28
+ color: 'color.text',
29
+ zIndex: 'card',
30
+ outline: 'none',
31
+ ':hover': {
32
+ backgroundColor: 'color.background.neutral.hovered'
33
+ },
34
+ ':active': {
35
+ backgroundColor: 'color.background.neutral.pressed'
36
+ },
37
+ ':focus': {
38
+ outline: "2px solid ".concat("var(--ds-border-focused, #388BFF)")
39
+ }
40
+ });
41
+ export var TypeAheadControl = function TypeAheadControl(_ref) {
42
+ var api = _ref.api,
43
+ getPos = _ref.getPos,
44
+ formatMessage = _ref.intl.formatMessage;
45
+ return /*#__PURE__*/React.createElement(Box, {
46
+ xcss: [wrapperStyles]
47
+ }, /*#__PURE__*/React.createElement(Tooltip, {
48
+ content: /*#__PURE__*/React.createElement(ToolTipContent, {
49
+ description: formatMessage(messages.insert),
50
+ shortcutOverride: "/"
51
+ })
52
+ }, /*#__PURE__*/React.createElement(Pressable, {
53
+ type: "button",
54
+ "aria-label": formatMessage(messages.insert),
55
+ xcss: [buttonStyles],
56
+ onClick: function onClick() {
57
+ var _api$core, _api$quickInsert;
58
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
59
+ var tr = _ref2.tr;
60
+ var start = getPos();
61
+ if (!start) {
62
+ return null;
63
+ }
64
+ return tr.setSelection(TextSelection.create(tr.doc, start));
65
+ });
66
+ api === null || api === void 0 || (_api$quickInsert = api.quickInsert) === null || _api$quickInsert === void 0 || _api$quickInsert.actions.openTypeAhead('blockControl');
67
+ }
68
+ }, /*#__PURE__*/React.createElement(EditorAddIcon, {
69
+ label: "add",
70
+ size: "medium"
71
+ }))));
72
+ };
73
+ var TypeAheadControlWithIntl = injectIntl(TypeAheadControl);
74
+ var toDOM = function toDOM(api, getPos, getIntl) {
75
+ var element = document.createElement('span');
76
+ element.contentEditable = 'false';
77
+ element.setAttribute('style', 'position: relative');
78
+ element.setAttribute('class', 'empty-block-experiment');
79
+ element.setAttribute('data-empty-block-experiment', 'true');
80
+ ReactDOM.render( /*#__PURE__*/createElement(RawIntlProvider, {
81
+ value: getIntl()
82
+ }, /*#__PURE__*/createElement(TypeAheadControlWithIntl, {
83
+ api: api,
84
+ getPos: getPos
85
+ })), element);
86
+
87
+ // // This is a hack to ensure that the cursor in Chrome does not take on the height of the widget button.
88
+ // // Cursor height cannot be controlled via CSS and is handled by the browser.
89
+ // // see Prosemirror forum: https://discuss.prosemirror.net/t/chrome-caret-cursor-larger-than-the-text-with-inlined-items/5946
90
+ var cursorHack = document.createTextNode(ZERO_WIDTH_SPACE);
91
+ element.appendChild(cursorHack);
92
+ return element;
93
+ };
94
+ export var createEmptyBlockWidgetDecoration = function createEmptyBlockWidgetDecoration(selection, api, getIntl) {
95
+ if (selection instanceof TextSelection && selection.$cursor) {
96
+ var _$cursor$parent, _$cursor$parent2;
97
+ var $cursor = selection.$cursor;
98
+ var depth = $cursor.depth;
99
+ var cursorAtRoot = depth === 1;
100
+ var nodeIsEmpty = ((_$cursor$parent = $cursor.parent) === null || _$cursor$parent === void 0 ? void 0 : _$cursor$parent.nodeSize) === 2;
101
+ var supportedNodeTypes = ['paragraph', 'heading'];
102
+ if (cursorAtRoot && nodeIsEmpty && supportedNodeTypes.includes((_$cursor$parent2 = $cursor.parent) === null || _$cursor$parent2 === void 0 ? void 0 : _$cursor$parent2.type.name)) {
103
+ return Decoration.widget(selection.$cursor.posAtIndex($cursor.depth - 1), function (_view, getPos) {
104
+ return toDOM(api, getPos, getIntl);
105
+ }, {
106
+ key: 'emptyBlockWidgetDecoration',
107
+ side: -1
108
+ });
109
+ }
110
+ }
111
+ };
@@ -8,6 +8,7 @@ import { css, Global, jsx } from '@emotion/react';
8
8
  import { fg } from '@atlaskit/platform-feature-flags';
9
9
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
10
10
  import { DRAG_HANDLE_MAX_WIDTH_PLUS_GAP } from './consts';
11
+ import { emptyBlockExperimentGlobalStyles } from './empty-block-experiment/global-styles';
11
12
  var extendedHoverZone = css({
12
13
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors
13
14
  '.block-ctrl-drag-preview [data-drag-handler-anchor-name]::after': {
@@ -77,7 +78,7 @@ var extendedHoverZoneNested = css({
77
78
  'hr[data-drag-handler-anchor-name]': {
78
79
  overflow: 'visible'
79
80
  },
80
- //Hide psudeo element at top depth level. Leave for nested depths to prevent mouseover loop.
81
+ //Hide pseudo element at top depth level. Leave for nested depths to prevent mouseover loop.
81
82
  //eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors
82
83
  '[data-blocks-drag-handle-container="true"] + [data-drag-handler-anchor-depth="0"]::after': {
83
84
  display: 'none'
@@ -123,6 +124,8 @@ var getTextNodeStyle = function getTextNodeStyle() {
123
124
  };
124
125
  export var GlobalStylesWrapper = function GlobalStylesWrapper() {
125
126
  return jsx(Global, {
126
- styles: [globalStyles, editorExperiment('nested-dnd', true) ? extendedHoverZoneNested : extendedHoverZone, getTextNodeStyle(), withDeleteLinesStyleFix, withMediaSingleStyleFix]
127
+ styles: [globalStyles, editorExperiment('nested-dnd', true) ? extendedHoverZoneNested : extendedHoverZone, getTextNodeStyle(), withDeleteLinesStyleFix, withMediaSingleStyleFix, editorExperiment('platform_editor_empty_line_prompt', true, {
128
+ exposure: false
129
+ }) ? emptyBlockExperimentGlobalStyles : undefined]
127
130
  });
128
131
  };
@@ -0,0 +1,13 @@
1
+ import { type IntlShape } from 'react-intl-next';
2
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import { type ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
6
+ import { type BlockControlsPlugin } from '../types';
7
+ export declare const emptyBlockExperimentPluginKey: PluginKey<EmptyBlockExperimentState>;
8
+ export type EmptyBlockExperimentState = {
9
+ decorations: DecorationSet;
10
+ };
11
+ export declare const createEmptyBlockExperimentPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, getIntl: () => IntlShape) => SafePlugin<{
12
+ decorations: DecorationSet;
13
+ }>;
@@ -5,6 +5,7 @@ import type { AccessibilityUtilsPlugin } from '@atlaskit/editor-plugin-accessibi
5
5
  import { type AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
6
6
  import type { EditorDisabledPlugin } from '@atlaskit/editor-plugin-editor-disabled';
7
7
  import type { FeatureFlagsPlugin } from '@atlaskit/editor-plugin-feature-flags';
8
+ import type { QuickInsertPlugin } from '@atlaskit/editor-plugin-quick-insert';
8
9
  import type { WidthPlugin } from '@atlaskit/editor-plugin-width';
9
10
  import { type DecorationSet } from '@atlaskit/editor-prosemirror/view';
10
11
  export type ActiveNode = {
@@ -51,7 +52,12 @@ export type BlockControlsPlugin = NextEditorPlugin<'blockControls', {
51
52
  OptionalPlugin<WidthPlugin>,
52
53
  OptionalPlugin<FeatureFlagsPlugin>,
53
54
  OptionalPlugin<AnalyticsPlugin>,
54
- OptionalPlugin<AccessibilityUtilsPlugin>
55
+ OptionalPlugin<AccessibilityUtilsPlugin>,
56
+ /**
57
+ * For Typeahead - Empty line prompt experiment
58
+ * Clean up ticket ED-24824
59
+ */
60
+ OptionalPlugin<QuickInsertPlugin>
55
61
  ];
56
62
  sharedState: BlockControlsSharedState;
57
63
  commands: {
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Hide the experiment button when it has been activated. (contains quick-insert decoration widget)
3
+ */
4
+ export declare const emptyBlockExperimentGlobalStyles: import("@emotion/react").SerializedStyles;
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import { type IntlShape, type WrappedComponentProps } from 'react-intl-next';
3
+ import { type ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import { type Selection } from '@atlaskit/editor-prosemirror/state';
5
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
6
+ import { type BlockControlsPlugin } from '../../types';
7
+ type Props = {
8
+ api: ExtractInjectionAPI<BlockControlsPlugin> | undefined;
9
+ getPos: () => number | undefined;
10
+ };
11
+ export declare const TypeAheadControl: ({ api, getPos, intl: { formatMessage }, }: Props & WrappedComponentProps) => JSX.Element;
12
+ export declare const createEmptyBlockWidgetDecoration: (selection: Selection, api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, getIntl: () => IntlShape) => Decoration | undefined;
13
+ export {};
@@ -0,0 +1,13 @@
1
+ import { type IntlShape } from 'react-intl-next';
2
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import { type ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
6
+ import { type BlockControlsPlugin } from '../types';
7
+ export declare const emptyBlockExperimentPluginKey: PluginKey<EmptyBlockExperimentState>;
8
+ export type EmptyBlockExperimentState = {
9
+ decorations: DecorationSet;
10
+ };
11
+ export declare const createEmptyBlockExperimentPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, getIntl: () => IntlShape) => SafePlugin<{
12
+ decorations: DecorationSet;
13
+ }>;
@@ -5,6 +5,7 @@ import type { AccessibilityUtilsPlugin } from '@atlaskit/editor-plugin-accessibi
5
5
  import { type AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
6
6
  import type { EditorDisabledPlugin } from '@atlaskit/editor-plugin-editor-disabled';
7
7
  import type { FeatureFlagsPlugin } from '@atlaskit/editor-plugin-feature-flags';
8
+ import type { QuickInsertPlugin } from '@atlaskit/editor-plugin-quick-insert';
8
9
  import type { WidthPlugin } from '@atlaskit/editor-plugin-width';
9
10
  import { type DecorationSet } from '@atlaskit/editor-prosemirror/view';
10
11
  export type ActiveNode = {
@@ -51,7 +52,12 @@ export type BlockControlsPlugin = NextEditorPlugin<'blockControls', {
51
52
  OptionalPlugin<WidthPlugin>,
52
53
  OptionalPlugin<FeatureFlagsPlugin>,
53
54
  OptionalPlugin<AnalyticsPlugin>,
54
- OptionalPlugin<AccessibilityUtilsPlugin>
55
+ OptionalPlugin<AccessibilityUtilsPlugin>,
56
+ /**
57
+ * For Typeahead - Empty line prompt experiment
58
+ * Clean up ticket ED-24824
59
+ */
60
+ OptionalPlugin<QuickInsertPlugin>
55
61
  ];
56
62
  sharedState: BlockControlsSharedState;
57
63
  commands: {
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Hide the experiment button when it has been activated. (contains quick-insert decoration widget)
3
+ */
4
+ export declare const emptyBlockExperimentGlobalStyles: import("@emotion/react").SerializedStyles;
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import { type IntlShape, type WrappedComponentProps } from 'react-intl-next';
3
+ import { type ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import { type Selection } from '@atlaskit/editor-prosemirror/state';
5
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
6
+ import { type BlockControlsPlugin } from '../../types';
7
+ type Props = {
8
+ api: ExtractInjectionAPI<BlockControlsPlugin> | undefined;
9
+ getPos: () => number | undefined;
10
+ };
11
+ export declare const TypeAheadControl: ({ api, getPos, intl: { formatMessage }, }: Props & WrappedComponentProps) => JSX.Element;
12
+ export declare const createEmptyBlockWidgetDecoration: (selection: Selection, api: ExtractInjectionAPI<BlockControlsPlugin> | undefined, getIntl: () => IntlShape) => Decoration | undefined;
13
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "1.12.10",
3
+ "version": "1.13.0",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -29,11 +29,12 @@
29
29
  ".": "./src/index.ts"
30
30
  },
31
31
  "dependencies": {
32
- "@atlaskit/editor-common": "^88.8.0",
32
+ "@atlaskit/editor-common": "^88.9.0",
33
33
  "@atlaskit/editor-plugin-accessibility-utils": "^1.2.0",
34
34
  "@atlaskit/editor-plugin-analytics": "^1.8.0",
35
35
  "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",
36
36
  "@atlaskit/editor-plugin-feature-flags": "^1.2.0",
37
+ "@atlaskit/editor-plugin-quick-insert": "^1.3.0",
37
38
  "@atlaskit/editor-plugin-width": "^1.3.0",
38
39
  "@atlaskit/editor-prosemirror": "5.0.1",
39
40
  "@atlaskit/editor-shared-styles": "^2.13.0",
@@ -43,6 +44,7 @@
43
44
  "@atlaskit/pragmatic-drag-and-drop": "^1.3.0",
44
45
  "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^1.4.0",
45
46
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.0",
47
+ "@atlaskit/primitives": "^12.1.0",
46
48
  "@atlaskit/theme": "^13.0.0",
47
49
  "@atlaskit/tmp-editor-statsig": "^2.1.0",
48
50
  "@atlaskit/tokens": "^1.59.0",