UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

263 lines (241 loc) • 8.22 kB
/** @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' } }); };