@atlaskit/editor-plugin-media
Version:
Media plugin for @atlaskit/editor-core
222 lines (221 loc) • 9.35 kB
JavaScript
import { mediaSingleSpec } from '@atlaskit/adf-schema';
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { getAttrsFromNodeMediaSingle } from './toDOMAttrs';
const WRAPPED_LAYOUTS = ['wrap-left', 'wrap-right'];
const ALIGNED_LAYOUTS = ['align-end', 'align-start'];
const LEGACY_LAYOUTS = ['full-width', 'wide'];
const DEFAULT_IMAGE_WIDTH = 250;
const DEFAULT_IMAGE_HEIGHT = 200;
const GUTTER_SIZE = '24px';
const HALF_GUTTER_SIZE = '12px';
export const mediaWidthCSSCalc = ({
mediaSingleDimensionWidth,
layout,
baseWidth,
isPixelWidth,
isExtendedResizeExperience
}) => {
const hasMediaDimensionWidth = typeof mediaSingleDimensionWidth === 'number';
const isMediaWrapped = WRAPPED_LAYOUTS.includes(layout);
const isMediaAligned = ALIGNED_LAYOUTS.includes(layout);
const isMediaLegacyLayout = LEGACY_LAYOUTS.includes(layout);
const shouldUseAlignedLayoutCalc = isMediaAligned && !hasMediaDimensionWidth;
const shouldUseWrappedLayoutCalc = isMediaWrapped && !hasMediaDimensionWidth;
const shouldUseBreakoutWideLogic = layout === 'wide';
const shouldUseBreakoutFullWidthLogic = layout === 'full-width';
const shouldUseProportionalCalc = !isExtendedResizeExperience && !isPixelWidth && hasMediaDimensionWidth && !isMediaLegacyLayout && !isMediaWrapped;
const shouldUseHalfContainerCalc = shouldUseProportionalCalc && isMediaAligned && mediaSingleDimensionWidth >= 100;
const shouldHardCodePixelWidth = isExtendedResizeExperience && isPixelWidth && hasMediaDimensionWidth;
const containerWidthPlusGutter = `(min(100cqw, 100%) + ${GUTTER_SIZE})`;
const fullContainerWidth = 'var(--ak-editor-max-container-width, 100cqw)';
const applyContainerWidthBoundaries = calc => {
// Safe measure to avoid bleeding
return `min(${calc}, ${fullContainerWidth})`;
};
let cssCalc = '';
if (shouldUseAlignedLayoutCalc) {
cssCalc = `min(calc(${containerWidthPlusGutter} * 0.5 - ${GUTTER_SIZE}), ${baseWidth}px)`;
} else if (shouldUseWrappedLayoutCalc) {
cssCalc = `100%`;
} else if (shouldUseHalfContainerCalc) {
cssCalc = `min(min(${baseWidth}px, calc(50cqw - ${HALF_GUTTER_SIZE})), 100%)`;
} else if (shouldUseProportionalCalc) {
cssCalc = `calc(${containerWidthPlusGutter} * var(--ak-editor-media-single--proportion, 1px) - ${GUTTER_SIZE})`;
} else if (shouldHardCodePixelWidth) {
cssCalc = `min(${mediaSingleDimensionWidth}px, ${fullContainerWidth})`;
} else if (shouldUseBreakoutWideLogic) {
if (expValEquals('platform_editor_media_vc_fixes', 'isEnabled', true)) {
cssCalc = `max(var(--ak-editor--line-length), min(var(--ak-editor--breakout-wide-layout-width), var(--ak-editor-max-container-width)))`;
} else {
cssCalc = `max(var(--ak-editor--line-length), min(var(--ak-editor--breakout-wide-layout-width), calc(100cqw - var(--ak-editor--breakout-full-page-guttering-padding))))`;
}
} else if (shouldUseBreakoutFullWidthLogic) {
if (expValEquals('platform_editor_media_vc_fixes', 'isEnabled', true)) {
cssCalc = `max(var(--ak-editor--line-length), min(var(--ak-editor--full-width-layout-width), var(--ak-editor-max-container-width)))`;
} else {
cssCalc = `max(var(--ak-editor--line-length), min(var(--ak-editor--full-width-layout-width), calc(100cqw - var(--ak-editor--breakout-full-page-guttering-padding))))`;
}
} else {
cssCalc = `max(min(${baseWidth}px, min(100cqw, 100%)), ${GUTTER_SIZE})`;
}
return applyContainerWidthBoundaries(cssCalc);
};
export const mediaContentWrapperWidthCSSCalc = ({
isMediaWrapped,
isExternalMedia,
isPixelWidth,
childMediaWidth,
mediaSingleDimensionWidth
}) => {
if (isExternalMedia || !isMediaWrapped) {
return 'unset';
}
const hasMediaDimensionWidth = typeof mediaSingleDimensionWidth === 'number';
if (!hasMediaDimensionWidth) {
return `calc((100% / 2) - ${HALF_GUTTER_SIZE})`;
}
if (isPixelWidth) {
return `min(calc((var(--ak-editor-max-container-width, 100%) / 2) - ${HALF_GUTTER_SIZE}), ${mediaSingleDimensionWidth}px)`;
}
const hasChildMediaWidth = typeof childMediaWidth === 'number';
if (hasChildMediaWidth) {
return `min(calc(100% * (${mediaSingleDimensionWidth} / 100) - ${HALF_GUTTER_SIZE}), ${childMediaWidth}px)`;
}
return `calc(100% * (${mediaSingleDimensionWidth} / 100) - ${HALF_GUTTER_SIZE})`;
};
export const mediaProportionalWidthCSSCalc = ({
isPixelWidth,
isExtendedResizeExperience,
mediaSingleDimensionWidth,
isMediaWrapped
}) => {
const hasMediaWidth = typeof mediaSingleDimensionWidth === 'number';
if (isPixelWidth || isExtendedResizeExperience || !hasMediaWidth) {
return 'unset';
}
if (isMediaWrapped) {
return mediaSingleDimensionWidth >= 50 ? '1' : `${1 - mediaSingleDimensionWidth / 100}`;
}
return `${mediaSingleDimensionWidth / 100}`;
};
export const mediaJustifyContentCSS = ({
layout
}) => {
switch (layout) {
case 'align-end':
case 'wrap-right':
return 'end';
case 'align-start':
case 'wrap-left':
return 'start';
default:
return 'center';
}
};
export const prepareWrapperContentDOM = ({
layout,
dataAttrs,
childMediaWidth,
childMediaHeight,
mediaSingleDimensionWidth,
isPixelWidth,
isExtendedResizeExperience
}) => {
const layoutStyleJustifyContent = mediaJustifyContentCSS({
layout
});
const mediaWidthCalc = mediaWidthCSSCalc({
layout,
mediaSingleDimensionWidth,
baseWidth: childMediaWidth,
isPixelWidth,
isExtendedResizeExperience
});
const paddingBottom = `calc((${childMediaHeight} / ${childMediaWidth}) * 100%)`;
return ['div', {
class: `rich-media-item mediaSingleView-content-wrap image-${layout}`,
style: convertToInlineCss({
display: 'flex',
justifyContent: layoutStyleJustifyContent,
transform: 'unset',
marginLeft: '0'
}),
...dataAttrs
}, ['div', {
style: convertToInlineCss({
borderRadius: "var(--ds-radius-small, 3px)",
width: mediaWidthCalc,
minWidth: mediaWidthCalc,
color: "var(--ds-icon, #292A2E)"
})
}, ['figure', {
class: 'media-single-node',
style: convertToInlineCss({
'--ak-editor-media-padding-bottom': paddingBottom,
margin: '0px'
})
}, ['div', {}, ['div', {
class: 'media-content-wrap'
}, 0]]]]];
};
export const getToDom = allowPixelResizing => node => {
var _mediaSingleAttrs$lay;
const mediaSingleAttrs = node.attrs;
const isPixelWidth = (mediaSingleAttrs === null || mediaSingleAttrs === void 0 ? void 0 : mediaSingleAttrs.widthType) === 'pixel';
const layout = (_mediaSingleAttrs$lay = mediaSingleAttrs === null || mediaSingleAttrs === void 0 ? void 0 : mediaSingleAttrs.layout) !== null && _mediaSingleAttrs$lay !== void 0 ? _mediaSingleAttrs$lay : 'center';
const childNode = node.firstChild;
const isExternalMedia = (childNode === null || childNode === void 0 ? void 0 : childNode.attrs.type) === 'external';
const childMediaWidth = (childNode === null || childNode === void 0 ? void 0 : childNode.attrs.width) || DEFAULT_IMAGE_WIDTH;
const childMediaHeight = (childNode === null || childNode === void 0 ? void 0 : childNode.attrs.height) || DEFAULT_IMAGE_HEIGHT;
const dataAttrs = getAttrsFromNodeMediaSingle(true, node);
const content = prepareWrapperContentDOM({
layout,
dataAttrs,
childMediaWidth,
childMediaHeight,
mediaSingleDimensionWidth: mediaSingleAttrs.width,
isPixelWidth,
isExtendedResizeExperience: allowPixelResizing
});
const isMediaWrapped = WRAPPED_LAYOUTS.includes(layout);
const proportionCalc = mediaProportionalWidthCSSCalc({
isPixelWidth,
isMediaWrapped,
mediaSingleDimensionWidth: mediaSingleAttrs === null || mediaSingleAttrs === void 0 ? void 0 : mediaSingleAttrs.width,
isExtendedResizeExperience: allowPixelResizing
});
const contentWrapperWidth = mediaContentWrapperWidthCSSCalc({
isMediaWrapped,
isExternalMedia,
isPixelWidth,
childMediaWidth,
mediaSingleDimensionWidth: mediaSingleAttrs === null || mediaSingleAttrs === void 0 ? void 0 : mediaSingleAttrs.width
});
return ['div', {
class: 'mediaSingleView-content-wrap',
layout,
'data-media-vc-wrapper': 'true',
style: convertToInlineCss({
'--ak-editor-media-single--proportion': proportionCalc,
'--ak-editor-media-card-display': 'block',
'--ak-editor-media-single--gutter-size': GUTTER_SIZE,
'--ak-editor-media-margin-right': '0',
'--ak-editor-media-card-background-color': "var(--ds-background-neutral, #0515240F)",
marginTop: isMediaWrapped ? HALF_GUTTER_SIZE : "var(--ds-space-300, 24px)",
marginBottom: isMediaWrapped ? HALF_GUTTER_SIZE : "var(--ds-space-300, 24px)",
marginRight: isMediaWrapped ? layout === 'wrap-right' ? 'auto' : HALF_GUTTER_SIZE : 0,
marginLeft: isMediaWrapped ? layout === 'wrap-left' ? 'auto' : HALF_GUTTER_SIZE : 0,
width: contentWrapperWidth
})
}, content];
};
// @nodeSpecException:toDOM patch
export const mediaSingleSpecWithFixedToDOM = mediaSingleOption => {
const mediaSingleNode = mediaSingleSpec(mediaSingleOption);
const toDOM = getToDom(mediaSingleOption.withExtendedWidthTypes);
return {
...mediaSingleNode,
toDOM
};
};