@atlaskit/editor-plugin-breakout
Version:
Breakout plugin for @atlaskit/editor-core
161 lines (160 loc) • 6.17 kB
JavaScript
import React, { useLayoutEffect, useState } from 'react';
import { bind } from 'bind-event-listener';
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
import uuid from 'uuid/v4';
import { breakoutMessages as messages } from '@atlaskit/editor-common/messages';
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';
import { preventUnhandled } from '@atlaskit/pragmatic-drag-and-drop/prevent-unhandled';
import Tooltip from '@atlaskit/tooltip';
const getNodeName = nodeName => {
if (nodeName === 'layoutSection') {
return 'layout';
} else if (nodeName === 'codeBlock' || nodeName === 'expand') {
return nodeName;
} else {
return 'node';
}
};
export const resizeHandleMessage = {
expand: messages.resizeExpand,
codeBlock: messages.resizeCodeBlock,
layout: messages.resizeLayout,
node: messages.resizeElement
};
const RailWithTooltip = ({
rail,
target,
intl
}) => {
const [nodeName, setNodeName] = useState('node');
useLayoutEffect(() => {
const node = target.querySelector('[data-prosemirror-node-name]');
const name = getNodeName(node === null || node === void 0 ? void 0 : node.dataset.prosemirrorNodeName);
setNodeName(name);
}, [target]);
return /*#__PURE__*/React.createElement(Tooltip, {
content: intl.formatMessage(resizeHandleMessage[nodeName]),
position: "mouse"
}, /*#__PURE__*/React.createElement("div", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: "pm-breakout-resize-handle-rail-inside-tooltip",
ref: el => {
if (el && rail.parentNode !== el) {
el.appendChild(rail);
}
}
}));
};
export const createPragmaticResizer = ({
target,
onDragStart,
onDrag,
onDrop,
intl,
nodeViewPortalProviderAPI
}) => {
let state = 'default';
const createHandle = side => {
const handle = document.createElement('div');
handle.contentEditable = 'false';
handle.classList.add('pm-breakout-resize-handle-container');
handle.style.gridColumn = side === 'left' ? '1' : '3';
const rail = document.createElement('div');
rail.classList.add('pm-breakout-resize-handle-rail');
if (side === 'left') {
handle.classList.add('pm-breakout-resize-handle-container--left');
handle.setAttribute('data-testid', 'pragmatic-resizer-handle-left');
} else {
handle.classList.add('pm-breakout-resize-handle-container--right');
handle.setAttribute('data-testid', 'pragmatic-resizer-handle-right');
}
const handleHitBox = document.createElement('div');
handleHitBox.classList.add('pm-breakout-resize-handle-hit-box');
const thumb = document.createElement('div');
thumb.classList.add('pm-breakout-resize-handle-thumb');
thumb.style.pointerEvents = 'none';
rail.appendChild(thumb);
const tooltipContainer = document.createElement('div');
tooltipContainer.classList.add('pm-breakout-resize-handle-rail-wrapper');
handle.appendChild(tooltipContainer);
handle.appendChild(handleHitBox);
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
const key = uuid();
nodeViewPortalProviderAPI.render(() => /*#__PURE__*/React.createElement(RailWithTooltip, {
rail: rail,
target: target,
intl: intl
}), tooltipContainer, key);
return {
handle,
rail,
handleHitBox,
destroyTooltip: () => nodeViewPortalProviderAPI.remove(key)
};
};
const rightHandle = createHandle('right');
const leftHandle = createHandle('left');
const registerHandle = (handleElement, handleSide) => {
return draggable({
element: handleElement,
onGenerateDragPreview: ({
nativeSetDragImage
}) => {
disableNativeDragPreview({
nativeSetDragImage
});
preventUnhandled.start();
},
getInitialData: () => ({
handleSide
}),
onDragStart(args) {
state = 'resizing';
handleElement.classList.add('pm-breakout-resize-handle-container--active');
onDragStart(args);
},
onDrag,
onDrop(args) {
preventUnhandled.stop();
state = 'default';
handleElement.classList.remove('pm-breakout-resize-handle-container--active');
onDrop(args);
}
});
};
const registerEvents = element => {
return [bind(element, {
type: 'mouseenter',
listener: () => {
rightHandle.rail.style.setProperty('opacity', '1');
leftHandle.rail.style.setProperty('opacity', '1');
}
}), bind(element, {
type: 'mouseleave',
listener: () => {
if (state === 'resizing') {
return;
}
rightHandle.rail.style.removeProperty('opacity');
leftHandle.rail.style.removeProperty('opacity');
}
})];
};
const unbindFns = [...registerEvents(target), ...registerEvents(rightHandle.handleHitBox), ...registerEvents(leftHandle.handleHitBox), ...registerEvents(rightHandle.rail), ...registerEvents(leftHandle.rail)];
const handleElement = 'rail';
const destroyFns = [registerHandle(rightHandle[handleElement], 'right'), registerHandle(leftHandle[handleElement], 'left'), rightHandle.destroyTooltip, leftHandle.destroyTooltip];
return {
rightHandle: rightHandle.handle,
leftHandle: leftHandle.handle,
destroy: isChangeToViewMode => {
destroyFns.forEach(destroyFn => destroyFn());
unbindFns.forEach(unbindFn => unbindFn());
if (isChangeToViewMode) {
var _rightHandle$handle$p, _leftHandle$handle$pa;
(_rightHandle$handle$p = rightHandle.handle.parentElement) === null || _rightHandle$handle$p === void 0 ? void 0 : _rightHandle$handle$p.removeChild(rightHandle.handle);
(_leftHandle$handle$pa = leftHandle.handle.parentElement) === null || _leftHandle$handle$pa === void 0 ? void 0 : _leftHandle$handle$pa.removeChild(leftHandle.handle);
}
}
};
};