@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
303 lines (272 loc) • 12.7 kB
JavaScript
/* eslint-disable @atlaskit/ui-styling-standard/use-compiled -- Pre-existing lint debt surfaced by this mechanical type-import-only PR. */
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
import { css } from '@emotion/react';
import { tableCellContentDomSelector, tableCellSelector, tableHeaderSelector, tablePrefixSelector } from '@atlaskit/adf-schema';
import { akEditorBreakoutPadding, akEditorFullWidthLayoutWidth, akEditorSelectedNodeClassName, akEditorTableNumberColumnWidth, akEditorWideLayoutWidth, overflowShadow } from '@atlaskit/editor-shared-styles';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { getBrowserInfo } from '../../utils/browser';
import { CodeBlockSharedCssClassName } from './code-block';
import { tableCellBackgroundStyleOverride } from './tableCell';
export const tableMarginTop = 24;
export const tableMarginBottom = 16;
export const tableMarginTopWithControl = 14;
export const tableMarginSides = 8;
export const tableCellMinWidth = 48;
export const tableNewColumnMinWidth = 140;
export const tableCellBorderWidth = 1;
export const tableCellPadding = 8;
export const tableResizeHandleWidth = 6;
export const tablePadding = 8;
export const tableControlsSpacing = tableMarginTop + tablePadding - tableCellBorderWidth;
export const TableSharedCssClassName = {
TABLE_CONTAINER: `${tablePrefixSelector}-container`,
TABLE_NODE_WRAPPER: `${tablePrefixSelector}-wrapper`,
TABLE_NODE_WRAPPER_NO_OVERFLOW: `${tablePrefixSelector}-wrapper-no-overflow`,
TABLE_SCROLL_INLINE_SHADOW: `${tablePrefixSelector}-scroll-inline-shadow`,
TABLE_RIGHT_BORDER: `${tablePrefixSelector}-right-border`,
TABLE_LEFT_BORDER: `${tablePrefixSelector}-left-border`,
TABLE_LEFT_SHADOW: `${tablePrefixSelector}-with-left-shadow`,
TABLE_RIGHT_SHADOW: `${tablePrefixSelector}-with-right-shadow`,
TABLE_STICKY_SHADOW: `${tablePrefixSelector}-sticky-shadow`,
TABLE_STICKY_WRAPPER: `${tablePrefixSelector}-sticky-wrapper`,
TABLE_STICKY_SCROLLBAR_CONTAINER: `${tablePrefixSelector}-sticky-scrollbar-container`,
TABLE_STICKY_SENTINEL_TOP: `${tablePrefixSelector}-sticky-sentinel-top`,
TABLE_STICKY_SENTINEL_BOTTOM: `${tablePrefixSelector}-sticky-sentinel-bottom`,
TABLE_STICKY_SCROLLBAR_SENTINEL_TOP: `${tablePrefixSelector}-sticky-scrollbar-sentinel-top`,
TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM: `${tablePrefixSelector}-sticky-scrollbar-sentinel-bottom`,
TABLE_SHADOW_SENTINEL_LEFT: `${tablePrefixSelector}-shadow-sentinel-left`,
TABLE_SHADOW_SENTINEL_RIGHT: `${tablePrefixSelector}-shadow-sentinel-right`,
// eslint-disable-next-line @atlaskit/editor/no-re-export
TABLE_CELL_NODEVIEW_CONTENT_DOM: tableCellContentDomSelector,
// eslint-disable-next-line @atlaskit/editor/no-re-export
TABLE_CELL_WRAPPER: tableCellSelector,
// eslint-disable-next-line @atlaskit/editor/no-re-export
TABLE_HEADER_CELL_WRAPPER: tableHeaderSelector,
TABLE_ROW_CONTROLS_WRAPPER: `${tablePrefixSelector}-row-controls-wrapper`,
TABLE_COLUMN_CONTROLS_DECORATIONS: `${tablePrefixSelector}-column-controls-decoration`,
TABLE_RESIZER_CONTAINER: `${tablePrefixSelector}-resizer-container`,
TABLE_VIEW_CONTENT_WRAP: 'tableView-content-wrap'
};
/* first block node has 0 top margin */
const firstNodeWithNotMarginTop = () => fg('platform_editor_nested_dnd_styles_changes') ?
// eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression
css`
> :nth-child(1 of :not(style, .ProseMirror-gapcursor, .ProseMirror-widget, span)) {
margin-top: 0;
}
` :
// eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression
css`
> :first-child:not(style),
> style:first-child + * {
margin-top: 0;
}
> .ProseMirror-gapcursor:first-child + *,
> style:first-child + .ProseMirror-gapcursor + * {
margin-top: 0;
}
> .ProseMirror-gapcursor:first-child + span + *,
> style:first-child + .ProseMirror-gapcursor + span + * {
margin-top: 0;
}
`;
const tableSharedStyle = () => {
const browser = getBrowserInfo();
// eslint-disable-next-line @atlaskit/design-system/no-css-tagged-template-expression -- Appears safe to auto-fix, but leaving it up to the team to remediate as the readability only gets worse with autofixing
return css`
${tableCellBackgroundStyleOverride()}
.${TableSharedCssClassName.TABLE_CONTAINER} {
position: relative;
margin: 0 auto ${"var(--ds-space-200, 16px)"};
box-sizing: border-box;
/**
* Fix block top alignment inside table cells.
*/
.decisionItemView-content-wrap:first-of-type > div {
margin-top: 0;
}
${expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true) ? `/* Fake side borders are not needed when the rounded overlay owns the outer border. */
.${TableSharedCssClassName.TABLE_RIGHT_BORDER},
.${TableSharedCssClassName.TABLE_LEFT_BORDER} {
display: none;
}
` : `.${TableSharedCssClassName.TABLE_RIGHT_BORDER},
.${TableSharedCssClassName.TABLE_LEFT_BORDER} {
display: block;
width: 1px;
height: calc(100% - ${"var(--ds-space-300, 24px)"});
background: ${"var(--ds-background-accent-gray-subtler, #DDDEE1)"};
position: absolute;
top: ${"var(--ds-space-300, 24px)"};
}
.${TableSharedCssClassName.TABLE_RIGHT_BORDER} {
right: 0;
}
.${TableSharedCssClassName.TABLE_LEFT_BORDER} {
left: 0;
}
.${TableSharedCssClassName.TABLE_LEFT_BORDER}[data-with-numbered-table='true'] {
left: ${akEditorTableNumberColumnWidth - 1}px;
}`}
}
.${TableSharedCssClassName.TABLE_CONTAINER}[data-number-column='true'] {
padding-left: ${akEditorTableNumberColumnWidth - 1}px;
clear: both;
}
.${TableSharedCssClassName.TABLE_RESIZER_CONTAINER} {
will-change: width, margin-left;
}
.${TableSharedCssClassName.TABLE_RESIZER_CONTAINER} table {
will-change: width;
}
.${TableSharedCssClassName.TABLE_NODE_WRAPPER} > table {
margin: ${"var(--ds-space-300, 24px)"} 0 0 0;
}
.${TableSharedCssClassName.TABLE_CONTAINER} > table,
.${TableSharedCssClassName.TABLE_STICKY_WRAPPER} > table {
margin: ${"var(--ds-space-300, 24px)"} ${"var(--ds-space-100, 8px)"} 0 0;
}
/* support panel nested in table */
${fg('platform_editor_bordered_panel_nested_in_table') ? `.${TableSharedCssClassName.TABLE_NODE_WRAPPER} .ak-editor-panel {
border: ${"var(--ds-border-width, 1px)"} solid ${"var(--ds-border, #0B120E24)"};
}` : ''}
/* avoid applying styles to nested tables (possible via extensions) */
.${TableSharedCssClassName.TABLE_CONTAINER} > table,
.${TableSharedCssClassName.TABLE_NODE_WRAPPER} > table,
.${TableSharedCssClassName.TABLE_STICKY_WRAPPER} > table {
border-collapse: collapse;
${expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true) ? `/* Keep a transparent border so the collapsed border model reserves the same 1px slot
on the table edge; the ::after overlay draws the visible rounded border instead. */
border: ${tableCellBorderWidth}px solid transparent;` : `border: ${tableCellBorderWidth}px solid ${"var(--ds-background-accent-gray-subtler, #DDDEE1)"};
border-left-color: transparent;
border-right-color: transparent;`}
table-layout: fixed;
font-size: 1em;
width: 100%;
${expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true) ? `position: relative;
/* Table-width outer-border owner for overflow-safe rounded corners. */
&::after {
content: '';
position: absolute;
inset: 0;
border: ${tableCellBorderWidth}px solid ${"var(--ds-background-accent-gray-subtler, #DDDEE1)"};
border-radius: ${"var(--ds-radius-medium, 6px)"};
pointer-events: none;
z-index: 1;
}` : ''}
&[data-autosize='true'] {
table-layout: auto;
}
& {
* {
box-sizing: border-box;
}
hr {
box-sizing: content-box;
}
tbody {
border-bottom: none;
}
th td {
background-color: ${"var(--ds-background-neutral-subtle, #00000000)"};
}
> tbody > tr > th,
> tbody > tr > td {
min-width: ${tableCellMinWidth}px;
font-weight: ${"var(--ds-font-weight-regular, 400)"};
vertical-align: top;
border: 1px solid ${"var(--ds-background-accent-gray-subtler, #DDDEE1)"};
border-right-width: 0;
border-bottom-width: 0;
padding: ${"var(--ds-space-100, 8px)"};
/* https://stackoverflow.com/questions/7517127/borders-not-shown-in-firefox-with-border-collapse-on-table-position-relative-o */
${browser.gecko || browser.ie || browser.mac && browser.chrome ? 'background-clip: padding-box;' : ''}
${firstNodeWithNotMarginTop()}
th p:not(:first-of-type),
td p:not(:first-of-type) {
margin-top: ${"var(--ds-space-150, 12px)"};
}
}
/* Ensures nested tables are compatible with parent table background color - uses specificity to ensure tables nested by extensions are not affected */
> tbody > tr > td {
background-color: ${"var(--ds-surface, #FFFFFF)"};
}
${expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true) ? `/* Let the wrapper overlay own the outer table perimeter.
data-reaches-* attributes are set by the TableCell node view. */
> tbody > tr > th[data-reaches-top],
> tbody > tr > td[data-reaches-top] {
border-top-color: transparent;
}
> tbody > tr > th[data-reaches-left],
> tbody > tr > td[data-reaches-left] {
border-left-color: transparent;
}
> tbody > tr > td[data-reaches-left]::after {
border-left-color: transparent;
}
> tbody > tr > td[data-reaches-bottom]::after,
> tbody > tr > th[data-reaches-bottom]::after {
border-bottom-color: transparent;
}` : ''}
th {
background-color: ${"var(--ds-background-accent-gray-subtlest, #F0F1F2)"};
text-align: left;
/* only apply this styling to codeblocks in default background headercells */
/* TODO this needs to be overhauled as it relies on unsafe selectors */
${expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? '&:not(.danger)' : '&:not([style]):not(.danger)'} {
.${CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER}:not(.danger) {
background-color: ${"var(--ds-surface-raised, #FFFFFF)"};
:not(.${akEditorSelectedNodeClassName}) {
box-shadow: 0px 0px 0px 1px ${"var(--ds-border, #0B120E24)"};
}
.${CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPER} {
background-image: ${overflowShadow({
leftCoverWidth: "var(--ds-space-300, 24px)"
})};
background-color: ${"var(--ds-background-neutral, #0515240F)"};
}
.${CodeBlockSharedCssClassName.CODEBLOCK_LINE_NUMBER_GUTTER} {
background-color: ${"var(--ds-background-neutral, #0515240F)"};
}
/* this is only relevant to the element taken care of by renderer */
> [data-ds--code--code-block] {
background-image: ${overflowShadow({
leftCoverWidth: "var(--ds-space-300, 24px)"
})};
background-color: ${"var(--ds-background-neutral, #0515240F)"};
/* selector lives inside @atlaskit/code */
--ds--code--line-number-bg-color: ${"var(--ds-background-neutral, #0515240F)"};
}
}
}
}
}
}
${expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true) ? `/* When the number column is enabled, the left visual edge belongs to the number column.
Remove the left border-radius and left border from the table's ::after overlay
so it doesn't double-up or round where the number column already provides that edge. */
.${TableSharedCssClassName.TABLE_CONTAINER}[data-number-column='true'] {
> .${TableSharedCssClassName.TABLE_NODE_WRAPPER} > table::after,
> .${TableSharedCssClassName.TABLE_STICKY_WRAPPER} > table::after {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left-color: transparent;
}
}` : ''}
`;
};
export const calcTableWidth = (layout, containerWidth, addControllerPadding = true) => {
switch (layout) {
case 'full-width':
return containerWidth ? Math.min(containerWidth - (addControllerPadding ? akEditorBreakoutPadding : 0), akEditorFullWidthLayoutWidth) : akEditorFullWidthLayoutWidth;
case 'wide':
if (containerWidth) {
return Math.min(containerWidth - (addControllerPadding ? akEditorBreakoutPadding : 0), akEditorWideLayoutWidth);
}
return akEditorWideLayoutWidth;
default:
return 'inherit';
}
};
export { tableSharedStyle };