@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
129 lines (127 loc) • 4.83 kB
JavaScript
import { useCallback, useMemo, useState } from 'react';
import { akEditorCalculatedWideLayoutWidth, akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorGutterPadding, akEditorGutterPaddingDynamic, akEditorGutterPaddingReduced, akEditorFullPageNarrowBreakout, breakoutWideScaleRatio } from '@atlaskit/editor-shared-styles';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
export const SNAP_GAP = 8;
const GUIDELINE_KEYS = {
lineLength: 'grid',
wide: 'wide',
fullWidth: 'full_width'
};
const CURRENT_LAYOUT_KEYS = {
lineLength: 'center',
wide: 'wide',
fullWidth: 'full-width'
};
const roundToNearest = (value, interval = 0.5) => Math.round(value / interval) * interval;
export function useBreakoutGuidelines(getEditorWidth, isResizing, dynamicFullWidthGuidelineOffset = 0) {
const widthState = getEditorWidth();
const {
lineLength,
wide,
fullWidth
} = useMemo(() => {
if (!isResizing) {
return {};
}
const {
width,
lineLength
} = widthState || {};
const wideCalWithRatio = lineLength ? Math.round(lineLength * breakoutWideScaleRatio) : undefined;
// When page is full width, lineLength from widthState can be much wider than 760.
// But the lineLength variable here is being used like a const 760.
// when the page is full width, the calculation of wide is wrong.
// Actuall the wide is the wide breakout point, which is
const wide = editorExperiment('single_column_layouts', true) ? akEditorCalculatedWideLayoutWidth : wideCalWithRatio;
const padding = width && width <= akEditorFullPageNarrowBreakout && editorExperiment('platform_editor_preview_panel_responsiveness', true, {
exposure: true
}) ? akEditorGutterPaddingReduced : akEditorGutterPaddingDynamic();
const layoutCalculatedWidth = width ? width - (padding + dynamicFullWidthGuidelineOffset) * 2 : undefined;
const fullWidth = width && layoutCalculatedWidth ? Math.min(layoutCalculatedWidth, akEditorFullWidthLayoutWidth) : undefined;
return {
wide,
fullWidth,
// When page is full width, lineLength from widthState can be much wider than 760.
// But the lineLength variable here is being used like a const 760.
lineLength: editorExperiment('single_column_layouts', true) ? akEditorDefaultLayoutWidth : lineLength
};
}, [widthState, isResizing, dynamicFullWidthGuidelineOffset]);
// calculate snapping width
const defaultSnappingWidths = useMemo(() => {
if (!fullWidth || !wide || !lineLength || fullWidth <= (editorExperiment('single_column_layouts', true) ? akEditorDefaultLayoutWidth : lineLength)) {
return null;
}
if (fullWidth - wide > SNAP_GAP) {
return {
lineLength,
wide,
fullWidth
};
}
if (fullWidth <= wide && fullWidth - lineLength > SNAP_GAP) {
return {
lineLength,
fullWidth
};
}
return null;
}, [fullWidth, lineLength, wide]);
const snaps = useMemo(() => {
if (!isResizing || !defaultSnappingWidths) {
return null;
}
return {
x: Object.values(defaultSnappingWidths)
};
}, [defaultSnappingWidths, isResizing]);
// calculate guidelines, and calculate which lines are active
const [currentLayout, setCurrentLayout] = useState(null);
const guidelines = useMemo(() => {
const guidelines = [];
if (!defaultSnappingWidths) {
return guidelines;
}
Object.entries(defaultSnappingWidths).map(([key, value]) => {
if (value) {
guidelines.push({
key: `${GUIDELINE_KEYS[key]}_left`,
position: {
x: -roundToNearest(value / 2)
},
active: currentLayout === CURRENT_LAYOUT_KEYS[key]
});
guidelines.push({
key: `${GUIDELINE_KEYS[key]}_right`,
position: {
x: roundToNearest(value / 2)
},
active: currentLayout === CURRENT_LAYOUT_KEYS[key]
});
}
});
return guidelines;
}, [defaultSnappingWidths, currentLayout]);
const setCurrentWidth = useCallback(newWidth => {
if (typeof newWidth !== 'number') {
setCurrentLayout(null);
return;
}
if (lineLength && Math.abs(newWidth - lineLength) < SNAP_GAP / 2) {
setCurrentLayout('center');
} else if (wide && Math.abs(newWidth - wide) < SNAP_GAP / 2) {
setCurrentLayout('wide');
} else if (fullWidth && (
// we only allow snap from one side, so we don't use Math.abs here
fullWidth + akEditorGutterPadding - newWidth < SNAP_GAP / 2 || newWidth >= fullWidth)) {
setCurrentLayout('full-width');
} else {
setCurrentLayout(null);
}
}, [lineLength, wide, fullWidth]);
return {
snaps,
currentLayout,
guidelines,
setCurrentWidth
};
}