@atlaskit/editor-plugin-block-controls 17.1.1 → 17.1.3
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 +18 -0
- package/dist/cjs/blockControlsPlugin.js +14 -6
- package/dist/cjs/pm-plugins/main.js +14 -6
- package/dist/cjs/ui/block-controls-surface-context.js +2 -1
- package/dist/cjs/ui/block-controls-surface-drag-handle-registration.js +37 -0
- package/dist/cjs/ui/block-controls-surface-drag-handle-utils.js +45 -0
- package/dist/cjs/ui/block-controls-surface-drag-handle.compiled.css +32 -0
- package/dist/cjs/ui/block-controls-surface-drag-handle.js +296 -0
- package/dist/cjs/ui/block-controls-surface.compiled.css +2 -1
- package/dist/cjs/ui/block-controls-surface.js +49 -24
- package/dist/cjs/ui/consts.js +2 -1
- package/dist/cjs/ui/global-styles.js +1 -21
- package/dist/cjs/ui/surface-editor-view-context.js +12 -0
- package/dist/cjs/ui/use-block-controls-surface-drag-source.js +172 -0
- package/dist/cjs/ui/utils/get-surface-placement.js +8 -1
- package/dist/es2019/blockControlsPlugin.js +13 -6
- package/dist/es2019/pm-plugins/main.js +14 -7
- package/dist/es2019/ui/block-controls-surface-context.js +2 -2
- package/dist/es2019/ui/block-controls-surface-drag-handle-registration.js +26 -0
- package/dist/es2019/ui/block-controls-surface-drag-handle-utils.js +33 -0
- package/dist/es2019/ui/block-controls-surface-drag-handle.compiled.css +32 -0
- package/dist/es2019/ui/block-controls-surface-drag-handle.js +282 -0
- package/dist/es2019/ui/block-controls-surface.compiled.css +2 -1
- package/dist/es2019/ui/block-controls-surface.js +48 -22
- package/dist/es2019/ui/consts.js +1 -0
- package/dist/es2019/ui/global-styles.js +1 -21
- package/dist/es2019/ui/surface-editor-view-context.js +4 -0
- package/dist/es2019/ui/use-block-controls-surface-drag-source.js +170 -0
- package/dist/es2019/ui/utils/get-surface-placement.js +15 -6
- package/dist/esm/blockControlsPlugin.js +14 -6
- package/dist/esm/pm-plugins/main.js +14 -6
- package/dist/esm/ui/block-controls-surface-context.js +2 -1
- package/dist/esm/ui/block-controls-surface-drag-handle-registration.js +30 -0
- package/dist/esm/ui/block-controls-surface-drag-handle-utils.js +38 -0
- package/dist/esm/ui/block-controls-surface-drag-handle.compiled.css +32 -0
- package/dist/esm/ui/block-controls-surface-drag-handle.js +290 -0
- package/dist/esm/ui/block-controls-surface.compiled.css +2 -1
- package/dist/esm/ui/block-controls-surface.js +49 -24
- package/dist/esm/ui/consts.js +1 -0
- package/dist/esm/ui/global-styles.js +1 -21
- package/dist/esm/ui/surface-editor-view-context.js +6 -0
- package/dist/esm/ui/use-block-controls-surface-drag-source.js +166 -0
- package/dist/esm/ui/utils/get-surface-placement.js +9 -2
- package/dist/types/pm-plugins/main.d.ts +6 -1
- package/dist/types/ui/block-controls-surface-context.d.ts +1 -1
- package/dist/types/ui/block-controls-surface-drag-handle-registration.d.ts +6 -0
- package/dist/types/ui/block-controls-surface-drag-handle-utils.d.ts +14 -0
- package/dist/types/ui/block-controls-surface-drag-handle.d.ts +10 -0
- package/dist/types/ui/block-controls-surface.d.ts +1 -0
- package/dist/types/ui/consts.d.ts +1 -0
- package/dist/types/ui/surface-editor-view-context.d.ts +5 -0
- package/dist/types/ui/use-block-controls-surface-drag-source.d.ts +19 -0
- package/dist/types/ui/utils/get-surface-placement.d.ts +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/* block-controls-surface-drag-handle.tsx generated by @compiled/babel-plugin v2.0.0 */
|
|
2
|
+
import "./block-controls-surface-drag-handle.compiled.css";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
5
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
import { useIntl } from 'react-intl';
|
|
7
|
+
|
|
8
|
+
// oxlint-disable-next-line typescript/consistent-type-imports -- jsx is the runtime factory for the classic JSX pragma above.
|
|
9
|
+
|
|
10
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
11
|
+
import { BLOCK_CONTROL_UI_CONTEXT } from '@atlaskit/editor-common/block-controls/block-control-ui-context';
|
|
12
|
+
import { surfaceDragHandleElementStore } from '@atlaskit/editor-common/block-controls/surface-drag-handle-element';
|
|
13
|
+
import { getBrowserInfo } from '@atlaskit/editor-common/browser';
|
|
14
|
+
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
15
|
+
import { TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps';
|
|
16
|
+
import { blockControlsMessages } from '@atlaskit/editor-common/messages';
|
|
17
|
+
import DragHandleVerticalIcon from '@atlaskit/icon/core/drag-handle-vertical';
|
|
18
|
+
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
19
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
20
|
+
import Tooltip from '@atlaskit/tooltip/Tooltip';
|
|
21
|
+
import { selectionPreservationPluginKey } from '../pm-plugins/selection-preservation/plugin-key';
|
|
22
|
+
import { expandAndUpdateSelection } from '../pm-plugins/utils/expand-and-update-selection';
|
|
23
|
+
import { isHandleCorrelatedToSelection } from '../pm-plugins/utils/getSelection';
|
|
24
|
+
import { buildLayoutColumnMenuMeta } from './block-controls-surface-drag-handle-utils';
|
|
25
|
+
import { DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH } from './consts';
|
|
26
|
+
import { DragHandleNestedIcon } from './drag-handle-nested-icon';
|
|
27
|
+
import { shouldUseNestedDragHandleIcon } from './should-use-nested-drag-handle-icon';
|
|
28
|
+
import { useSurfaceEditorView } from './surface-editor-view-context';
|
|
29
|
+
import { useBlockControlsSurfaceDragSource } from './use-block-controls-surface-drag-source';
|
|
30
|
+
import { getAnchorAttrName, NODE_ANCHOR_ATTR_NAME } from './utils/dom-attr-name';
|
|
31
|
+
|
|
32
|
+
// Keep style values co-located for Compiled while matching the legacy drag handle dimensions.
|
|
33
|
+
const SURFACE_DRAG_HANDLE_HEIGHT = 24;
|
|
34
|
+
const SURFACE_DRAG_HANDLE_WIDTH = 12;
|
|
35
|
+
const SURFACE_DRAG_HANDLE_BORDER_RADIUS = 4;
|
|
36
|
+
const SURFACE_DRAG_HANDLE_Z_INDEX = 100;
|
|
37
|
+
const dragHandleStyles = {
|
|
38
|
+
root: "_19itglyw _2rko1y44 _12ji1r31 _1qu2glyw _12y31o36 _1e0c1txw _vchhusvi _2lx21bp4 _4cvr1h6o _1bah1h6o _4t3i1tcg _1bsb1crf _bfhksm61 _syazdgkc _80om1qgj _1pbyb4wl _ca0qze3t _u5f3ze3t _n3tdze3t _19bvze3t _cun91j28 _vbqb2sac _1ygbdfik _irr31dpa _6g80187o _1di6fcek",
|
|
39
|
+
scaled: "_4t3i1myc _1bsbx5ub",
|
|
40
|
+
selected: "_bfhk15s3 _syazxl6c",
|
|
41
|
+
keyboardFocused: "_1a37dfik",
|
|
42
|
+
firefoxSelection: "_1p1y1j28",
|
|
43
|
+
layoutColumn: "_t9ec14w8",
|
|
44
|
+
iconWrapper: "_1e0c1txw _4cvr1h6o _1bah1h6o"
|
|
45
|
+
};
|
|
46
|
+
const handleIconDragStart = event => {
|
|
47
|
+
var _event$currentTarget$;
|
|
48
|
+
if (!getBrowserInfo().chrome) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
event.stopPropagation();
|
|
52
|
+
(_event$currentTarget$ = event.currentTarget.parentElement) === null || _event$currentTarget$ === void 0 ? void 0 : _event$currentTarget$.dispatchEvent(new DragEvent('dragstart', {
|
|
53
|
+
bubbles: true,
|
|
54
|
+
cancelable: true,
|
|
55
|
+
dataTransfer: event.dataTransfer
|
|
56
|
+
}));
|
|
57
|
+
};
|
|
58
|
+
const isSelected = (selection, pos, view) => {
|
|
59
|
+
if (typeof pos !== 'number' || !selection || !view) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return isHandleCorrelatedToSelection(view.state, selection, pos);
|
|
63
|
+
};
|
|
64
|
+
export const BlockControlsSurfaceDragHandle = ({
|
|
65
|
+
api,
|
|
66
|
+
surfaceContext
|
|
67
|
+
}) => {
|
|
68
|
+
var _activeNode$type$name;
|
|
69
|
+
const {
|
|
70
|
+
formatMessage
|
|
71
|
+
} = useIntl();
|
|
72
|
+
const view = useSurfaceEditorView();
|
|
73
|
+
const context = surfaceContext === null || surfaceContext === void 0 ? void 0 : surfaceContext.get(BLOCK_CONTROL_UI_CONTEXT);
|
|
74
|
+
const activeNode = context === null || context === void 0 ? void 0 : context.activeNode;
|
|
75
|
+
const pos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.pos;
|
|
76
|
+
const nodeType = (_activeNode$type$name = activeNode === null || activeNode === void 0 ? void 0 : activeNode.type.name) !== null && _activeNode$type$name !== void 0 ? _activeNode$type$name : '';
|
|
77
|
+
const buttonRef = useRef(null);
|
|
78
|
+
const posRef = useRef(pos);
|
|
79
|
+
posRef.current = pos;
|
|
80
|
+
const getPos = useCallback(() => posRef.current, []);
|
|
81
|
+
const {
|
|
82
|
+
activeNodeAnchorName,
|
|
83
|
+
handleOptions,
|
|
84
|
+
interactionState,
|
|
85
|
+
isShiftDown,
|
|
86
|
+
selection
|
|
87
|
+
} = useSharedPluginStateWithSelector(api, ['blockControls', 'interaction', 'selection'], states => {
|
|
88
|
+
var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$blockControls4, _states$interactionSt, _states$blockControls5, _states$selectionStat;
|
|
89
|
+
return {
|
|
90
|
+
activeNodeAnchorName: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : (_states$blockControls2 = _states$blockControls.activeNode) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.anchorName,
|
|
91
|
+
handleOptions: (_states$blockControls3 = states.blockControlsState) === null || _states$blockControls3 === void 0 ? void 0 : (_states$blockControls4 = _states$blockControls3.activeNode) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.handleOptions,
|
|
92
|
+
interactionState: (_states$interactionSt = states.interactionState) === null || _states$interactionSt === void 0 ? void 0 : _states$interactionSt.interactionState,
|
|
93
|
+
isShiftDown: (_states$blockControls5 = states.blockControlsState) === null || _states$blockControls5 === void 0 ? void 0 : _states$blockControls5.isShiftDown,
|
|
94
|
+
selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
const [dragHandleSelected, setDragHandleSelected] = useState(false);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
setDragHandleSelected(isSelected(selection, pos, view));
|
|
100
|
+
}, [pos, selection, view]);
|
|
101
|
+
const isLayoutColumn = nodeType === 'layoutColumn';
|
|
102
|
+
const isTopLevelNode = (activeNode === null || activeNode === void 0 ? void 0 : activeNode.parentType) === 'doc';
|
|
103
|
+
const isDisabled = useMemo(() => {
|
|
104
|
+
var _api$blockControls$sh;
|
|
105
|
+
if (!isShiftDown || !view || view.state.selection.empty || !fg('platform_editor_elements_dnd_shift_click_select')) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if (isLayoutColumn && expValEquals('platform_editor_layout_column_menu', 'isEnabled', true)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const multiSelect = api === null || api === void 0 ? void 0 : (_api$blockControls$sh = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh === void 0 ? void 0 : _api$blockControls$sh.multiSelectDnD;
|
|
112
|
+
const $anchor = (multiSelect === null || multiSelect === void 0 ? void 0 : multiSelect.anchor) !== undefined ? view.state.doc.resolve(multiSelect.anchor) : view.state.selection.$anchor;
|
|
113
|
+
return !isTopLevelNode || $anchor.depth > DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH;
|
|
114
|
+
}, [api, isLayoutColumn, isShiftDown, isTopLevelNode, view]);
|
|
115
|
+
const getAnchorName = useCallback(() => {
|
|
116
|
+
var _ref, _ref2, _dom$getAttribute, _dom$closest;
|
|
117
|
+
if (activeNodeAnchorName) {
|
|
118
|
+
return activeNodeAnchorName;
|
|
119
|
+
}
|
|
120
|
+
const currentPos = posRef.current;
|
|
121
|
+
if (!view || currentPos === undefined) {
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
const dom = view.nodeDOM(currentPos);
|
|
125
|
+
if (!(dom instanceof HTMLElement)) {
|
|
126
|
+
return '';
|
|
127
|
+
}
|
|
128
|
+
const anchorAttrName = getAnchorAttrName();
|
|
129
|
+
return (_ref = (_ref2 = (_dom$getAttribute = dom.getAttribute(anchorAttrName)) !== null && _dom$getAttribute !== void 0 ? _dom$getAttribute : dom.getAttribute(NODE_ANCHOR_ATTR_NAME)) !== null && _ref2 !== void 0 ? _ref2 : (_dom$closest = dom.closest(`[${anchorAttrName}]`)) === null || _dom$closest === void 0 ? void 0 : _dom$closest.getAttribute(anchorAttrName)) !== null && _ref !== void 0 ? _ref : '';
|
|
130
|
+
}, [activeNodeAnchorName, view]);
|
|
131
|
+
useLayoutEffect(() => {
|
|
132
|
+
const element = buttonRef.current;
|
|
133
|
+
if (!view || !element) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
surfaceDragHandleElementStore.set(view, element);
|
|
137
|
+
return () => surfaceDragHandleElementStore.release(view, element);
|
|
138
|
+
}, [view]);
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (!(handleOptions !== null && handleOptions !== void 0 && handleOptions.isFocused) || !buttonRef.current || !view) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
let animationFrameId;
|
|
144
|
+
let attempts = 0;
|
|
145
|
+
const focusHandle = () => {
|
|
146
|
+
const button = buttonRef.current;
|
|
147
|
+
if (!button) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
button.focus();
|
|
151
|
+
if (button.ownerDocument.activeElement !== button && attempts < 5) {
|
|
152
|
+
attempts++;
|
|
153
|
+
animationFrameId = requestAnimationFrame(focusHandle);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
focusHandle();
|
|
157
|
+
return () => {
|
|
158
|
+
if (animationFrameId !== undefined) {
|
|
159
|
+
cancelAnimationFrame(animationFrameId);
|
|
160
|
+
}
|
|
161
|
+
view.focus();
|
|
162
|
+
};
|
|
163
|
+
}, [handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused, view]);
|
|
164
|
+
useBlockControlsSurfaceDragSource({
|
|
165
|
+
api,
|
|
166
|
+
elementRef: buttonRef,
|
|
167
|
+
getAnchorName,
|
|
168
|
+
getPos,
|
|
169
|
+
nodeType,
|
|
170
|
+
start: pos,
|
|
171
|
+
view
|
|
172
|
+
});
|
|
173
|
+
const handleMouseDown = useCallback(() => {
|
|
174
|
+
var _api$core, _api$blockControls;
|
|
175
|
+
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$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.setSelectedViaDragHandle(true));
|
|
176
|
+
}, [api]);
|
|
177
|
+
const handleClick = useCallback(event => {
|
|
178
|
+
var _api$core2;
|
|
179
|
+
if (!view || isDisabled) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const openedViaKeyboard = event.detail === 0;
|
|
183
|
+
api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(({
|
|
184
|
+
tr
|
|
185
|
+
}) => {
|
|
186
|
+
var _selectionPreservatio, _selectionPreservatio2, _api$analytics, _resolvedStartPos$nod, _api$blockControls2, _api$blockControls3, _activeNode$rootPos;
|
|
187
|
+
const startPos = getPos();
|
|
188
|
+
if (startPos === undefined) {
|
|
189
|
+
return tr;
|
|
190
|
+
}
|
|
191
|
+
if (nodeType === 'layoutColumn' && expValEquals('platform_editor_layout_column_menu', 'isEnabled', true)) {
|
|
192
|
+
tr.setMeta('toggleLayoutColumnMenu', buildLayoutColumnMenuMeta(startPos, openedViaKeyboard));
|
|
193
|
+
}
|
|
194
|
+
const selection = (_selectionPreservatio = (_selectionPreservatio2 = selectionPreservationPluginKey.getState(view.state)) === null || _selectionPreservatio2 === void 0 ? void 0 : _selectionPreservatio2.preservedSelection) !== null && _selectionPreservatio !== void 0 ? _selectionPreservatio : tr.selection;
|
|
195
|
+
const resolvedStartPos = tr.doc.resolve(startPos);
|
|
196
|
+
api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.attachAnalyticsEvent({
|
|
197
|
+
action: ACTION.CLICKED,
|
|
198
|
+
actionSubject: ACTION_SUBJECT.BUTTON,
|
|
199
|
+
actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
|
|
200
|
+
attributes: {
|
|
201
|
+
nodeDepth: resolvedStartPos.depth,
|
|
202
|
+
nodeTypes: ((_resolvedStartPos$nod = resolvedStartPos.nodeAfter) === null || _resolvedStartPos$nod === void 0 ? void 0 : _resolvedStartPos$nod.type.name) || ''
|
|
203
|
+
},
|
|
204
|
+
eventType: EVENT_TYPE.UI
|
|
205
|
+
})(tr);
|
|
206
|
+
expandAndUpdateSelection({
|
|
207
|
+
api,
|
|
208
|
+
isShiftPressed: event.shiftKey,
|
|
209
|
+
nodeType,
|
|
210
|
+
selection,
|
|
211
|
+
startPos,
|
|
212
|
+
tr
|
|
213
|
+
});
|
|
214
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.startPreservingSelection()({
|
|
215
|
+
tr
|
|
216
|
+
});
|
|
217
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.toggleBlockMenu({
|
|
218
|
+
anchorName: getAnchorName(),
|
|
219
|
+
openedViaKeyboard,
|
|
220
|
+
triggerByNode: {
|
|
221
|
+
nodeType,
|
|
222
|
+
pos: startPos,
|
|
223
|
+
rootPos: (_activeNode$rootPos = activeNode === null || activeNode === void 0 ? void 0 : activeNode.rootPos) !== null && _activeNode$rootPos !== void 0 ? _activeNode$rootPos : resolvedStartPos.before(1)
|
|
224
|
+
}
|
|
225
|
+
})({
|
|
226
|
+
tr
|
|
227
|
+
});
|
|
228
|
+
tr.setMeta('scrollIntoView', false);
|
|
229
|
+
return tr;
|
|
230
|
+
});
|
|
231
|
+
view.focus();
|
|
232
|
+
}, [activeNode === null || activeNode === void 0 ? void 0 : activeNode.rootPos, api, getAnchorName, getPos, isDisabled, nodeType, view]);
|
|
233
|
+
const label = formatMessage(blockControlsMessages.dragToMoveClickToOpen, {
|
|
234
|
+
br: ' '
|
|
235
|
+
});
|
|
236
|
+
const helpDescriptors = useMemo(() => [{
|
|
237
|
+
description: formatMessage(blockControlsMessages.dragToMoveClickToOpen, {
|
|
238
|
+
br: /*#__PURE__*/React.createElement("br", null)
|
|
239
|
+
})
|
|
240
|
+
}], [formatMessage]);
|
|
241
|
+
const handleTooltipShow = useCallback(() => {
|
|
242
|
+
var _api$accessibilityUti;
|
|
243
|
+
api === null || api === void 0 ? void 0 : (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 ? void 0 : _api$accessibilityUti.actions.ariaNotify(label, {
|
|
244
|
+
priority: 'important'
|
|
245
|
+
});
|
|
246
|
+
}, [api, label]);
|
|
247
|
+
if (!view || !activeNode || pos === undefined) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const tooltipContent = /*#__PURE__*/React.createElement(TooltipContentWithMultipleShortcuts, {
|
|
251
|
+
helpDescriptors: helpDescriptors
|
|
252
|
+
});
|
|
253
|
+
const browser = getBrowserInfo();
|
|
254
|
+
const button = /*#__PURE__*/React.createElement("button", {
|
|
255
|
+
ref: buttonRef,
|
|
256
|
+
type: "button",
|
|
257
|
+
"aria-label": label,
|
|
258
|
+
disabled: isDisabled,
|
|
259
|
+
onClick: handleClick,
|
|
260
|
+
onMouseDown: handleMouseDown
|
|
261
|
+
// eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop -- Pragmatic DnD owns this native drag source.
|
|
262
|
+
,
|
|
263
|
+
onDrop: event => event.stopPropagation(),
|
|
264
|
+
"data-editor-block-ctrl-drag-handle": true,
|
|
265
|
+
"data-blocks-drag-handle": fg('confluence_remix_button_right_side_block_fg') || undefined,
|
|
266
|
+
"data-testid": "block-controls-surface-drag-handle",
|
|
267
|
+
className: ax([dragHandleStyles.root, browser.gecko && dragHandleStyles.firefoxSelection, isLayoutColumn && dragHandleStyles.layoutColumn, dragHandleSelected && interactionState !== 'hasNotHadInteraction' && dragHandleStyles.selected, (handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused) && dragHandleStyles.keyboardFocused, dragHandleStyles.scaled])
|
|
268
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
269
|
+
onDragStart: handleIconDragStart,
|
|
270
|
+
className: ax([dragHandleStyles.iconWrapper])
|
|
271
|
+
}, shouldUseNestedDragHandleIcon(Boolean(isTopLevelNode), isLayoutColumn) ? /*#__PURE__*/React.createElement(DragHandleNestedIcon, null) : /*#__PURE__*/React.createElement(DragHandleVerticalIcon, {
|
|
272
|
+
label: "",
|
|
273
|
+
size: "small",
|
|
274
|
+
spacing: "spacious"
|
|
275
|
+
})));
|
|
276
|
+
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
277
|
+
position: "top",
|
|
278
|
+
content: tooltipContent,
|
|
279
|
+
ignoreTooltipPointerEvents: true,
|
|
280
|
+
onShow: handleTooltipShow
|
|
281
|
+
}, button);
|
|
282
|
+
};
|
|
@@ -16,21 +16,17 @@ import { getAbsoluteSurfacePlacement, getSurfacePlacement } from './utils/get-su
|
|
|
16
16
|
import { VisibilityContainer } from './visibility-container';
|
|
17
17
|
const BLOCK_CONTROLS_SURFACE_Z_INDEX = 100;
|
|
18
18
|
const surfaceStyles = null;
|
|
19
|
-
|
|
19
|
+
const BlockControlsSurfaceAtTarget = ({
|
|
20
|
+
activeNode,
|
|
20
21
|
api,
|
|
21
|
-
editorView
|
|
22
|
+
editorView,
|
|
23
|
+
target
|
|
22
24
|
}) => {
|
|
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;
|
|
25
|
+
var _api$uiControlRegistr, _api$uiControlRegistr2, _activeNode$handleOpt;
|
|
30
26
|
const [position, setPosition] = useState();
|
|
31
27
|
const animationFrameRef = useRef(undefined);
|
|
32
28
|
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]);
|
|
29
|
+
const blockControlsContext = useMemo(() => createBlockControlsSurfaceContext(editorView, activeNode, target), [activeNode, editorView, target]);
|
|
34
30
|
const surfaceContext = useMemo(() => blockControlsContext ? createSurfaceContext(BLOCK_CONTROL_UI_CONTEXT, blockControlsContext) : undefined, [blockControlsContext]);
|
|
35
31
|
useLayoutEffect(() => {
|
|
36
32
|
var _getDocument;
|
|
@@ -38,29 +34,29 @@ export const BlockControlsSurface = ({
|
|
|
38
34
|
setPosition(undefined);
|
|
39
35
|
return;
|
|
40
36
|
}
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
37
|
+
const targetNodeElement = editorView.nodeDOM(blockControlsContext.targetNode.pos);
|
|
38
|
+
const targetElementRoot = targetNodeElement instanceof HTMLElement ? targetNodeElement : targetNodeElement === null || targetNodeElement === void 0 ? void 0 : targetNodeElement.parentElement;
|
|
39
|
+
if (!targetElementRoot) {
|
|
44
40
|
setPosition(undefined);
|
|
45
41
|
return;
|
|
46
42
|
}
|
|
47
|
-
const targetElement = getNodeContentElement(
|
|
43
|
+
const targetElement = getNodeContentElement(targetElementRoot, blockControlsContext.targetNode.type.name);
|
|
48
44
|
const offsetParent = editorView.dom.offsetParent;
|
|
49
45
|
const isDocumentOffsetParent = !offsetParent || offsetParent === ((_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.body);
|
|
50
46
|
const scrollingOffsetParent = offsetParent instanceof HTMLElement && !isDocumentOffsetParent ? offsetParent : undefined;
|
|
51
47
|
const updatePosition = () => {
|
|
52
|
-
var
|
|
48
|
+
var _targetElementRoot$ge, _scrollingOffsetParen, _scrollingOffsetParen2;
|
|
53
49
|
animationFrameRef.current = undefined;
|
|
54
|
-
if (!
|
|
50
|
+
if (!targetElementRoot.isConnected || !targetElement.isConnected) {
|
|
55
51
|
setPosition(undefined);
|
|
56
52
|
return;
|
|
57
53
|
}
|
|
58
54
|
const placement = getSurfacePlacement({
|
|
59
|
-
layout: (
|
|
55
|
+
layout: (_targetElementRoot$ge = targetElementRoot.getAttribute('layout')) !== null && _targetElementRoot$ge !== void 0 ? _targetElementRoot$ge : '',
|
|
60
56
|
nodeRect: targetElement.getBoundingClientRect(),
|
|
61
|
-
nodeType: blockControlsContext.
|
|
62
|
-
nodeTypeWithLevel: getNodeTypeWithLevel(blockControlsContext.
|
|
63
|
-
parentNodeType: blockControlsContext.
|
|
57
|
+
nodeType: blockControlsContext.targetNode.type.name,
|
|
58
|
+
nodeTypeWithLevel: getNodeTypeWithLevel(blockControlsContext.targetNode.node),
|
|
59
|
+
parentNodeType: blockControlsContext.targetNode.parentType === 'doc' ? undefined : blockControlsContext.targetNode.parentType
|
|
64
60
|
});
|
|
65
61
|
const offsetParentRect = offsetParent === null || offsetParent === void 0 ? void 0 : offsetParent.getBoundingClientRect();
|
|
66
62
|
const offsetParentScrollTop = (_scrollingOffsetParen = scrollingOffsetParent === null || scrollingOffsetParent === void 0 ? void 0 : scrollingOffsetParent.scrollTop) !== null && _scrollingOffsetParen !== void 0 ? _scrollingOffsetParen : window.scrollY;
|
|
@@ -128,17 +124,47 @@ export const BlockControlsSurface = ({
|
|
|
128
124
|
return null;
|
|
129
125
|
}
|
|
130
126
|
return /*#__PURE__*/React.createElement("div", {
|
|
127
|
+
"data-editor-block-controls-surface": true
|
|
131
128
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Placement is resolved from the active node's runtime DOM geometry.
|
|
129
|
+
,
|
|
132
130
|
style: position,
|
|
133
|
-
"data-testid":
|
|
134
|
-
className: ax(["_1e0c1txw _kqswstnw _1pbyb4wl"])
|
|
131
|
+
"data-testid": target === 'root' ? 'block-controls-left-surface' : 'block-controls-left-surface-active',
|
|
132
|
+
className: ax(["_zulpv77o _4cvr1h6o _1e0c1txw _kqswstnw _1pbyb4wl"])
|
|
135
133
|
}, /*#__PURE__*/React.createElement(VisibilityContainer, {
|
|
136
134
|
api: api,
|
|
137
135
|
controlSide: "left",
|
|
136
|
+
forceVisibleOnMouseOut: Boolean((_activeNode$handleOpt = activeNode.handleOptions) === null || _activeNode$handleOpt === void 0 ? void 0 : _activeNode$handleOpt.isFocused),
|
|
138
137
|
shouldUseDisplayContents: true
|
|
139
138
|
}, /*#__PURE__*/React.createElement(SurfaceRenderer, {
|
|
140
139
|
components: components,
|
|
141
140
|
surface: BLOCK_CONTROLS_LEFT_SURFACE,
|
|
142
141
|
surfaceContext: surfaceContext
|
|
143
142
|
})));
|
|
143
|
+
};
|
|
144
|
+
export const BlockControlsSurface = ({
|
|
145
|
+
api,
|
|
146
|
+
editorView
|
|
147
|
+
}) => {
|
|
148
|
+
var _activeNode$rootPos;
|
|
149
|
+
const activeNode = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
|
|
150
|
+
var _states$blockControls;
|
|
151
|
+
return {
|
|
152
|
+
activeNode: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.activeNode
|
|
153
|
+
};
|
|
154
|
+
}).activeNode;
|
|
155
|
+
if (!activeNode) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const rootPos = (_activeNode$rootPos = activeNode.rootPos) !== null && _activeNode$rootPos !== void 0 ? _activeNode$rootPos : activeNode.pos;
|
|
159
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(BlockControlsSurfaceAtTarget, {
|
|
160
|
+
activeNode: activeNode,
|
|
161
|
+
api: api,
|
|
162
|
+
editorView: editorView,
|
|
163
|
+
target: "root"
|
|
164
|
+
}), rootPos !== activeNode.pos ? /*#__PURE__*/React.createElement(BlockControlsSurfaceAtTarget, {
|
|
165
|
+
activeNode: activeNode,
|
|
166
|
+
api: api,
|
|
167
|
+
editorView: editorView,
|
|
168
|
+
target: "active"
|
|
169
|
+
}) : null);
|
|
144
170
|
};
|
package/dist/es2019/ui/consts.js
CHANGED
|
@@ -7,6 +7,7 @@ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equ
|
|
|
7
7
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
8
8
|
export const ACTIVE_DRAG_HANDLE_ATTR = 'data-active-drag-handle';
|
|
9
9
|
export const ACTIVE_QUICK_INSERT_ATTR = 'data-active-quick-insert';
|
|
10
|
+
export const BLOCK_CONTROLS_SURFACE_SELECTOR = '[data-editor-block-controls-surface]';
|
|
10
11
|
export const ACTIVE_DRAG_HANDLE_FALLBACK_ANCHOR_NAME = '--editor-block-controls-active-drag-handle-anchor';
|
|
11
12
|
export const ACTIVE_QUICK_INSERT_FALLBACK_ANCHOR_NAME = '--editor-block-controls-active-quick-insert-anchor';
|
|
12
13
|
export const DRAG_HANDLE_HEIGHT = 24;
|
|
@@ -300,23 +300,6 @@ const globalStyles = () => css({
|
|
|
300
300
|
marginTop: '0 !important'
|
|
301
301
|
}
|
|
302
302
|
});
|
|
303
|
-
const topLevelNodeMarginStyles = css({
|
|
304
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766
|
|
305
|
-
'.ProseMirror': {
|
|
306
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
|
|
307
|
-
'> .ProseMirror-widget:first-child + .ProseMirror-gapcursor + *:not([data-layout-section="true"], [data-prosemirror-node-name="bodiedSyncBlock"]), > .ProseMirror-widget:first-child + *:not([data-layout-section="true"], [data-prosemirror-node-name="bodiedSyncBlock"])': {
|
|
308
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-important-styles -- Ignored via go/DSP-18766
|
|
309
|
-
marginTop: '0 !important'
|
|
310
|
-
},
|
|
311
|
-
// Reach through a font-size wrapper to zero the inner content margin (e.g. during drag when a
|
|
312
|
-
// drop target widget is inserted before the wrapper).
|
|
313
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
|
|
314
|
-
'> .ProseMirror-widget:first-child + .ProseMirror-widget + .fabric-editor-font-size > :is(p, h1, h2, h3, h4, h5, h6):first-child, > .ProseMirror-widget:first-child + .ProseMirror-gapcursor + .fabric-editor-font-size > :is(p, h1, h2, h3, h4, h5, h6):first-child': {
|
|
315
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-important-styles
|
|
316
|
-
marginTop: '0 !important'
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
303
|
const withDividerInPanelStyleFix = css({
|
|
321
304
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-values
|
|
322
305
|
[`${dividerBodiedInCustomPanelWithNoIconSelector}`]: {
|
|
@@ -528,10 +511,7 @@ export const GlobalStylesWrapper = ({
|
|
|
528
511
|
exposure: true
|
|
529
512
|
}) ? expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? extendHoverZoneReducedNext : extendHoverZoneReduced : undefined,
|
|
530
513
|
// platform_editor_controls note: this allows drag handles to render on empty lines
|
|
531
|
-
toolbarFlagsEnabled ? undefined : withInlineNodeStyle, withDeleteLinesStyleFix, withMediaSingleStyleFix, legacyBreakoutWideLayoutStyle, headingWithIndentationInLayoutStyleFix, editorExperiment('advanced_layouts', true) ? blockCardWithoutLayout : undefined, withDividerInPanelStyleFix, withFormatInLayoutStyleFix, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? withRelativePosStyleNext : withRelativePosStyle,
|
|
532
|
-
// When `platform_editor_first_node_fix` is enabled, EditorContentContainer applies the
|
|
533
|
-
// equivalent rules (`firstNodeWidgetFixStyles`), so skip them here to avoid duplication.
|
|
534
|
-
expValEquals('platform_editor_first_node_fix', 'isEnabled', true) ? undefined : topLevelNodeMarginStyles, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? withAnchorNameZindexStyleNext : withAnchorNameZindexStyle, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) && expValEquals('advanced_layouts', 'isEnabled', true) ? layoutColumnExtendedHoverZone : layoutColumnWithoutHoverZone, expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true) ?
|
|
514
|
+
toolbarFlagsEnabled ? undefined : withInlineNodeStyle, withDeleteLinesStyleFix, withMediaSingleStyleFix, legacyBreakoutWideLayoutStyle, headingWithIndentationInLayoutStyleFix, editorExperiment('advanced_layouts', true) ? blockCardWithoutLayout : undefined, withDividerInPanelStyleFix, withFormatInLayoutStyleFix, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? withRelativePosStyleNext : withRelativePosStyle, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? withAnchorNameZindexStyleNext : withAnchorNameZindexStyle, expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) && expValEquals('advanced_layouts', 'isEnabled', true) ? layoutColumnExtendedHoverZone : layoutColumnWithoutHoverZone, expValEquals('platform_editor_controls_reliable_anchor', 'isEnabled', true) ?
|
|
535
515
|
// dragAnchorStyles sets anchor-name on ALL nodes during drag (needed for drop target positioning).
|
|
536
516
|
// staticControlsAnchorStyles handles anchor-name via node decorations for non-drag state.
|
|
537
517
|
// shouldRenderAnchors guards both: only apply anchor styles on browsers that support CSS anchor positioning.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
/** Provides registered block-control surface contributors with their owning editor view. */
|
|
3
|
+
export const SurfaceEditorViewContext = /*#__PURE__*/createContext(undefined);
|
|
4
|
+
export const useSurfaceEditorView = () => useContext(SurfaceEditorViewContext);
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
3
|
+
import { startMeasure } from '@atlaskit/editor-common/performance-measures';
|
|
4
|
+
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter';
|
|
6
|
+
import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/utils/set-custom-native-drag-preview';
|
|
7
|
+
import { defaultActiveAnchorTracker } from '../pm-plugins/utils/active-anchor-tracker';
|
|
8
|
+
import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
|
|
9
|
+
import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection';
|
|
10
|
+
import { dragPreview } from './drag-preview';
|
|
11
|
+
import { getNodeMarginsForDragPreview, getNodeSpacingForDragPreview } from './block-controls-surface-drag-handle-utils';
|
|
12
|
+
const EDITOR_BLOCKS_DRAG_INIT = 'Editor Blocks Drag Initialization Time';
|
|
13
|
+
/**
|
|
14
|
+
* Registry surface drag source. This intentionally duplicates the stable widget handle's drag
|
|
15
|
+
* contract so the legacy implementation remains byte-for-byte unchanged during migration.
|
|
16
|
+
*/
|
|
17
|
+
export const useBlockControlsSurfaceDragSource = ({
|
|
18
|
+
api,
|
|
19
|
+
elementRef,
|
|
20
|
+
getAnchorName,
|
|
21
|
+
getPos,
|
|
22
|
+
nodeType,
|
|
23
|
+
start,
|
|
24
|
+
view
|
|
25
|
+
}) => {
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const element = elementRef.current;
|
|
28
|
+
if (!element || !view) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
return draggable({
|
|
32
|
+
element,
|
|
33
|
+
getInitialData: () => ({
|
|
34
|
+
type: 'element',
|
|
35
|
+
start
|
|
36
|
+
}),
|
|
37
|
+
onGenerateDragPreview: ({
|
|
38
|
+
nativeSetDragImage
|
|
39
|
+
}) => {
|
|
40
|
+
var _api$core, _api$blockControls$sh;
|
|
41
|
+
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
|
|
42
|
+
tr
|
|
43
|
+
}) => {
|
|
44
|
+
const handlePos = getPos();
|
|
45
|
+
if (typeof handlePos !== 'number') {
|
|
46
|
+
return tr;
|
|
47
|
+
}
|
|
48
|
+
if (!tr.selection.empty && isHandleCorrelatedToSelection(view.state, tr.selection, handlePos)) {
|
|
49
|
+
var _api$blockControls;
|
|
50
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.setMultiSelectPositions()({
|
|
51
|
+
tr
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
tr = selectNode(tr, handlePos, nodeType, api);
|
|
55
|
+
}
|
|
56
|
+
return tr;
|
|
57
|
+
});
|
|
58
|
+
const startPos = getPos();
|
|
59
|
+
const {
|
|
60
|
+
doc,
|
|
61
|
+
selection
|
|
62
|
+
} = view.state;
|
|
63
|
+
let sliceFrom = selection.from;
|
|
64
|
+
let sliceTo = selection.to;
|
|
65
|
+
const multiSelect = api === null || api === void 0 ? void 0 : (_api$blockControls$sh = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh === void 0 ? void 0 : _api$blockControls$sh.multiSelectDnD;
|
|
66
|
+
if (multiSelect) {
|
|
67
|
+
sliceFrom = Math.min(multiSelect.anchor, multiSelect.head);
|
|
68
|
+
sliceTo = Math.max(multiSelect.anchor, multiSelect.head);
|
|
69
|
+
}
|
|
70
|
+
const expandedSlice = doc.slice(sliceFrom, sliceTo);
|
|
71
|
+
const isDraggingMultipleNodes = startPos !== undefined && startPos >= sliceFrom && startPos < sliceTo && expandedSlice.content.childCount > 1;
|
|
72
|
+
setCustomNativeDragPreview({
|
|
73
|
+
getOffset: () => {
|
|
74
|
+
if (!isDraggingMultipleNodes || startPos === undefined) {
|
|
75
|
+
return {
|
|
76
|
+
x: 0,
|
|
77
|
+
y: 0
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const domAtPos = view.domAtPos.bind(view);
|
|
81
|
+
let heightBeforeHandle = 0;
|
|
82
|
+
let nodeStart = sliceFrom;
|
|
83
|
+
let activeNodeMarginTop = 0;
|
|
84
|
+
for (let index = 0; index < expandedSlice.content.childCount; index++) {
|
|
85
|
+
var _node$nodeSize;
|
|
86
|
+
const node = expandedSlice.content.maybeChild(index);
|
|
87
|
+
const nodeEnd = nodeStart + ((_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 0);
|
|
88
|
+
if (nodeEnd <= startPos) {
|
|
89
|
+
const nodeElement = findDomRefAtPos(nodeStart, domAtPos);
|
|
90
|
+
const margins = getNodeMarginsForDragPreview(node);
|
|
91
|
+
heightBeforeHandle += (nodeElement instanceof HTMLElement ? nodeElement.offsetHeight : 0) + margins.top + margins.bottom;
|
|
92
|
+
} else {
|
|
93
|
+
activeNodeMarginTop = getNodeMarginsForDragPreview(node).top;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
nodeStart = nodeEnd;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
x: 0,
|
|
100
|
+
y: heightBeforeHandle + activeNodeMarginTop
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
render: ({
|
|
104
|
+
container
|
|
105
|
+
}) => {
|
|
106
|
+
if (!isDraggingMultipleNodes && startPos !== undefined) {
|
|
107
|
+
const dom = findDomRefAtPos(startPos, view.domAtPos.bind(view));
|
|
108
|
+
return dom instanceof HTMLElement ? dragPreview(container, {
|
|
109
|
+
dom,
|
|
110
|
+
nodeType
|
|
111
|
+
}) : undefined;
|
|
112
|
+
}
|
|
113
|
+
const previewContent = [];
|
|
114
|
+
expandedSlice.content.descendants((node, pos) => {
|
|
115
|
+
const dom = findDomRefAtPos(sliceFrom + pos, view.domAtPos.bind(view));
|
|
116
|
+
if (dom instanceof HTMLElement) {
|
|
117
|
+
previewContent.push({
|
|
118
|
+
dom,
|
|
119
|
+
nodeSpacing: getNodeSpacingForDragPreview(node),
|
|
120
|
+
nodeType: node.type.name
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
});
|
|
125
|
+
return previewContent.length > 0 ? dragPreview(container, previewContent) : undefined;
|
|
126
|
+
},
|
|
127
|
+
nativeSetDragImage
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
onDragStart: () => {
|
|
131
|
+
var _api$core2;
|
|
132
|
+
if (start === undefined) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// This handle is outside ProseMirror, so it owns the side effects normally started by PM.
|
|
137
|
+
startMeasure(EDITOR_BLOCKS_DRAG_INIT);
|
|
138
|
+
defaultActiveAnchorTracker.reset();
|
|
139
|
+
api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(({
|
|
140
|
+
tr
|
|
141
|
+
}) => {
|
|
142
|
+
var _api$blockControls$sh2, _resolvedMovingNode$n, _api$blockControls2, _api$analytics;
|
|
143
|
+
const resolvedMovingNode = tr.doc.resolve(start);
|
|
144
|
+
const multiSelect = api === null || api === void 0 ? void 0 : (_api$blockControls$sh2 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh2 === void 0 ? void 0 : _api$blockControls$sh2.multiSelectDnD;
|
|
145
|
+
const attributes = multiSelect ? getMultiSelectAnalyticsAttributes(tr, multiSelect.anchor, multiSelect.head) : {
|
|
146
|
+
hasSelectedMultipleNodes: false,
|
|
147
|
+
nodeTypes: (_resolvedMovingNode$n = resolvedMovingNode.nodeAfter) === null || _resolvedMovingNode$n === void 0 ? void 0 : _resolvedMovingNode$n.type.name
|
|
148
|
+
};
|
|
149
|
+
api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.setNodeDragged(getPos, getAnchorName(), nodeType)({
|
|
150
|
+
tr
|
|
151
|
+
});
|
|
152
|
+
tr.setMeta('scrollIntoView', false);
|
|
153
|
+
api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.attachAnalyticsEvent({
|
|
154
|
+
action: ACTION.DRAGGED,
|
|
155
|
+
actionSubject: ACTION_SUBJECT.ELEMENT,
|
|
156
|
+
actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
|
|
157
|
+
attributes: {
|
|
158
|
+
hasSelectedMultipleNodes: attributes.hasSelectedMultipleNodes,
|
|
159
|
+
nodeDepth: resolvedMovingNode.depth,
|
|
160
|
+
nodeTypes: attributes.nodeTypes || ''
|
|
161
|
+
},
|
|
162
|
+
eventType: EVENT_TYPE.UI
|
|
163
|
+
})(tr);
|
|
164
|
+
return tr;
|
|
165
|
+
});
|
|
166
|
+
view.focus();
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}, [api, elementRef, getAnchorName, getPos, nodeType, start, view]);
|
|
170
|
+
};
|