@atlaskit/editor-plugin-breakout
Version:
Breakout plugin for @atlaskit/editor-core
197 lines (195 loc) • 9.69 kB
JavaScript
import { akEditorGutterPaddingDynamic, akEditorGutterPadding, akEditorGutterPaddingReduced, akEditorFullPageNarrowBreakout, akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorCalculatedWideLayoutWidth, akEditorMaxLayoutWidth } from '@atlaskit/editor-shared-styles';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { setBreakoutWidth } from '../editor-commands/set-breakout-width';
import { getGuidelines } from './get-guidelines';
import { LOCAL_RESIZE_PROPERTY } from './resizing-mark-view';
import { resizingPluginKey } from './resizing-plugin';
import { generateResizeFrameRatePayloads, generateResizedEventPayload } from './utils/analytics';
import { measureFramerate, reduceResizeFrameRateSamples } from './utils/measure-framerate';
var RESIZE_RATIO = 2;
var SNAP_GAP = 10;
var WIDTHS = {
MIN: akEditorDefaultLayoutWidth,
WIDE: akEditorCalculatedWideLayoutWidth,
FULL: akEditorFullWidthLayoutWidth,
MAX: akEditorMaxLayoutWidth
};
export function getProposedWidth(_ref) {
var _api$width$sharedStat;
var initialWidth = _ref.initialWidth,
location = _ref.location,
api = _ref.api,
source = _ref.source;
var directionMultiplier = source.data.handleSide === 'left' ? -1 : 1;
var diffX = (location.current.input.clientX - location.initial.input.clientX) * RESIZE_RATIO * directionMultiplier;
var width = (api === null || api === void 0 || (_api$width$sharedStat = api.width.sharedState) === null || _api$width$sharedStat === void 0 || (_api$width$sharedStat = _api$width$sharedStat.currentState()) === null || _api$width$sharedStat === void 0 ? void 0 : _api$width$sharedStat.width) || 0;
var padding = width <= akEditorFullPageNarrowBreakout && editorExperiment('platform_editor_preview_panel_responsiveness', true, {
exposure: true
}) ? akEditorGutterPaddingReduced : akEditorGutterPaddingDynamic();
var containerWidth = width - 2 * padding - akEditorGutterPadding;
// the node width may be greater than the container width so we resize using the smaller value
var proposedWidth = Math.min(initialWidth, containerWidth) + diffX;
var snapPoints = [WIDTHS.MIN, WIDTHS.WIDE, Math.min(containerWidth, WIDTHS.FULL)];
if (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) {
snapPoints.push(Math.min(containerWidth, WIDTHS.MAX));
}
for (var _i = 0, _snapPoints = snapPoints; _i < _snapPoints.length; _i++) {
var snapPoint = _snapPoints[_i];
if (snapPoint - SNAP_GAP < proposedWidth && snapPoint + SNAP_GAP > proposedWidth) {
return snapPoint;
}
}
var hardMax = expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true) ? Math.min(containerWidth, WIDTHS.MAX) : Math.min(containerWidth, WIDTHS.FULL);
return Math.max(WIDTHS.MIN, Math.min(proposedWidth, hardMax));
}
export function createResizerCallbacks(_ref2) {
var dom = _ref2.dom,
view = _ref2.view,
mark = _ref2.mark,
api = _ref2.api;
var node = null;
var guidelines = [];
var _measureFramerate = measureFramerate(),
startMeasure = _measureFramerate.startMeasure,
endMeasure = _measureFramerate.endMeasure,
countFrames = _measureFramerate.countFrames;
var getEditorWidth = function getEditorWidth() {
var _api$width;
return api === null || api === void 0 || (_api$width = api.width) === null || _api$width === void 0 ? void 0 : _api$width.sharedState.currentState();
};
return {
onDragStart: function onDragStart() {
startMeasure();
var pos = view.posAtDOM(dom, 0);
node = view.state.doc.nodeAt(pos);
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
var _api$userIntent;
var tr = _ref3.tr;
(_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 || _api$userIntent.commands.setCurrentUserIntent('dragging')({
tr: tr
});
tr.setMeta('is-resizer-resizing', true);
tr.setMeta(resizingPluginKey, {
type: 'UPDATE_BREAKOUT_NODE',
data: {
node: node,
pos: pos,
start: pos,
depth: 0
}
});
return tr;
});
},
onDrag: function onDrag(_ref4) {
var _node, _api$guideline, _api$breakout$sharedS;
var location = _ref4.location,
source = _ref4.source;
countFrames();
var initialWidth = mark.attrs.width;
var newWidth = getProposedWidth({
initialWidth: initialWidth,
location: location,
api: api,
source: source
});
guidelines = getGuidelines(true, newWidth, getEditorWidth, (_node = node) === null || _node === void 0 ? void 0 : _node.type);
api === null || api === void 0 || (_api$guideline = api.guideline) === null || _api$guideline === void 0 || (_api$guideline = _api$guideline.actions) === null || _api$guideline === void 0 || _api$guideline.displayGuideline(view)({
guidelines: guidelines
});
var activeGuideline = guidelines.find(function (guideline) {
return guideline.active && !guideline.key.startsWith('grid');
});
if (activeGuideline) {
api === null || api === void 0 || api.core.actions.execute(function (_ref5) {
var tr = _ref5.tr;
tr.setMeta(resizingPluginKey, {
type: 'UPDATE_ACTIVE_GUIDELINE_KEY',
data: {
activeGuidelineKey: activeGuideline.key
}
});
return tr;
});
}
if (!activeGuideline && api !== null && api !== void 0 && (_api$breakout$sharedS = api.breakout.sharedState.currentState()) !== null && _api$breakout$sharedS !== void 0 && _api$breakout$sharedS.activeGuidelineKey) {
api === null || api === void 0 || api.core.actions.execute(function (_ref6) {
var tr = _ref6.tr;
tr.setMeta(resizingPluginKey, {
type: 'CLEAR_ACTIVE_GUIDELINE_KEY'
});
return tr;
});
}
// dom is used for width calculations
dom.style.setProperty(LOCAL_RESIZE_PROPERTY, "".concat(newWidth, "px"));
},
onDrop: function onDrop(_ref7) {
var _api$guideline2, _api$editorViewMode;
var location = _ref7.location,
source = _ref7.source;
var payloads = [];
var frameRateSamples = endMeasure();
payloads = generateResizeFrameRatePayloads({
docSize: view.state.doc.nodeSize,
frameRateSamples: reduceResizeFrameRateSamples(frameRateSamples),
originalNode: node
});
var isResizedToFullWidth = !!guidelines.find(function (guideline) {
return guideline.key.startsWith('full_width') && guideline.active;
});
var isResizedToMaxWidth = false;
if (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) {
isResizedToMaxWidth = !!guidelines.find(function (guideline) {
return guideline.key.startsWith('max_width') && guideline.active;
});
}
guidelines = getGuidelines(false, 0, getEditorWidth);
api === null || api === void 0 || (_api$guideline2 = api.guideline) === null || _api$guideline2 === void 0 || (_api$guideline2 = _api$guideline2.actions) === null || _api$guideline2 === void 0 || _api$guideline2.displayGuideline(view)({
guidelines: guidelines
});
var pos = view.posAtDOM(dom, 0);
var mode = mark.attrs.mode;
var initialWidth = mark.attrs.width;
var newWidth = isResizedToFullWidth ? WIDTHS.FULL : getProposedWidth({
initialWidth: initialWidth,
location: location,
api: api,
source: source
});
if (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) {
if (isResizedToMaxWidth) {
newWidth = WIDTHS.MAX;
}
}
var isEditMode = (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'edit';
setBreakoutWidth(newWidth, mode, pos, isEditMode)(view.state, view.dispatch);
dom.style.removeProperty(LOCAL_RESIZE_PROPERTY);
if (node) {
var resizedPayload = generateResizedEventPayload({
node: node,
prevWidth: initialWidth,
newWidth: newWidth
});
payloads.push(resizedPayload);
}
api === null || api === void 0 || api.core.actions.execute(function (_ref8) {
var _api$userIntent2;
var tr = _ref8.tr;
(_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 || _api$userIntent2.commands.setCurrentUserIntent('default')({
tr: tr
});
payloads.forEach(function (payload) {
var _api$analytics;
(_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.attachAnalyticsEvent(payload)(tr);
});
tr.setMeta('is-resizer-resizing', false).setMeta('scrollIntoView', false);
tr.setMeta(resizingPluginKey, {
type: 'RESET_STATE'
});
return tr;
});
}
};
}