@atlaskit/editor-plugin-block-controls 1.1.0 → 1.3.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +23 -3
  2. package/dist/cjs/plugin.js +36 -2
  3. package/dist/cjs/pm-plugins/decorations.js +71 -0
  4. package/dist/cjs/pm-plugins/main.js +95 -4
  5. package/dist/cjs/ui/consts.js +8 -0
  6. package/dist/cjs/ui/drag-handle-menu.js +15 -0
  7. package/dist/cjs/ui/drag-handle.js +93 -0
  8. package/dist/cjs/ui/drag-preview.js +35 -0
  9. package/dist/cjs/ui/drop-target.js +72 -0
  10. package/dist/cjs/ui/global-styles.js +19 -0
  11. package/dist/es2019/plugin.js +35 -3
  12. package/dist/es2019/pm-plugins/decorations.js +64 -0
  13. package/dist/es2019/pm-plugins/main.js +97 -5
  14. package/dist/es2019/ui/consts.js +2 -0
  15. package/dist/es2019/ui/drag-handle-menu.js +10 -0
  16. package/dist/es2019/ui/drag-handle.js +86 -0
  17. package/dist/es2019/ui/drag-preview.js +27 -0
  18. package/dist/es2019/ui/drop-target.js +55 -0
  19. package/dist/es2019/ui/global-styles.js +12 -0
  20. package/dist/esm/plugin.js +36 -3
  21. package/dist/esm/pm-plugins/decorations.js +64 -0
  22. package/dist/esm/pm-plugins/main.js +95 -4
  23. package/dist/esm/ui/consts.js +2 -0
  24. package/dist/esm/ui/drag-handle-menu.js +8 -0
  25. package/dist/esm/ui/drag-handle.js +86 -0
  26. package/dist/esm/ui/drag-preview.js +29 -0
  27. package/dist/esm/ui/drop-target.js +62 -0
  28. package/dist/esm/ui/global-styles.js +12 -0
  29. package/dist/types/pm-plugins/decorations.d.ts +12 -0
  30. package/dist/types/pm-plugins/main.d.ts +2 -9
  31. package/dist/types/types.d.ts +25 -2
  32. package/dist/types/ui/consts.d.ts +2 -0
  33. package/dist/types/ui/drag-handle-menu.d.ts +6 -0
  34. package/dist/types/ui/drag-handle.d.ts +8 -0
  35. package/dist/types/ui/drag-preview.d.ts +1 -0
  36. package/dist/types/ui/drop-target.d.ts +7 -0
  37. package/dist/types/ui/global-styles.d.ts +3 -0
  38. package/dist/types-ts4.5/pm-plugins/decorations.d.ts +12 -0
  39. package/dist/types-ts4.5/pm-plugins/main.d.ts +2 -9
  40. package/dist/types-ts4.5/types.d.ts +25 -2
  41. package/dist/types-ts4.5/ui/consts.d.ts +2 -0
  42. package/dist/types-ts4.5/ui/drag-handle-menu.d.ts +6 -0
  43. package/dist/types-ts4.5/ui/drag-handle.d.ts +8 -0
  44. package/dist/types-ts4.5/ui/drag-preview.d.ts +1 -0
  45. package/dist/types-ts4.5/ui/drop-target.d.ts +7 -0
  46. package/dist/types-ts4.5/ui/global-styles.d.ts +3 -0
  47. package/package.json +7 -4
@@ -1,6 +1,7 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
3
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
4
+ import { dragHandleDecoration, dropTargetDecorations } from './decorations';
4
5
  export const key = new PluginKey('blockControls');
5
6
  export const createPlugin = api => {
6
7
  return new SafePlugin({
@@ -8,15 +9,74 @@ export const createPlugin = api => {
8
9
  state: {
9
10
  init() {
10
11
  return {
11
- decorations: DecorationSet.empty
12
+ decorations: DecorationSet.empty,
13
+ decorationState: [],
14
+ activeNode: null,
15
+ isDragging: false,
16
+ isMenuOpen: false,
17
+ start: null,
18
+ end: null
12
19
  };
13
20
  },
14
- apply(tr, currentState) {
15
- const {
16
- decorations
21
+ apply(tr, currentState, oldState, newState) {
22
+ var _decorationState, _meta$pos, _meta$isDragging;
23
+ // return currentState;
24
+ let {
25
+ activeNode,
26
+ decorations,
27
+ isMenuOpen,
28
+ decorationState
17
29
  } = currentState;
30
+ const meta = tr.getMeta(key);
31
+
32
+ // Drag handle decoration
33
+ if (meta && meta.pos !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos) && api) {
34
+ decorations = dragHandleDecoration(newState, meta, api);
35
+ }
36
+ // Drop target decorations
37
+ if (meta !== null && meta !== void 0 && meta.isDragging && api) {
38
+ decorations = DecorationSet.create(newState.doc, []);
39
+ const {
40
+ decs,
41
+ decorationState: updatedDecorationState
42
+ } = dropTargetDecorations(oldState, newState, api);
43
+ decorationState = updatedDecorationState;
44
+ decorations = decorations.add(newState.doc, decs);
45
+ }
46
+
47
+ // Remove drop target decorations when dragging is stopped
48
+ if ((meta === null || meta === void 0 ? void 0 : meta.isDragging) === false) {
49
+ decorations = DecorationSet.create(newState.doc, []);
50
+ }
51
+
52
+ // Map decorations when the document changes
53
+ if (tr.docChanged && decorations !== DecorationSet.empty) {
54
+ decorations = decorations.map(tr.mapping, tr.doc);
55
+ }
56
+
57
+ // Map drop target decoration positions when the document changes
58
+ if (tr.docChanged && currentState.isDragging) {
59
+ decorationState = decorationState.map(({
60
+ index,
61
+ pos
62
+ }) => {
63
+ return {
64
+ index,
65
+ pos: tr.mapping.map(pos)
66
+ };
67
+ });
68
+ }
69
+
70
+ // Map active node position when the document changes
71
+ const mappedActiveNodePos = tr.docChanged && activeNode ? tr.mapping.map(activeNode.pos) : activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
18
72
  return {
19
- decorations
73
+ decorations,
74
+ decorationState: (_decorationState = decorationState) !== null && _decorationState !== void 0 ? _decorationState : currentState.decorationState,
75
+ activeNode: {
76
+ pos: (_meta$pos = meta === null || meta === void 0 ? void 0 : meta.pos) !== null && _meta$pos !== void 0 ? _meta$pos : mappedActiveNodePos
77
+ },
78
+ isDragging: (_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : currentState.isDragging,
79
+ isMenuOpen: meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen
20
80
  };
21
81
  }
22
82
  },
@@ -24,6 +84,38 @@ export const createPlugin = api => {
24
84
  decorations: state => {
25
85
  var _key$getState;
26
86
  return (_key$getState = key.getState(state)) === null || _key$getState === void 0 ? void 0 : _key$getState.decorations;
87
+ },
88
+ handleDOMEvents: {
89
+ mousemove(view, event) {
90
+ const pos = view.posAtCoords({
91
+ left: event.clientX,
92
+ top: event.clientY
93
+ });
94
+ if (pos !== null && pos !== void 0 && pos.inside && pos.inside > 0) {
95
+ var _api$core;
96
+ const node = view.state.doc.nodeAt(pos.inside);
97
+ if (!node) {
98
+ return;
99
+ }
100
+ const resolvedPos = view.state.doc.resolve(pos.pos);
101
+ const topLevelPos = resolvedPos.before(1); // 1 here restricts the depth to the root level
102
+ const topLevelNode = view.state.doc.nodeAt(topLevelPos);
103
+ if (!topLevelNode) {
104
+ return;
105
+ }
106
+ const dom = view.nodeDOM(topLevelPos);
107
+ if (!dom) {
108
+ return;
109
+ }
110
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
111
+ tr
112
+ }) => tr.setMeta(key, {
113
+ pos: topLevelPos,
114
+ dom,
115
+ type: topLevelNode.type.name
116
+ }));
117
+ }
118
+ }
27
119
  }
28
120
  }
29
121
  });
@@ -0,0 +1,2 @@
1
+ export const DRAG_HANDLE_HEIGHT = 48;
2
+ export const DRAG_HANDLE_WIDTH = 24;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
3
+ export const DragHandleMenu = ({
4
+ api
5
+ }) => {
6
+ const {
7
+ blockControlsState
8
+ } = useSharedPluginState(api, ['blockControls']);
9
+ return blockControlsState !== null && blockControlsState !== void 0 && blockControlsState.isMenuOpen ? /*#__PURE__*/React.createElement("div", null, "menu") : null;
10
+ };
@@ -0,0 +1,86 @@
1
+ /** @jsx jsx */
2
+ import { useEffect, useRef } from 'react';
3
+ import { css, jsx } from '@emotion/react';
4
+ import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
5
+ import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
6
+ import { key } from '../pm-plugins/main';
7
+ import { DRAG_HANDLE_HEIGHT, DRAG_HANDLE_WIDTH } from './consts';
8
+ import { dragPreview } from './drag-preview';
9
+ const styles = css({
10
+ position: 'absolute',
11
+ // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage
12
+ background: 'grey',
13
+ zIndex: 1,
14
+ height: DRAG_HANDLE_HEIGHT,
15
+ width: DRAG_HANDLE_WIDTH,
16
+ left: -DRAG_HANDLE_WIDTH
17
+ });
18
+ export const DragHandle = ({
19
+ dom,
20
+ api,
21
+ start
22
+ }) => {
23
+ const buttonRef = useRef(null);
24
+ const domRef = useRef(dom);
25
+ useEffect(() => {
26
+ const element = buttonRef.current;
27
+ if (!element) {
28
+ return;
29
+ }
30
+ return draggable({
31
+ element,
32
+ onGenerateDragPreview: ({
33
+ nativeSetDragImage
34
+ }) => {
35
+ setCustomNativeDragPreview({
36
+ getOffset: () => {
37
+ const rect = domRef.current.getBoundingClientRect();
38
+ // Offset the drag preview to the center of the element
39
+ return {
40
+ x: 0,
41
+ y: rect.height / 2
42
+ };
43
+ },
44
+ render: ({
45
+ container
46
+ }) => {
47
+ return dragPreview(container, domRef);
48
+ },
49
+ nativeSetDragImage
50
+ });
51
+ },
52
+ onDragStart() {
53
+ var _api$core;
54
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
55
+ tr
56
+ }) => tr.setMeta(key, {
57
+ isDragging: true,
58
+ start
59
+ }));
60
+ },
61
+ onDrop() {
62
+ var _api$core2;
63
+ api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(({
64
+ tr
65
+ }) => tr.setMeta(key, {
66
+ isDragging: false
67
+ }));
68
+ }
69
+ });
70
+ }, [api, start]);
71
+ return jsx("div", {
72
+ css: styles,
73
+ style: {
74
+ top: dom.clientHeight / 2 - DRAG_HANDLE_HEIGHT / 2
75
+ },
76
+ ref: buttonRef,
77
+ onClick: () => {
78
+ var _api$core3;
79
+ api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
80
+ tr
81
+ }) => tr.setMeta(key, {
82
+ toggleMenu: true
83
+ }));
84
+ }
85
+ });
86
+ };
@@ -0,0 +1,27 @@
1
+ export const dragPreview = (container, domRef) => {
2
+ const rect = domRef.current.getBoundingClientRect();
3
+ container.style.width = `${rect.width}px`;
4
+ container.style.height = `${rect.height}px`;
5
+ container.style.pointerEvents = 'none';
6
+ const parent = document.createElement('div');
7
+ // ProseMirror class is required to make sure the cloned dom is styled correctly
8
+ parent.classList.add('ProseMirror');
9
+ const clonedDom = domRef.current.cloneNode(true);
10
+
11
+ // Remove any margin from the cloned element to ensure is doesn't position incorrectly
12
+ clonedDom.style.marginLeft = '0';
13
+ clonedDom.style.marginTop = '0';
14
+ clonedDom.style.marginRight = '0';
15
+ clonedDom.style.marginBottom = '0';
16
+ parent.appendChild(clonedDom);
17
+ container.appendChild(parent);
18
+ const scrollParent = document.querySelector('.fabric-editor-popup-scroll-parent');
19
+ const scrollParentClassNames = scrollParent === null || scrollParent === void 0 ? void 0 : scrollParent.className;
20
+
21
+ // Add the scroll parent class to the container to ensure the cloned element is styled correctly
22
+ container.className = scrollParentClassNames || '';
23
+ container.classList.remove('fabric-editor-popup-scroll-parent');
24
+ // Prevents a scrollbar from showing
25
+ container.style.overflow = 'visible';
26
+ return () => container;
27
+ };
@@ -0,0 +1,55 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
3
+ export const DropTarget = ({
4
+ api,
5
+ index
6
+ }) => {
7
+ const ref = useRef(null);
8
+ const [isDraggedOver, setIsDraggedOver] = useState(false);
9
+ useEffect(() => {
10
+ const element = ref.current;
11
+ if (!element) {
12
+ return;
13
+ }
14
+ return dropTargetForElements({
15
+ element,
16
+ getIsSticky: () => true,
17
+ onDragEnter: () => setIsDraggedOver(true),
18
+ onDragLeave: () => setIsDraggedOver(false),
19
+ onDrop: () => {
20
+ var _api$blockControls;
21
+ const {
22
+ activeNode,
23
+ decorationState
24
+ } = (api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {};
25
+ if (!activeNode || !decorationState) {
26
+ return;
27
+ }
28
+ const {
29
+ pos
30
+ } = decorationState.find(dec => dec.index === index) || {};
31
+ if (activeNode && pos !== undefined) {
32
+ var _api$core, _api$blockControls2, _api$blockControls2$c;
33
+ const {
34
+ pos: start
35
+ } = activeNode;
36
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : (_api$blockControls2$c = _api$blockControls2.commands) === null || _api$blockControls2$c === void 0 ? void 0 : _api$blockControls2$c.moveNode(start, pos));
37
+ }
38
+ }
39
+ });
40
+ }, [index, api]);
41
+ return (
42
+ /*#__PURE__*/
43
+ // Note: Firefox has trouble with using a button element as the handle for drag and drop
44
+ React.createElement("div", {
45
+ style: {
46
+ height: '20px',
47
+ marginTop: '-22px',
48
+ top: '10px',
49
+ position: 'relative',
50
+ borderBottom: `solid ${isDraggedOver ? 'blue' : 'transparent'} 2px`
51
+ },
52
+ ref: ref
53
+ })
54
+ );
55
+ };
@@ -0,0 +1,12 @@
1
+ /** @jsx jsx */
2
+ import { css, Global, jsx } from '@emotion/react';
3
+ const globalStyles = css({
4
+ '.ProseMirror-widget:first-child + *': {
5
+ 'margin-top': '0 !important'
6
+ }
7
+ });
8
+ export const GlobalStylesWrapper = () => {
9
+ return jsx(Global, {
10
+ styles: globalStyles
11
+ });
12
+ };
@@ -1,4 +1,7 @@
1
- import { createPlugin } from './pm-plugins/main';
1
+ import React from 'react';
2
+ import { createPlugin, key } from './pm-plugins/main';
3
+ import { DragHandleMenu } from './ui/drag-handle-menu';
4
+ import { GlobalStylesWrapper } from './ui/global-styles';
2
5
  export var blockControlsPlugin = function blockControlsPlugin(_ref) {
3
6
  var api = _ref.api;
4
7
  return {
@@ -11,8 +14,38 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
11
14
  }
12
15
  }];
13
16
  },
14
- getSharedState: function getSharedState(_editorState) {
15
- return undefined;
17
+ commands: {
18
+ moveNode: function moveNode(start, to) {
19
+ return function (_ref2) {
20
+ var _node$nodeSize, _api$core;
21
+ var tr = _ref2.tr;
22
+ var node = tr.doc.nodeAt(start);
23
+ var size = (_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 1;
24
+ var end = start + size;
25
+ var nodeCopy = tr.doc.content.cut(start, end); // cut the content
26
+ tr.delete(start, end); // delete the content from the original position
27
+ var mappedTo = tr.mapping.map(to);
28
+ tr.insert(mappedTo, nodeCopy); // insert the content at the new position
29
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.focus();
30
+ return tr;
31
+ };
32
+ }
33
+ },
34
+ getSharedState: function getSharedState(editorState) {
35
+ var _key$getState$isMenuO, _key$getState, _key$getState$activeN, _key$getState2, _key$getState$decorat, _key$getState3;
36
+ if (!editorState) {
37
+ return undefined;
38
+ }
39
+ return {
40
+ isMenuOpen: (_key$getState$isMenuO = (_key$getState = key.getState(editorState)) === null || _key$getState === void 0 ? void 0 : _key$getState.isMenuOpen) !== null && _key$getState$isMenuO !== void 0 ? _key$getState$isMenuO : false,
41
+ activeNode: (_key$getState$activeN = (_key$getState2 = key.getState(editorState)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.activeNode) !== null && _key$getState$activeN !== void 0 ? _key$getState$activeN : null,
42
+ decorationState: (_key$getState$decorat = (_key$getState3 = key.getState(editorState)) === null || _key$getState3 === void 0 ? void 0 : _key$getState3.decorationState) !== null && _key$getState$decorat !== void 0 ? _key$getState$decorat : []
43
+ };
44
+ },
45
+ contentComponent: function contentComponent() {
46
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DragHandleMenu, {
47
+ api: api
48
+ }), /*#__PURE__*/React.createElement(GlobalStylesWrapper, null));
16
49
  }
17
50
  };
18
51
  };
@@ -0,0 +1,64 @@
1
+ import { createElement } from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
4
+ import { DragHandle } from '../ui/drag-handle';
5
+ import { DropTarget } from '../ui/drop-target';
6
+ export var dropTargetDecorations = function dropTargetDecorations(oldState, newState, api) {
7
+ var decs = [];
8
+ // Decoration state is used to keep track of the position of the drop targets
9
+ // and allows us to easily map the updated position in the plugin apply method.
10
+ var decorationState = [];
11
+ oldState.doc.nodesBetween(0, newState.doc.nodeSize - 2, function (_node, pos, _parent, index) {
12
+ decorationState.push({
13
+ index: index,
14
+ pos: pos
15
+ });
16
+ decs.push(Decoration.widget(pos, function () {
17
+ var element = document.createElement('div');
18
+ ReactDOM.render( /*#__PURE__*/createElement(DropTarget, {
19
+ api: api,
20
+ index: index
21
+ }), element);
22
+ return element;
23
+ }));
24
+ return false;
25
+ });
26
+
27
+ /**
28
+ * We are adding a drop target at the end of the document because by default we
29
+ * draw all drop targets at the top of every node. It's better to draw the drop targets
30
+ * at the top of each node because that way we only need to know the start position of the
31
+ * node and not its size.
32
+ *
33
+ */
34
+ decorationState.push({
35
+ index: decorationState.length + 1,
36
+ pos: newState.doc.nodeSize - 2
37
+ });
38
+ decs.push(Decoration.widget(newState.doc.nodeSize - 2, function () {
39
+ var element = document.createElement('div');
40
+ ReactDOM.render( /*#__PURE__*/createElement(DropTarget, {
41
+ api: api,
42
+ index: decorationState.length
43
+ }), element);
44
+ return element;
45
+ }));
46
+ return {
47
+ decs: decs,
48
+ decorationState: decorationState
49
+ };
50
+ };
51
+ export var dragHandleDecoration = function dragHandleDecoration(oldState,
52
+ // @ts-ignore
53
+ meta, api) {
54
+ return DecorationSet.create(oldState.doc, [Decoration.widget(meta.pos, function (view, getPos) {
55
+ var element = document.createElement('div');
56
+ ReactDOM.render( /*#__PURE__*/createElement(DragHandle, {
57
+ dom: meta.dom,
58
+ api: api,
59
+ start: meta.pos
60
+ }), element);
61
+ element.style.position = 'absolute';
62
+ return element;
63
+ })]);
64
+ };
@@ -1,6 +1,7 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
3
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
4
+ import { dragHandleDecoration, dropTargetDecorations } from './decorations';
4
5
  export var key = new PluginKey('blockControls');
5
6
  export var createPlugin = function createPlugin(api) {
6
7
  return new SafePlugin({
@@ -8,13 +9,70 @@ export var createPlugin = function createPlugin(api) {
8
9
  state: {
9
10
  init: function init() {
10
11
  return {
11
- decorations: DecorationSet.empty
12
+ decorations: DecorationSet.empty,
13
+ decorationState: [],
14
+ activeNode: null,
15
+ isDragging: false,
16
+ isMenuOpen: false,
17
+ start: null,
18
+ end: null
12
19
  };
13
20
  },
14
- apply: function apply(tr, currentState) {
15
- var decorations = currentState.decorations;
21
+ apply: function apply(tr, currentState, oldState, newState) {
22
+ var _decorationState, _meta$pos, _meta$isDragging;
23
+ // return currentState;
24
+ var activeNode = currentState.activeNode,
25
+ decorations = currentState.decorations,
26
+ isMenuOpen = currentState.isMenuOpen,
27
+ decorationState = currentState.decorationState;
28
+ var meta = tr.getMeta(key);
29
+
30
+ // Drag handle decoration
31
+ if (meta && meta.pos !== (activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos) && api) {
32
+ decorations = dragHandleDecoration(newState, meta, api);
33
+ }
34
+ // Drop target decorations
35
+ if (meta !== null && meta !== void 0 && meta.isDragging && api) {
36
+ decorations = DecorationSet.create(newState.doc, []);
37
+ var _dropTargetDecoration = dropTargetDecorations(oldState, newState, api),
38
+ decs = _dropTargetDecoration.decs,
39
+ updatedDecorationState = _dropTargetDecoration.decorationState;
40
+ decorationState = updatedDecorationState;
41
+ decorations = decorations.add(newState.doc, decs);
42
+ }
43
+
44
+ // Remove drop target decorations when dragging is stopped
45
+ if ((meta === null || meta === void 0 ? void 0 : meta.isDragging) === false) {
46
+ decorations = DecorationSet.create(newState.doc, []);
47
+ }
48
+
49
+ // Map decorations when the document changes
50
+ if (tr.docChanged && decorations !== DecorationSet.empty) {
51
+ decorations = decorations.map(tr.mapping, tr.doc);
52
+ }
53
+
54
+ // Map drop target decoration positions when the document changes
55
+ if (tr.docChanged && currentState.isDragging) {
56
+ decorationState = decorationState.map(function (_ref) {
57
+ var index = _ref.index,
58
+ pos = _ref.pos;
59
+ return {
60
+ index: index,
61
+ pos: tr.mapping.map(pos)
62
+ };
63
+ });
64
+ }
65
+
66
+ // Map active node position when the document changes
67
+ var mappedActiveNodePos = tr.docChanged && activeNode ? tr.mapping.map(activeNode.pos) : activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
16
68
  return {
17
- decorations: decorations
69
+ decorations: decorations,
70
+ decorationState: (_decorationState = decorationState) !== null && _decorationState !== void 0 ? _decorationState : currentState.decorationState,
71
+ activeNode: {
72
+ pos: (_meta$pos = meta === null || meta === void 0 ? void 0 : meta.pos) !== null && _meta$pos !== void 0 ? _meta$pos : mappedActiveNodePos
73
+ },
74
+ isDragging: (_meta$isDragging = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging !== void 0 ? _meta$isDragging : currentState.isDragging,
75
+ isMenuOpen: meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen
18
76
  };
19
77
  }
20
78
  },
@@ -22,6 +80,39 @@ export var createPlugin = function createPlugin(api) {
22
80
  decorations: function decorations(state) {
23
81
  var _key$getState;
24
82
  return (_key$getState = key.getState(state)) === null || _key$getState === void 0 ? void 0 : _key$getState.decorations;
83
+ },
84
+ handleDOMEvents: {
85
+ mousemove: function mousemove(view, event) {
86
+ var pos = view.posAtCoords({
87
+ left: event.clientX,
88
+ top: event.clientY
89
+ });
90
+ if (pos !== null && pos !== void 0 && pos.inside && pos.inside > 0) {
91
+ var _api$core;
92
+ var node = view.state.doc.nodeAt(pos.inside);
93
+ if (!node) {
94
+ return;
95
+ }
96
+ var resolvedPos = view.state.doc.resolve(pos.pos);
97
+ var topLevelPos = resolvedPos.before(1); // 1 here restricts the depth to the root level
98
+ var topLevelNode = view.state.doc.nodeAt(topLevelPos);
99
+ if (!topLevelNode) {
100
+ return;
101
+ }
102
+ var dom = view.nodeDOM(topLevelPos);
103
+ if (!dom) {
104
+ return;
105
+ }
106
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
107
+ var tr = _ref2.tr;
108
+ return tr.setMeta(key, {
109
+ pos: topLevelPos,
110
+ dom: dom,
111
+ type: topLevelNode.type.name
112
+ });
113
+ });
114
+ }
115
+ }
25
116
  }
26
117
  }
27
118
  });
@@ -0,0 +1,2 @@
1
+ export var DRAG_HANDLE_HEIGHT = 48;
2
+ export var DRAG_HANDLE_WIDTH = 24;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
3
+ export var DragHandleMenu = function DragHandleMenu(_ref) {
4
+ var api = _ref.api;
5
+ var _useSharedPluginState = useSharedPluginState(api, ['blockControls']),
6
+ blockControlsState = _useSharedPluginState.blockControlsState;
7
+ return blockControlsState !== null && blockControlsState !== void 0 && blockControlsState.isMenuOpen ? /*#__PURE__*/React.createElement("div", null, "menu") : null;
8
+ };
@@ -0,0 +1,86 @@
1
+ /** @jsx jsx */
2
+ import { useEffect, useRef } from 'react';
3
+ import { css, jsx } from '@emotion/react';
4
+ import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
5
+ import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
6
+ import { key } from '../pm-plugins/main';
7
+ import { DRAG_HANDLE_HEIGHT, DRAG_HANDLE_WIDTH } from './consts';
8
+ import { dragPreview } from './drag-preview';
9
+ var styles = css({
10
+ position: 'absolute',
11
+ // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage
12
+ background: 'grey',
13
+ zIndex: 1,
14
+ height: DRAG_HANDLE_HEIGHT,
15
+ width: DRAG_HANDLE_WIDTH,
16
+ left: -DRAG_HANDLE_WIDTH
17
+ });
18
+ export var DragHandle = function DragHandle(_ref) {
19
+ var dom = _ref.dom,
20
+ api = _ref.api,
21
+ start = _ref.start;
22
+ var buttonRef = useRef(null);
23
+ var domRef = useRef(dom);
24
+ useEffect(function () {
25
+ var element = buttonRef.current;
26
+ if (!element) {
27
+ return;
28
+ }
29
+ return draggable({
30
+ element: element,
31
+ onGenerateDragPreview: function onGenerateDragPreview(_ref2) {
32
+ var nativeSetDragImage = _ref2.nativeSetDragImage;
33
+ setCustomNativeDragPreview({
34
+ getOffset: function getOffset() {
35
+ var rect = domRef.current.getBoundingClientRect();
36
+ // Offset the drag preview to the center of the element
37
+ return {
38
+ x: 0,
39
+ y: rect.height / 2
40
+ };
41
+ },
42
+ render: function render(_ref3) {
43
+ var container = _ref3.container;
44
+ return dragPreview(container, domRef);
45
+ },
46
+ nativeSetDragImage: nativeSetDragImage
47
+ });
48
+ },
49
+ onDragStart: function onDragStart() {
50
+ var _api$core;
51
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref4) {
52
+ var tr = _ref4.tr;
53
+ return tr.setMeta(key, {
54
+ isDragging: true,
55
+ start: start
56
+ });
57
+ });
58
+ },
59
+ onDrop: function onDrop() {
60
+ var _api$core2;
61
+ api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref5) {
62
+ var tr = _ref5.tr;
63
+ return tr.setMeta(key, {
64
+ isDragging: false
65
+ });
66
+ });
67
+ }
68
+ });
69
+ }, [api, start]);
70
+ return jsx("div", {
71
+ css: styles,
72
+ style: {
73
+ top: dom.clientHeight / 2 - DRAG_HANDLE_HEIGHT / 2
74
+ },
75
+ ref: buttonRef,
76
+ onClick: function onClick() {
77
+ var _api$core3;
78
+ api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref6) {
79
+ var tr = _ref6.tr;
80
+ return tr.setMeta(key, {
81
+ toggleMenu: true
82
+ });
83
+ });
84
+ }
85
+ });
86
+ };