@atlaskit/editor-plugin-block-controls 17.0.1 → 17.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/blockControlsPlugin.js +23 -4
  3. package/dist/cjs/pm-plugins/decorations-drag-handle.js +5 -22
  4. package/dist/cjs/pm-plugins/decorations-quick-insert-button.js +2 -6
  5. package/dist/cjs/ui/block-controls-surface-context.js +60 -0
  6. package/dist/cjs/ui/block-controls-surface.compiled.css +3 -0
  7. package/dist/cjs/ui/block-controls-surface.js +160 -0
  8. package/dist/cjs/ui/quick-insert-button.js +9 -0
  9. package/dist/cjs/ui/utils/get-node-content-element.js +24 -0
  10. package/dist/cjs/ui/utils/get-surface-placement.js +39 -0
  11. package/dist/es2019/blockControlsPlugin.js +28 -4
  12. package/dist/es2019/pm-plugins/decorations-drag-handle.js +5 -22
  13. package/dist/es2019/pm-plugins/decorations-quick-insert-button.js +2 -6
  14. package/dist/es2019/ui/block-controls-surface-context.js +51 -0
  15. package/dist/es2019/ui/block-controls-surface.compiled.css +3 -0
  16. package/dist/es2019/ui/block-controls-surface.js +144 -0
  17. package/dist/es2019/ui/quick-insert-button.js +9 -0
  18. package/dist/es2019/ui/utils/get-node-content-element.js +18 -0
  19. package/dist/es2019/ui/utils/get-surface-placement.js +30 -0
  20. package/dist/esm/blockControlsPlugin.js +23 -4
  21. package/dist/esm/pm-plugins/decorations-drag-handle.js +5 -22
  22. package/dist/esm/pm-plugins/decorations-quick-insert-button.js +2 -6
  23. package/dist/esm/ui/block-controls-surface-context.js +53 -0
  24. package/dist/esm/ui/block-controls-surface.compiled.css +3 -0
  25. package/dist/esm/ui/block-controls-surface.js +151 -0
  26. package/dist/esm/ui/quick-insert-button.js +9 -0
  27. package/dist/esm/ui/utils/get-node-content-element.js +18 -0
  28. package/dist/esm/ui/utils/get-surface-placement.js +32 -0
  29. package/dist/types/blockControlsPluginType.d.ts +3 -1
  30. package/dist/types/ui/block-controls-surface-context.d.ts +4 -0
  31. package/dist/types/ui/block-controls-surface.d.ts +14 -0
  32. package/dist/types/ui/quick-insert-button.d.ts +8 -0
  33. package/dist/types/ui/utils/get-node-content-element.d.ts +1 -0
  34. package/dist/types/ui/utils/get-surface-placement.d.ts +23 -0
  35. package/package.json +7 -7
@@ -0,0 +1,51 @@
1
+ const getNodeContext = (view, pos) => {
2
+ const node = view.state.doc.nodeAt(pos);
3
+ if (!node) {
4
+ return undefined;
5
+ }
6
+ const $pos = view.state.doc.resolve(pos);
7
+ const ancestors = [];
8
+ for (let depth = 0; depth <= $pos.depth; depth++) {
9
+ const ancestor = $pos.node(depth);
10
+ ancestors.push({
11
+ depth,
12
+ pos: depth === 0 ? 0 : $pos.before(depth),
13
+ type: {
14
+ name: ancestor.type.name
15
+ }
16
+ });
17
+ }
18
+ return {
19
+ ancestors,
20
+ depth: $pos.depth + 1,
21
+ node,
22
+ parentType: $pos.parent.type.name,
23
+ pos,
24
+ type: {
25
+ name: node.type.name
26
+ }
27
+ };
28
+ };
29
+ export const createBlockControlsSurfaceContext = (view, activeNode) => {
30
+ var _activeNode$rootPos, _activeNode$rootNodeT;
31
+ if (!activeNode) {
32
+ return undefined;
33
+ }
34
+ const rootPos = (_activeNode$rootPos = activeNode.rootPos) !== null && _activeNode$rootPos !== void 0 ? _activeNode$rootPos : activeNode.pos;
35
+ const activeNodeContext = getNodeContext(view, activeNode.pos);
36
+ const rootNodeContext = getNodeContext(view, rootPos);
37
+ if (!activeNodeContext || !rootNodeContext) {
38
+ return undefined;
39
+ }
40
+ return {
41
+ activeNode: {
42
+ ...activeNodeContext,
43
+ rootPos,
44
+ rootType: {
45
+ name: (_activeNode$rootNodeT = activeNode.rootNodeType) !== null && _activeNode$rootNodeT !== void 0 ? _activeNode$rootNodeT : rootNodeContext.type.name
46
+ }
47
+ },
48
+ rootNode: rootNodeContext,
49
+ targetNode: rootNodeContext
50
+ };
51
+ };
@@ -0,0 +1,3 @@
1
+ ._1e0c1txw{display:flex}
2
+ ._1pbyb4wl{z-index:100}
3
+ ._kqswstnw{position:absolute}
@@ -0,0 +1,144 @@
1
+ /* block-controls-surface.tsx generated by @compiled/babel-plugin v2.0.0 */
2
+ import "./block-controls-surface.compiled.css";
3
+ import { ax, ix } from "@compiled/react/runtime";
4
+ import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
5
+ import { bind } from 'bind-event-listener';
6
+ import { getDocument } from '@atlaskit/browser-apis';
7
+ import { BLOCK_CONTROL_UI_CONTEXT } from '@atlaskit/editor-common/block-controls/block-control-ui-context';
8
+ import { BLOCK_CONTROLS_LEFT_SURFACE } from '@atlaskit/editor-common/block-controls/surface-keys';
9
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
10
+ import { SurfaceRenderer, willSurfaceRender } from '@atlaskit/editor-ui-control-model/surface-renderer';
11
+ import { createSurfaceContext } from '@atlaskit/editor-ui-control-model/types';
12
+ import { getNodeTypeWithLevel } from '../pm-plugins/decorations-common';
13
+ import { createBlockControlsSurfaceContext } from './block-controls-surface-context';
14
+ import { getNodeContentElement } from './utils/get-node-content-element';
15
+ import { getAbsoluteSurfacePlacement, getSurfacePlacement } from './utils/get-surface-placement';
16
+ import { VisibilityContainer } from './visibility-container';
17
+ const BLOCK_CONTROLS_SURFACE_Z_INDEX = 100;
18
+ const surfaceStyles = null;
19
+ export const BlockControlsSurface = ({
20
+ api,
21
+ editorView
22
+ }) => {
23
+ var _api$uiControlRegistr, _api$uiControlRegistr2;
24
+ const activeNode = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
25
+ var _states$blockControls;
26
+ return {
27
+ activeNode: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.activeNode
28
+ };
29
+ }).activeNode;
30
+ const [position, setPosition] = useState();
31
+ const animationFrameRef = useRef(undefined);
32
+ const components = (_api$uiControlRegistr = (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(BLOCK_CONTROLS_LEFT_SURFACE)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
33
+ const blockControlsContext = useMemo(() => createBlockControlsSurfaceContext(editorView, activeNode), [activeNode, editorView]);
34
+ const surfaceContext = useMemo(() => blockControlsContext ? createSurfaceContext(BLOCK_CONTROL_UI_CONTEXT, blockControlsContext) : undefined, [blockControlsContext]);
35
+ useLayoutEffect(() => {
36
+ var _getDocument;
37
+ if (!blockControlsContext) {
38
+ setPosition(undefined);
39
+ return;
40
+ }
41
+ const rootNodeElement = editorView.nodeDOM(blockControlsContext.rootNode.pos);
42
+ const rootElement = rootNodeElement instanceof HTMLElement ? rootNodeElement : rootNodeElement === null || rootNodeElement === void 0 ? void 0 : rootNodeElement.parentElement;
43
+ if (!rootElement) {
44
+ setPosition(undefined);
45
+ return;
46
+ }
47
+ const targetElement = getNodeContentElement(rootElement, blockControlsContext.rootNode.type.name);
48
+ const offsetParent = editorView.dom.offsetParent;
49
+ const isDocumentOffsetParent = !offsetParent || offsetParent === ((_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.body);
50
+ const scrollingOffsetParent = offsetParent instanceof HTMLElement && !isDocumentOffsetParent ? offsetParent : undefined;
51
+ const updatePosition = () => {
52
+ var _rootElement$getAttri, _scrollingOffsetParen, _scrollingOffsetParen2;
53
+ animationFrameRef.current = undefined;
54
+ if (!rootElement.isConnected || !targetElement.isConnected) {
55
+ setPosition(undefined);
56
+ return;
57
+ }
58
+ const placement = getSurfacePlacement({
59
+ layout: (_rootElement$getAttri = rootElement.getAttribute('layout')) !== null && _rootElement$getAttri !== void 0 ? _rootElement$getAttri : '',
60
+ nodeRect: targetElement.getBoundingClientRect(),
61
+ nodeType: blockControlsContext.rootNode.type.name,
62
+ nodeTypeWithLevel: getNodeTypeWithLevel(blockControlsContext.rootNode.node),
63
+ parentNodeType: blockControlsContext.rootNode.parentType === 'doc' ? undefined : blockControlsContext.rootNode.parentType
64
+ });
65
+ const offsetParentRect = offsetParent === null || offsetParent === void 0 ? void 0 : offsetParent.getBoundingClientRect();
66
+ const offsetParentScrollTop = (_scrollingOffsetParen = scrollingOffsetParent === null || scrollingOffsetParent === void 0 ? void 0 : scrollingOffsetParent.scrollTop) !== null && _scrollingOffsetParen !== void 0 ? _scrollingOffsetParen : window.scrollY;
67
+ const offsetParentScrollLeft = (_scrollingOffsetParen2 = scrollingOffsetParent === null || scrollingOffsetParent === void 0 ? void 0 : scrollingOffsetParent.scrollLeft) !== null && _scrollingOffsetParen2 !== void 0 ? _scrollingOffsetParen2 : window.scrollX;
68
+ setPosition(getAbsoluteSurfacePlacement({
69
+ offsetParentRect,
70
+ offsetParentScrollLeft,
71
+ offsetParentScrollTop,
72
+ placement
73
+ }));
74
+ };
75
+ const schedulePositionUpdate = () => {
76
+ if (animationFrameRef.current === undefined) {
77
+ animationFrameRef.current = requestAnimationFrame(updatePosition);
78
+ }
79
+ };
80
+ updatePosition();
81
+ const resizeObserver = new ResizeObserver(schedulePositionUpdate);
82
+ resizeObserver.observe(editorView.dom);
83
+ if (targetElement && targetElement !== editorView.dom) {
84
+ resizeObserver.observe(targetElement);
85
+ }
86
+ if (offsetParent instanceof HTMLElement && offsetParent !== editorView.dom) {
87
+ resizeObserver.observe(offsetParent);
88
+ }
89
+ const unbindWindowResize = bind(window, {
90
+ type: 'resize',
91
+ listener: schedulePositionUpdate
92
+ });
93
+ const unbindWindowScroll = bind(window, {
94
+ type: 'scroll',
95
+ listener: schedulePositionUpdate,
96
+ options: {
97
+ capture: true,
98
+ passive: true
99
+ }
100
+ });
101
+ const visualViewport = window.visualViewport;
102
+ const unbindVisualViewportResize = visualViewport ? bind(visualViewport, {
103
+ type: 'resize',
104
+ listener: schedulePositionUpdate
105
+ }) : undefined;
106
+ const unbindVisualViewportScroll = visualViewport ? bind(visualViewport, {
107
+ type: 'scroll',
108
+ listener: schedulePositionUpdate
109
+ }) : undefined;
110
+ const unbindTransitionEnd = bind(targetElement, {
111
+ type: 'transitionend',
112
+ listener: schedulePositionUpdate
113
+ });
114
+ return () => {
115
+ if (animationFrameRef.current !== undefined) {
116
+ cancelAnimationFrame(animationFrameRef.current);
117
+ animationFrameRef.current = undefined;
118
+ }
119
+ resizeObserver.disconnect();
120
+ unbindWindowResize();
121
+ unbindWindowScroll();
122
+ unbindVisualViewportResize === null || unbindVisualViewportResize === void 0 ? void 0 : unbindVisualViewportResize();
123
+ unbindVisualViewportScroll === null || unbindVisualViewportScroll === void 0 ? void 0 : unbindVisualViewportScroll();
124
+ unbindTransitionEnd();
125
+ };
126
+ }, [blockControlsContext, editorView]);
127
+ if (components.length === 0 || !blockControlsContext || !surfaceContext || !position || !willSurfaceRender(components, BLOCK_CONTROLS_LEFT_SURFACE, surfaceContext)) {
128
+ return null;
129
+ }
130
+ return /*#__PURE__*/React.createElement("div", {
131
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Placement is resolved from the active node's runtime DOM geometry.
132
+ style: position,
133
+ "data-testid": "block-controls-left-surface",
134
+ className: ax(["_1e0c1txw _kqswstnw _1pbyb4wl"])
135
+ }, /*#__PURE__*/React.createElement(VisibilityContainer, {
136
+ api: api,
137
+ controlSide: "left",
138
+ shouldUseDisplayContents: true
139
+ }, /*#__PURE__*/React.createElement(SurfaceRenderer, {
140
+ components: components,
141
+ surface: BLOCK_CONTROLS_LEFT_SURFACE,
142
+ surfaceContext: surfaceContext
143
+ })));
144
+ };
@@ -150,6 +150,15 @@ const getQuickInsertAnchorReference = ({
150
150
  }
151
151
  return `anchor(${safeAnchorName} ${edge})`;
152
152
  };
153
+
154
+ /**
155
+ * Legacy widget-decoration Quick Insert implementation.
156
+ *
157
+ * Its behavior is intentionally duplicated by the registry-backed control in
158
+ * `editor-plugin-quick-insert`. Remove this implementation when
159
+ * `platform_editor_block_control_migration` is cleaned up; until then this path remains unchanged
160
+ * for users outside the experiment.
161
+ */
153
162
  export const TypeAheadControl = ({
154
163
  view,
155
164
  api,
@@ -0,0 +1,18 @@
1
+ import { resizerItemClassName } from '@atlaskit/editor-common/styles';
2
+ const INNER_CONTAINER_SELECTORS = {
3
+ blockCard: '.datasourceView-content-inner-wrap',
4
+ bodiedExtension: '.extension-container[data-layout]',
5
+ embedCard: '.rich-media-item',
6
+ extension: '.extension-container[data-layout]',
7
+ mediaSingle: `.${resizerItemClassName}`,
8
+ multiBodiedExtension: '.extension-container[data-layout]',
9
+ table: `.${resizerItemClassName}`
10
+ };
11
+ export const getNodeContentElement = (nodeElement, nodeType) => {
12
+ var _nodeElement$querySel;
13
+ const selector = INNER_CONTAINER_SELECTORS[nodeType];
14
+ if (!selector) {
15
+ return nodeElement;
16
+ }
17
+ return (_nodeElement$querySel = nodeElement.querySelector(selector)) !== null && _nodeElement$querySel !== void 0 ? _nodeElement$querySel : nodeElement;
18
+ };
@@ -0,0 +1,30 @@
1
+ import { QUICK_INSERT_LEFT_OFFSET, dragHandleGap, topPositionAdjustment } from '../consts';
2
+ export const getAbsoluteSurfacePlacement = ({
3
+ offsetParentRect,
4
+ offsetParentScrollLeft,
5
+ offsetParentScrollTop,
6
+ placement
7
+ }) => {
8
+ var _offsetParentRect$lef, _offsetParentRect$top;
9
+ return {
10
+ ...placement,
11
+ left: placement.left - ((_offsetParentRect$lef = offsetParentRect === null || offsetParentRect === void 0 ? void 0 : offsetParentRect.left) !== null && _offsetParentRect$lef !== void 0 ? _offsetParentRect$lef : 0) + offsetParentScrollLeft,
12
+ top: placement.top - ((_offsetParentRect$top = offsetParentRect === null || offsetParentRect === void 0 ? void 0 : offsetParentRect.top) !== null && _offsetParentRect$top !== void 0 ? _offsetParentRect$top : 0) + offsetParentScrollTop
13
+ };
14
+ };
15
+
16
+ /**
17
+ * Positions the Task 1 left surface beside the legacy drag-handle slot.
18
+ * The surface's own width is handled by the transform, so later controls do not require measuring it.
19
+ */
20
+ export const getSurfacePlacement = ({
21
+ layout,
22
+ nodeRect,
23
+ nodeType,
24
+ nodeTypeWithLevel,
25
+ parentNodeType
26
+ }) => ({
27
+ left: nodeRect.left,
28
+ top: nodeRect.top + topPositionAdjustment(nodeTypeWithLevel, layout),
29
+ transform: `translateX(calc(-100% - ${dragHandleGap(nodeType, parentNodeType) + QUICK_INSERT_LEFT_OFFSET}px))`
30
+ });
@@ -2,6 +2,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  import React from 'react';
5
+ import { BLOCK_CONTROLS_LEFT_GROUP, BLOCK_CONTROLS_LEFT_SECTION, BLOCK_CONTROLS_LEFT_SURFACE } from '@atlaskit/editor-common/block-controls/surface-keys';
5
6
  import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
6
7
  import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check';
7
8
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
@@ -24,6 +25,7 @@ import { selectionPreservationPluginKey } from './pm-plugins/selection-preservat
24
25
  import { createSelectionPreservationPlugin } from './pm-plugins/selection-preservation/pm-plugin';
25
26
  import { expandAndUpdateSelection as _expandAndUpdateSelection } from './pm-plugins/utils/expand-and-update-selection';
26
27
  import { selectNode } from './pm-plugins/utils/getSelection';
28
+ import { BlockControlsSurface } from './ui/block-controls-surface';
27
29
  import { GlobalStylesWrapper } from './ui/global-styles';
28
30
  export var blockControlsPlugin = function blockControlsPlugin(_ref) {
29
31
  var _config$rightSideCont, _config$quickInsertBu;
@@ -32,6 +34,19 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
32
34
  var nodeDecorationRegistry = [];
33
35
  var rightSideControlsEnabled = (_config$rightSideCont = config === null || config === void 0 ? void 0 : config.rightSideControlsEnabled) !== null && _config$rightSideCont !== void 0 ? _config$rightSideCont : false;
34
36
  var quickInsertButtonEnabled = (_config$quickInsertBu = config === null || config === void 0 ? void 0 : config.quickInsertButtonEnabled) !== null && _config$quickInsertBu !== void 0 ? _config$quickInsertBu : true;
37
+ var blockControlMigrationEnabled = isExperimentEnabled('platform_editor_block_control_migration');
38
+ if (blockControlMigrationEnabled) {
39
+ var _api$uiControlRegistr;
40
+ api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register([BLOCK_CONTROLS_LEFT_SURFACE, _objectSpread(_objectSpread({}, BLOCK_CONTROLS_LEFT_SECTION), {}, {
41
+ parents: [_objectSpread(_objectSpread({}, BLOCK_CONTROLS_LEFT_SURFACE), {}, {
42
+ rank: 100
43
+ })]
44
+ }), _objectSpread(_objectSpread({}, BLOCK_CONTROLS_LEFT_GROUP), {}, {
45
+ parents: [_objectSpread(_objectSpread({}, BLOCK_CONTROLS_LEFT_SECTION), {}, {
46
+ rank: 100
47
+ })]
48
+ })]);
49
+ }
35
50
  return {
36
51
  name: 'blockControls',
37
52
  actions: {
@@ -100,7 +115,7 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
100
115
  plugin: function plugin(_ref2) {
101
116
  var getIntl = _ref2.getIntl,
102
117
  nodeViewPortalProviderAPI = _ref2.nodeViewPortalProviderAPI;
103
- return createPlugin(api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled, quickInsertButtonEnabled);
118
+ return createPlugin(api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled, quickInsertButtonEnabled && !blockControlMigrationEnabled);
104
119
  }
105
120
  }];
106
121
  if (editorExperiment('platform_editor_controls', 'variant1')) {
@@ -415,10 +430,14 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
415
430
  }
416
431
  return sharedState;
417
432
  },
418
- contentComponent: function contentComponent() {
419
- return /*#__PURE__*/React.createElement(GlobalStylesWrapper, {
433
+ contentComponent: function contentComponent(_ref0) {
434
+ var editorView = _ref0.editorView;
435
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(GlobalStylesWrapper, {
420
436
  api: api
421
- });
437
+ }), blockControlMigrationEnabled && editorView && api ? /*#__PURE__*/React.createElement(BlockControlsSurface, {
438
+ api: api,
439
+ editorView: editorView
440
+ }) : null);
422
441
  }
423
442
  };
424
443
  };
@@ -1,6 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { createElement } from 'react';
3
- import { bind } from 'bind-event-listener';
4
3
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
5
4
  import uuid from 'uuid';
6
5
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
@@ -54,7 +53,6 @@ export var dragHandleDecoration = function dragHandleDecoration(_ref) {
54
53
  anchorRectCache = _ref.anchorRectCache,
55
54
  editorState = _ref.editorState;
56
55
  unmountDecorations(nodeViewPortalProviderAPI, 'data-blocks-drag-handle-container', 'data-blocks-drag-handle-key');
57
- var unbind;
58
56
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
59
57
  var key = uuid();
60
58
  var widgetSpec = editorExperiment('platform_editor_breakout_resizing', true) ? {
@@ -67,19 +65,13 @@ export var dragHandleDecoration = function dragHandleDecoration(_ref) {
67
65
  * Exclude 'breakout' on purpose, so the widgets render at the top of the document to avoid z-index issues
68
66
  * Other block marks must be added, otherwise PM will split the DOM elements causing mutations and re-draws
69
67
  */
70
- marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : [],
71
- destroy: function destroy(node) {
72
- unbind && unbind();
73
- }
68
+ marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : []
74
69
  } : {
75
70
  side: -1,
76
71
  type: TYPE_HANDLE_DEC,
77
72
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
78
73
  testid: "".concat(TYPE_HANDLE_DEC, "-").concat(uuid()),
79
- marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : [],
80
- destroy: function destroy(node) {
81
- unbind && unbind();
82
- }
74
+ marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : []
83
75
  };
84
76
  return Decoration.widget(pos, function (view, getPosUnsafe) {
85
77
  var element = document.createElement('span');
@@ -110,18 +102,9 @@ export var dragHandleDecoration = function dragHandleDecoration(_ref) {
110
102
  * However, the tooltip for nested drag handle is no long working.
111
103
  */
112
104
  if (newPos === undefined || !isTopLevelNode) {
113
- if (fg('platform_editor_fix_widget_destroy')) {
114
- element.onmouseover = function (e) {
115
- e.stopPropagation();
116
- };
117
- } else {
118
- unbind = bind(element, {
119
- type: 'mouseover',
120
- listener: function listener(e) {
121
- e.stopPropagation();
122
- }
123
- });
124
- }
105
+ element.onmouseover = function (e) {
106
+ e.stopPropagation();
107
+ };
125
108
  }
126
109
 
127
110
  // There are times when global clear: "both" styles are applied to this decoration causing jumpiness
@@ -56,9 +56,7 @@ export var quickInsertButtonDecoration = function quickInsertButtonDecoration(_r
56
56
 
57
57
  marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, rootPos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : [],
58
58
  destroy: function destroy(_) {
59
- if (fg('platform_editor_fix_widget_destroy')) {
60
- nodeViewPortalProviderAPI.remove(key);
61
- }
59
+ nodeViewPortalProviderAPI.remove(key);
62
60
  cleanupCallbacks.forEach(function (cb) {
63
61
  cb();
64
62
  });
@@ -67,9 +65,7 @@ export var quickInsertButtonDecoration = function quickInsertButtonDecoration(_r
67
65
  side: -2,
68
66
  type: TYPE_QUICK_INSERT,
69
67
  destroy: function destroy(_) {
70
- if (fg('platform_editor_fix_widget_destroy')) {
71
- nodeViewPortalProviderAPI.remove(key);
72
- }
68
+ nodeViewPortalProviderAPI.remove(key);
73
69
  cleanupCallbacks.forEach(function (cb) {
74
70
  cb();
75
71
  });
@@ -0,0 +1,53 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ var getNodeContext = function getNodeContext(view, pos) {
5
+ var node = view.state.doc.nodeAt(pos);
6
+ if (!node) {
7
+ return undefined;
8
+ }
9
+ var $pos = view.state.doc.resolve(pos);
10
+ var ancestors = [];
11
+ for (var depth = 0; depth <= $pos.depth; depth++) {
12
+ var ancestor = $pos.node(depth);
13
+ ancestors.push({
14
+ depth: depth,
15
+ pos: depth === 0 ? 0 : $pos.before(depth),
16
+ type: {
17
+ name: ancestor.type.name
18
+ }
19
+ });
20
+ }
21
+ return {
22
+ ancestors: ancestors,
23
+ depth: $pos.depth + 1,
24
+ node: node,
25
+ parentType: $pos.parent.type.name,
26
+ pos: pos,
27
+ type: {
28
+ name: node.type.name
29
+ }
30
+ };
31
+ };
32
+ export var createBlockControlsSurfaceContext = function createBlockControlsSurfaceContext(view, activeNode) {
33
+ var _activeNode$rootPos, _activeNode$rootNodeT;
34
+ if (!activeNode) {
35
+ return undefined;
36
+ }
37
+ var rootPos = (_activeNode$rootPos = activeNode.rootPos) !== null && _activeNode$rootPos !== void 0 ? _activeNode$rootPos : activeNode.pos;
38
+ var activeNodeContext = getNodeContext(view, activeNode.pos);
39
+ var rootNodeContext = getNodeContext(view, rootPos);
40
+ if (!activeNodeContext || !rootNodeContext) {
41
+ return undefined;
42
+ }
43
+ return {
44
+ activeNode: _objectSpread(_objectSpread({}, activeNodeContext), {}, {
45
+ rootPos: rootPos,
46
+ rootType: {
47
+ name: (_activeNode$rootNodeT = activeNode.rootNodeType) !== null && _activeNode$rootNodeT !== void 0 ? _activeNode$rootNodeT : rootNodeContext.type.name
48
+ }
49
+ }),
50
+ rootNode: rootNodeContext,
51
+ targetNode: rootNodeContext
52
+ };
53
+ };
@@ -0,0 +1,3 @@
1
+ ._1e0c1txw{display:flex}
2
+ ._1pbyb4wl{z-index:100}
3
+ ._kqswstnw{position:absolute}
@@ -0,0 +1,151 @@
1
+ /* block-controls-surface.tsx generated by @compiled/babel-plugin v2.0.0 */
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+ import "./block-controls-surface.compiled.css";
4
+ import { ax, ix } from "@compiled/react/runtime";
5
+ import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
6
+ import { bind } from 'bind-event-listener';
7
+ import { getDocument } from '@atlaskit/browser-apis';
8
+ import { BLOCK_CONTROL_UI_CONTEXT } from '@atlaskit/editor-common/block-controls/block-control-ui-context';
9
+ import { BLOCK_CONTROLS_LEFT_SURFACE } from '@atlaskit/editor-common/block-controls/surface-keys';
10
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
11
+ import { SurfaceRenderer, willSurfaceRender } from '@atlaskit/editor-ui-control-model/surface-renderer';
12
+ import { createSurfaceContext } from '@atlaskit/editor-ui-control-model/types';
13
+ import { getNodeTypeWithLevel } from '../pm-plugins/decorations-common';
14
+ import { createBlockControlsSurfaceContext } from './block-controls-surface-context';
15
+ import { getNodeContentElement } from './utils/get-node-content-element';
16
+ import { getAbsoluteSurfacePlacement, getSurfacePlacement } from './utils/get-surface-placement';
17
+ import { VisibilityContainer } from './visibility-container';
18
+ var BLOCK_CONTROLS_SURFACE_Z_INDEX = 100;
19
+ var surfaceStyles = null;
20
+ export var BlockControlsSurface = function BlockControlsSurface(_ref) {
21
+ var _api$uiControlRegistr, _api$uiControlRegistr2;
22
+ var api = _ref.api,
23
+ editorView = _ref.editorView;
24
+ var activeNode = useSharedPluginStateWithSelector(api, ['blockControls'], function (states) {
25
+ var _states$blockControls;
26
+ return {
27
+ activeNode: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.activeNode
28
+ };
29
+ }).activeNode;
30
+ var _useState = useState(),
31
+ _useState2 = _slicedToArray(_useState, 2),
32
+ position = _useState2[0],
33
+ setPosition = _useState2[1];
34
+ var animationFrameRef = useRef(undefined);
35
+ var components = (_api$uiControlRegistr = (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(BLOCK_CONTROLS_LEFT_SURFACE)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
36
+ var blockControlsContext = useMemo(function () {
37
+ return createBlockControlsSurfaceContext(editorView, activeNode);
38
+ }, [activeNode, editorView]);
39
+ var surfaceContext = useMemo(function () {
40
+ return blockControlsContext ? createSurfaceContext(BLOCK_CONTROL_UI_CONTEXT, blockControlsContext) : undefined;
41
+ }, [blockControlsContext]);
42
+ useLayoutEffect(function () {
43
+ var _getDocument;
44
+ if (!blockControlsContext) {
45
+ setPosition(undefined);
46
+ return;
47
+ }
48
+ var rootNodeElement = editorView.nodeDOM(blockControlsContext.rootNode.pos);
49
+ var rootElement = rootNodeElement instanceof HTMLElement ? rootNodeElement : rootNodeElement === null || rootNodeElement === void 0 ? void 0 : rootNodeElement.parentElement;
50
+ if (!rootElement) {
51
+ setPosition(undefined);
52
+ return;
53
+ }
54
+ var targetElement = getNodeContentElement(rootElement, blockControlsContext.rootNode.type.name);
55
+ var offsetParent = editorView.dom.offsetParent;
56
+ var isDocumentOffsetParent = !offsetParent || offsetParent === ((_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.body);
57
+ var scrollingOffsetParent = offsetParent instanceof HTMLElement && !isDocumentOffsetParent ? offsetParent : undefined;
58
+ var updatePosition = function updatePosition() {
59
+ var _rootElement$getAttri, _scrollingOffsetParen, _scrollingOffsetParen2;
60
+ animationFrameRef.current = undefined;
61
+ if (!rootElement.isConnected || !targetElement.isConnected) {
62
+ setPosition(undefined);
63
+ return;
64
+ }
65
+ var placement = getSurfacePlacement({
66
+ layout: (_rootElement$getAttri = rootElement.getAttribute('layout')) !== null && _rootElement$getAttri !== void 0 ? _rootElement$getAttri : '',
67
+ nodeRect: targetElement.getBoundingClientRect(),
68
+ nodeType: blockControlsContext.rootNode.type.name,
69
+ nodeTypeWithLevel: getNodeTypeWithLevel(blockControlsContext.rootNode.node),
70
+ parentNodeType: blockControlsContext.rootNode.parentType === 'doc' ? undefined : blockControlsContext.rootNode.parentType
71
+ });
72
+ var offsetParentRect = offsetParent === null || offsetParent === void 0 ? void 0 : offsetParent.getBoundingClientRect();
73
+ var offsetParentScrollTop = (_scrollingOffsetParen = scrollingOffsetParent === null || scrollingOffsetParent === void 0 ? void 0 : scrollingOffsetParent.scrollTop) !== null && _scrollingOffsetParen !== void 0 ? _scrollingOffsetParen : window.scrollY;
74
+ var offsetParentScrollLeft = (_scrollingOffsetParen2 = scrollingOffsetParent === null || scrollingOffsetParent === void 0 ? void 0 : scrollingOffsetParent.scrollLeft) !== null && _scrollingOffsetParen2 !== void 0 ? _scrollingOffsetParen2 : window.scrollX;
75
+ setPosition(getAbsoluteSurfacePlacement({
76
+ offsetParentRect: offsetParentRect,
77
+ offsetParentScrollLeft: offsetParentScrollLeft,
78
+ offsetParentScrollTop: offsetParentScrollTop,
79
+ placement: placement
80
+ }));
81
+ };
82
+ var schedulePositionUpdate = function schedulePositionUpdate() {
83
+ if (animationFrameRef.current === undefined) {
84
+ animationFrameRef.current = requestAnimationFrame(updatePosition);
85
+ }
86
+ };
87
+ updatePosition();
88
+ var resizeObserver = new ResizeObserver(schedulePositionUpdate);
89
+ resizeObserver.observe(editorView.dom);
90
+ if (targetElement && targetElement !== editorView.dom) {
91
+ resizeObserver.observe(targetElement);
92
+ }
93
+ if (offsetParent instanceof HTMLElement && offsetParent !== editorView.dom) {
94
+ resizeObserver.observe(offsetParent);
95
+ }
96
+ var unbindWindowResize = bind(window, {
97
+ type: 'resize',
98
+ listener: schedulePositionUpdate
99
+ });
100
+ var unbindWindowScroll = bind(window, {
101
+ type: 'scroll',
102
+ listener: schedulePositionUpdate,
103
+ options: {
104
+ capture: true,
105
+ passive: true
106
+ }
107
+ });
108
+ var visualViewport = window.visualViewport;
109
+ var unbindVisualViewportResize = visualViewport ? bind(visualViewport, {
110
+ type: 'resize',
111
+ listener: schedulePositionUpdate
112
+ }) : undefined;
113
+ var unbindVisualViewportScroll = visualViewport ? bind(visualViewport, {
114
+ type: 'scroll',
115
+ listener: schedulePositionUpdate
116
+ }) : undefined;
117
+ var unbindTransitionEnd = bind(targetElement, {
118
+ type: 'transitionend',
119
+ listener: schedulePositionUpdate
120
+ });
121
+ return function () {
122
+ if (animationFrameRef.current !== undefined) {
123
+ cancelAnimationFrame(animationFrameRef.current);
124
+ animationFrameRef.current = undefined;
125
+ }
126
+ resizeObserver.disconnect();
127
+ unbindWindowResize();
128
+ unbindWindowScroll();
129
+ unbindVisualViewportResize === null || unbindVisualViewportResize === void 0 || unbindVisualViewportResize();
130
+ unbindVisualViewportScroll === null || unbindVisualViewportScroll === void 0 || unbindVisualViewportScroll();
131
+ unbindTransitionEnd();
132
+ };
133
+ }, [blockControlsContext, editorView]);
134
+ if (components.length === 0 || !blockControlsContext || !surfaceContext || !position || !willSurfaceRender(components, BLOCK_CONTROLS_LEFT_SURFACE, surfaceContext)) {
135
+ return null;
136
+ }
137
+ return /*#__PURE__*/React.createElement("div", {
138
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Placement is resolved from the active node's runtime DOM geometry.
139
+ style: position,
140
+ "data-testid": "block-controls-left-surface",
141
+ className: ax(["_1e0c1txw _kqswstnw _1pbyb4wl"])
142
+ }, /*#__PURE__*/React.createElement(VisibilityContainer, {
143
+ api: api,
144
+ controlSide: "left",
145
+ shouldUseDisplayContents: true
146
+ }, /*#__PURE__*/React.createElement(SurfaceRenderer, {
147
+ components: components,
148
+ surface: BLOCK_CONTROLS_LEFT_SURFACE,
149
+ surfaceContext: surfaceContext
150
+ })));
151
+ };
@@ -153,6 +153,15 @@ var getQuickInsertAnchorReference = function getQuickInsertAnchorReference(_ref)
153
153
  }
154
154
  return "anchor(".concat(safeAnchorName, " ").concat(edge, ")");
155
155
  };
156
+
157
+ /**
158
+ * Legacy widget-decoration Quick Insert implementation.
159
+ *
160
+ * Its behavior is intentionally duplicated by the registry-backed control in
161
+ * `editor-plugin-quick-insert`. Remove this implementation when
162
+ * `platform_editor_block_control_migration` is cleaned up; until then this path remains unchanged
163
+ * for users outside the experiment.
164
+ */
156
165
  export var TypeAheadControl = function TypeAheadControl(_ref2) {
157
166
  var view = _ref2.view,
158
167
  api = _ref2.api,
@@ -0,0 +1,18 @@
1
+ import { resizerItemClassName } from '@atlaskit/editor-common/styles';
2
+ var INNER_CONTAINER_SELECTORS = {
3
+ blockCard: '.datasourceView-content-inner-wrap',
4
+ bodiedExtension: '.extension-container[data-layout]',
5
+ embedCard: '.rich-media-item',
6
+ extension: '.extension-container[data-layout]',
7
+ mediaSingle: ".".concat(resizerItemClassName),
8
+ multiBodiedExtension: '.extension-container[data-layout]',
9
+ table: ".".concat(resizerItemClassName)
10
+ };
11
+ export var getNodeContentElement = function getNodeContentElement(nodeElement, nodeType) {
12
+ var _nodeElement$querySel;
13
+ var selector = INNER_CONTAINER_SELECTORS[nodeType];
14
+ if (!selector) {
15
+ return nodeElement;
16
+ }
17
+ return (_nodeElement$querySel = nodeElement.querySelector(selector)) !== null && _nodeElement$querySel !== void 0 ? _nodeElement$querySel : nodeElement;
18
+ };