@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
263 lines (241 loc) • 8.22 kB
JavaScript
/** @jsx jsx */
import React from 'react';
import { css, jsx } from '@emotion/react';
import { akEditorDefaultLayoutWidth, akEditorFullPageMaxWidth, akEditorFullWidthLayoutWidth } from '@atlaskit/editor-shared-styles';
import { nonWrappedLayouts } from '../../utils';
import { calcBreakoutWidth, calcWideWidth } from '../../utils/breakout';
function float(layout) {
switch (layout) {
case 'wrap-right':
return 'right';
case 'wrap-left':
return 'left';
default:
return 'none';
}
}
function getWidthIfFullWidthMode(originalWidth, containerWidth, isInsideOfInlineExtension) {
if (isInsideOfInlineExtension) {
return originalWidth > akEditorFullWidthLayoutWidth ? `${Math.min(containerWidth, akEditorFullWidthLayoutWidth)}px` : `${originalWidth}px`;
}
return originalWidth > akEditorFullWidthLayoutWidth ? '100%' : `${originalWidth}px`;
}
function getWidthIfDefaultMode(originalWidth, containerWidth, isInsideOfInlineExtension) {
if (isInsideOfInlineExtension) {
return originalWidth > akEditorFullPageMaxWidth ? `${Math.min(containerWidth, akEditorDefaultLayoutWidth)}px` : `${originalWidth}px`;
}
return originalWidth > akEditorFullPageMaxWidth ? '100%' : `${originalWidth}px`;
}
/**
* Calculates the image width for non-resized images.
*
* If an image has not been resized using the pctWidth attribute,
* then an image in wide or full-width can not be wider than the image's
* original width.
*/
export function calcLegacyWidth(layout, width, containerWidth = 0, fullWidthMode, isResized, isInsideOfInlineExtension) {
switch (layout) {
case 'align-start':
case 'align-end':
case 'wrap-right':
case 'wrap-left':
return width > containerWidth / 2 ? 'calc(50% - 12px)' : `${width}px`;
case 'wide':
return isInsideOfInlineExtension ? calcWideWidth(containerWidth, Infinity, `${containerWidth}px`) : calcWideWidth(containerWidth);
case 'full-width':
return calcBreakoutWidth(layout, containerWidth);
default:
return isResized ? `${width}px` : fullWidthMode ? getWidthIfFullWidthMode(width, containerWidth, isInsideOfInlineExtension) : getWidthIfDefaultMode(width, containerWidth, isInsideOfInlineExtension);
}
}
/**
* Calculates the image width for non-resized images.
*
* If an image has not been resized using the pctWidth attribute,
* then an image in wide or full-width can not be wider than the image's
* original width.
*/
export function calcLegacyWidthForInline(layout, width, containerWidth = 0, fullWidthMode, isResized) {
switch (layout) {
case 'align-start':
case 'align-end':
case 'wrap-right':
case 'wrap-left':
return width > containerWidth / 2 ? 'calc(50% - 12px)' : `${width}px`;
case 'wide':
return calcWideWidth(containerWidth, Infinity, `${containerWidth}px`);
case 'full-width':
return calcBreakoutWidth(layout, containerWidth);
default:
return isResized ? `${width}px` : fullWidthMode ? getWidthIfFullWidthMode(width, containerWidth) : getWidthIfDefaultMode(width, containerWidth);
}
}
/**
* Calculates the image width for previously resized images.
*
* Wide and full-width images are always that size (960px and 100%); there is
* no distinction between max-width and width.
*/
export function calcResizedWidth(layout, width, containerWidth = 0) {
switch (layout) {
case 'wide':
return calcWideWidth(containerWidth);
case 'full-width':
return calcBreakoutWidth(layout, containerWidth);
default:
return `${width}px`;
}
}
function calcMaxWidth(layout, containerWidth) {
switch (layout) {
case 'wide':
return calcWideWidth(containerWidth);
case 'full-width':
return calcBreakoutWidth(layout, containerWidth);
default:
return '100%';
}
}
function calcMargin(layout) {
switch (layout) {
case 'wrap-right':
return '12px auto 12px 12px';
case 'wrap-left':
return '12px 12px 12px auto';
default:
return '24px auto';
}
}
function isImageAligned(layout) {
switch (layout) {
case 'align-end':
return 'margin-right: 0';
case 'align-start':
return 'margin-left: 0';
default:
return '';
}
}
/**
* Can't use `.attrs` to handle highly dynamic styles because we are still
* supporting `styled-components` v1.
*/
export const MediaSingleDimensionHelper = ({
containerWidth = 0,
fullWidthMode,
isResized,
layout,
mediaSingleWidth,
width,
// original media width
isExtendedResizeExperienceOn,
isNestedNode = false,
isInsideOfInlineExtension = false
}) =>
// eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression -- Needs manual remediation
css`
/* For nested rich media items, set max-width to 100% */
tr &,
[data-layout-column] &,
[data-node-type='expand'] &,
[data-panel-type] &,
li & {
max-width: 100%;
}
width: ${isExtendedResizeExperienceOn ? `${mediaSingleWidth || width}px` : mediaSingleWidth ? calcResizedWidth(layout, width || 0, containerWidth) : calcLegacyWidth(layout, width || 0, containerWidth, fullWidthMode, isResized, isInsideOfInlineExtension)};
${layout === 'full-width' &&
/* This causes issues for new experience where we don't strip layout attributes
when copying top-level node and pasting into a table/layout,
because full-width layout will remain, causing node to be edge-to-edge */
!isExtendedResizeExperienceOn && css({
minWidth: '100%'
})}
max-width: ${isExtendedResizeExperienceOn ? `${containerWidth}px` : calcMaxWidth(layout, containerWidth)};
${isExtendedResizeExperienceOn && `&[class*='is-resizing'] {
.new-file-experience-wrapper {
box-shadow: none !important;
}
${!isNestedNode && nonWrappedLayouts.includes(layout) && `margin-left: 50%;
transform: translateX(-50%);`}
}`}
&:not(.is-resizing) {
transition: width 100ms ease-in;
}
float: ${float(layout)};
margin: ${calcMargin(layout)};
&[class*='not-resizing'] {
${isNestedNode ? /* Make nested node appear responsive when resizing table cell */
`max-width: 100%;` : nonWrappedLayouts.includes(layout) && `margin-left: 50%;
transform: translateX(-50%);`}
}
${isImageAligned(layout)};
`;
const RenderFallbackContainer = ({
hasFallbackContainer,
paddingBottom,
height
}) =>
// eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression -- Needs manual remediation
css`
${hasFallbackContainer ? `
&::after {
content: '';
display: block;
${height ? `height: ${height}px;` : paddingBottom ? `padding-bottom: ${paddingBottom};` : ''}
/* Fixes extra padding problem in Firefox */
font-size: 0;
line-height: 0;
}
` : ''}
`;
// eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression -- Needs manual remediation
export const mediaWrapperStyle = props => css`
position: relative;
${RenderFallbackContainer(props)}
/* Editor */
& > figure {
position: ${props.hasFallbackContainer ? 'absolute' : 'relative'};
height: 100%;
width: 100%;
}
& > div {
position: ${props.hasFallbackContainer ? 'absolute' : 'relative'};
height: 100%;
width: 100%;
}
&[data-node-type='embedCard'] > div {
width: 100%;
}
/* Renderer */
[data-node-type='media'] {
position: static !important;
> div {
position: absolute;
height: 100%;
}
}
`;
export const MediaWrapper = ({
children,
...rest
}) => jsx("div", {
css: mediaWrapperStyle(rest)
}, children);
MediaWrapper.displayName = 'WrapperMediaSingle';
/*
There was an issue with a small, intermittent white gap appearing between the images due to a small pixel difference in browser rendering.
The solution implemented below was adapted from: https://stackoverflow.com/a/68885576
It suggests adding an absolute div on top which matches the width and height and setting the border on that div.
*/
export const MediaBorderGapFiller = ({
borderColor
}) => {
return jsx("div", {
style: {
position: 'absolute',
inset: '0px',
border: `0.5px solid ${borderColor}`,
borderRadius: '1px'
}
});
};