@atlaskit/renderer
Version:
Renderer component
705 lines (690 loc) • 33.4 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import React from 'react';
import { useIntl } from 'react-intl';
import { TableSharedCssClassName, tableMarginTop } from '@atlaskit/editor-common/styles';
import { tableMessages } from '@atlaskit/editor-common/messages';
import { WidthConsumer, overflowShadow } from '@atlaskit/editor-common/ui';
import { fg } from '@atlaskit/platform-feature-flags';
import { createCompareNodes, convertProsemirrorTableNodeToArrayOfRows, hasMergedCell, compose } from '@atlaskit/editor-common/utils';
import { SortOrder } from '@atlaskit/editor-common/types';
import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorMaxWidthLayoutWidth } from '@atlaskit/editor-shared-styles';
import { getTableContainerWidth } from '@atlaskit/editor-common/node-width';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { FullPagePadding } from '../../ui/Renderer/style';
import { TableHeader } from './tableCell';
import { withSmartCardStorage } from '../../ui/SmartCardStorage';
import { StickyTable, tableStickyPadding, OverflowParent } from './table/sticky';
import { Table } from './table/table';
import { isCommentAppearance, isFullPageAppearance, isFullWidthAppearance, isFullWidthOrFullPageAppearance, isMaxWidthAppearance } from '../utils/appearance';
import { TableStickyScrollbar } from './TableStickyScrollbar';
import { TableProcessorWithContainerStyles, RefSyncBlockFakeBorders } from './tableNew';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { isTableInContentMode } from '@atlaskit/editor-common/table';
import { isContentModeSupported } from './table/content-mode';
export const isTableResizingEnabled = appearance => isFullWidthOrFullPageAppearance(appearance) || isCommentAppearance(appearance);
export const isStickyScrollbarEnabled = appearance => isFullWidthOrFullPageAppearance(appearance) && editorExperiment('platform_renderer_table_sticky_scrollbar', true, {
exposure: true
});
export const orderChildren = (children, tableNode, smartCardStorage, tableOrderStatus) => {
if (!tableOrderStatus || tableOrderStatus.order === SortOrder.NO_ORDER) {
return children;
}
const {
order,
columnIndex
} = tableOrderStatus;
const compareNodesInOrder = createCompareNodes({
getInlineCardTextFromStore(attrs) {
const {
url
} = attrs;
if (!url) {
return null;
}
return smartCardStorage.get(url) || null;
}
}, order);
const tableArray = convertProsemirrorTableNodeToArrayOfRows(tableNode);
const tableArrayWithChildren = tableArray.map((rowNodes, index) => ({
rowNodes,
rowReact: children[index]
}));
const headerRow = tableArrayWithChildren.shift();
const sortedTable = tableArrayWithChildren.sort((rowA, rowB) => compareNodesInOrder(rowA.rowNodes[columnIndex], rowB.rowNodes[columnIndex]));
if (headerRow) {
sortedTable.unshift(headerRow);
}
return sortedTable.map(elem => elem.rowReact);
};
export const hasRowspan = row => {
let hasRowspan = false;
row.forEach(cell => hasRowspan = hasRowspan || cell.attrs.rowspan > 1);
return hasRowspan;
};
export const getRefTop = refElement => {
return Math.round(refElement.getBoundingClientRect().top);
};
export const shouldHeaderStick = (scrollTop, tableTop, tableBottom, rowHeight) => tableTop <= scrollTop && !(tableBottom - rowHeight <= scrollTop);
export const shouldHeaderPinBottom = (scrollTop, tableBottom, rowHeight) => tableBottom - rowHeight <= scrollTop && !(tableBottom < scrollTop);
export const addSortableColumn = (rows, tableOrderStatus, onSorting
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-explicit-any
) => {
return React.Children.map(rows, (row, index) => {
if (index === 0) {
return /*#__PURE__*/React.cloneElement(React.Children.only(row), {
tableOrderStatus,
onSorting
});
}
return row;
});
};
export const isHeaderRowEnabled = (rows
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => {
if (!rows.length) {
return false;
}
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const {
children
} = rows[0].props;
if (!children.length) {
return false;
}
if (children.length === 1) {
return children[0].type === TableHeader;
}
return children.every(node => node.type === TableHeader);
};
/**
* This TableWrapper component was created to make sure that the aria-label can be
* internationalized without needing to add `intl` to the TableContainer.
*
* <TableWrapper wrapperRef={ref} onScroll={handleScroll} stickyHeaders={config}>
* <Table>...</Table>
* </TableWrapper>
*/
const TableWrapper = ({
children,
wrapperRef,
onScroll,
stickyHeaders,
tabIndex
}) => {
const {
formatMessage
} = useIntl();
const isScrollableRegion = tabIndex !== undefined;
return /*#__PURE__*/React.createElement("div", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: TableSharedCssClassName.TABLE_NODE_WRAPPER,
ref: wrapperRef,
onScroll: stickyHeaders ? onScroll : undefined
// Adding tabIndex here because this is a scrollable container and it needs to be focusable so keyboard users can scroll it.
// eslint-disable-next-line @atlassian/a11y/no-noninteractive-tabindex
,
tabIndex: tabIndex,
role: isScrollableRegion ? 'region' : undefined,
"aria-label": isScrollableRegion ? formatMessage(tableMessages.tableScrollRegion) : undefined
}, children);
};
export const tableCanBeSticky = (node, children
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => {
return isHeaderRowEnabled(children) && node && node.firstChild && !hasRowspan(node.firstChild);
};
/**
*
*/
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/react/no-class-components
export class TableContainer extends React.Component {
constructor(...args) {
super(...args);
_defineProperty(this, "state", {
stickyMode: 'none',
wrapperWidth: 0,
headerRowHeight: 0
});
_defineProperty(this, "tableRef", /*#__PURE__*/React.createRef());
_defineProperty(this, "stickyHeaderRef", /*#__PURE__*/React.createRef());
_defineProperty(this, "stickyScrollbarRef", /*#__PURE__*/React.createRef());
// used for sync scroll + copying wrapper width to sticky header
_defineProperty(this, "stickyWrapperRef", /*#__PURE__*/React.createRef());
_defineProperty(this, "wrapperRef", /*#__PURE__*/React.createRef());
_defineProperty(this, "overflowParent", null);
_defineProperty(this, "resizeObserver", null);
_defineProperty(this, "applyResizerChange", entries => {
let wrapperWidth = this.state.wrapperWidth;
let headerRowHeight = this.state.headerRowHeight;
for (const entry of entries) {
if (entry.target === this.wrapperRef.current) {
wrapperWidth = entry.contentRect.width;
} else if (entry.target === this.stickyHeaderRef.current) {
headerRowHeight = Math.round(entry.contentRect.height);
}
}
if (headerRowHeight !== this.state.headerRowHeight || wrapperWidth !== this.state.wrapperWidth) {
this.setState({
wrapperWidth,
headerRowHeight
});
}
});
_defineProperty(this, "componentWillUnmount", () => {
if (this.overflowParent) {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
this.overflowParent.removeEventListener('scroll', this.onScroll);
}
if (this.nextFrame) {
cancelAnimationFrame(this.nextFrame);
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
if (this.stickyScrollbar) {
this.stickyScrollbar.dispose();
}
});
_defineProperty(this, "getScrollTop", () => {
const {
stickyHeaders
} = this.props;
const offsetTop = stickyHeaders && stickyHeaders.offsetTop || 0;
return (this.overflowParent ? this.overflowParent.top : 0) + offsetTop;
});
_defineProperty(this, "updateSticky", () => {
const tableElem = this.tableRef.current;
const refElem = this.stickyHeaderRef.current;
if (!tableElem || !refElem) {
return;
}
const scrollTop = this.getScrollTop() + tableStickyPadding;
const tableTop = getRefTop(tableElem);
const tableBottom = tableTop + tableElem.clientHeight;
const shouldSticky = shouldHeaderStick(scrollTop, tableTop, tableBottom, refElem.clientHeight);
const shouldPin = shouldHeaderPinBottom(scrollTop, tableBottom, refElem.clientHeight);
let stickyMode = 'none';
if (shouldPin) {
stickyMode = 'pin-bottom';
} else if (shouldSticky) {
stickyMode = 'stick';
}
if (this.state.stickyMode !== stickyMode) {
this.setState({
stickyMode
});
}
this.nextFrame = undefined;
});
_defineProperty(this, "onScroll", () => {
if (!this.nextFrame) {
this.nextFrame = requestAnimationFrame(this.updateSticky);
}
});
_defineProperty(this, "onWrapperScrolled", () => {
if (!this.wrapperRef.current || !this.stickyWrapperRef.current) {
return;
}
this.stickyWrapperRef.current.scrollLeft = this.wrapperRef.current.scrollLeft;
if (this.stickyScrollbarRef.current) {
this.stickyScrollbarRef.current.scrollLeft = this.wrapperRef.current.scrollLeft;
}
});
_defineProperty(this, "grabFirstRowRef", children => {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return React.Children.map(children || false, (child, idx) => {
if (idx === 0 && /*#__PURE__*/React.isValidElement(child)) {
return /*#__PURE__*/React.cloneElement(child, {
innerRef: this.stickyHeaderRef
});
}
return child;
});
});
}
/**
*
* @example
*/
componentDidMount() {
this.resizeObserver = new ResizeObserver(this.applyResizerChange);
if (this.wrapperRef.current) {
this.resizeObserver.observe(this.wrapperRef.current);
}
if (this.stickyHeaderRef.current) {
this.resizeObserver.observe(this.stickyHeaderRef.current);
}
if (this.props.stickyHeaders) {
var _this$props$stickyHea;
this.overflowParent = OverflowParent.fromElement(this.tableRef.current, (_this$props$stickyHea = this.props.stickyHeaders) === null || _this$props$stickyHea === void 0 ? void 0 : _this$props$stickyHea.defaultScrollRootId_DO_NOT_USE);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
this.overflowParent.addEventListener('scroll', this.onScroll);
}
if (this.wrapperRef.current && isStickyScrollbarEnabled(this.props.rendererAppearance)) {
this.stickyScrollbar = new TableStickyScrollbar(this.wrapperRef.current);
}
}
/**
*
* @param prevProps
* @param prevState
* @example
*/
componentDidUpdate(prevProps, prevState) {
// toggling sticky headers visiblity
if (this.props.stickyHeaders && !this.overflowParent) {
var _this$props$stickyHea2;
this.overflowParent = OverflowParent.fromElement(this.tableRef.current, (_this$props$stickyHea2 = this.props.stickyHeaders) === null || _this$props$stickyHea2 === void 0 ? void 0 : _this$props$stickyHea2.defaultScrollRootId_DO_NOT_USE);
} else if (!this.props.stickyHeaders && this.overflowParent) {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
this.overflowParent.removeEventListener('scroll', this.onScroll);
this.overflowParent = null;
}
// offsetTop might have changed, re-position sticky header
if (this.props.stickyHeaders !== prevProps.stickyHeaders) {
this.updateSticky();
}
// sync horizontal scroll in floating div when toggling modes
if (prevState.stickyMode !== this.state.stickyMode) {
this.onWrapperScrolled();
}
}
/**
*
*/
get pinTop() {
if (!this.tableRef.current || !this.stickyHeaderRef.current) {
return;
}
return this.tableRef.current.offsetHeight - this.stickyHeaderRef.current.offsetHeight + tableMarginTop - tableStickyPadding;
}
/**
*
*/
get shouldAddOverflowParentOffsetTop_DO_NOT_USE() {
// IF the StickyHeaderConfig specifies that the default scroll root offsetTop should be added
// AND the StickyHeaderConfig specifies a default scroll root id
// AND the OverflowParent is the corresponding element
// THEN we should add the OverflowParent offset top (RETURN TRUE)
return this.props.stickyHeaders && !!this.props.stickyHeaders.shouldAddDefaultScrollRootOffsetTop_DO_NOT_USE && !!this.props.stickyHeaders.defaultScrollRootId_DO_NOT_USE && this.overflowParent && this.overflowParent.id === this.props.stickyHeaders.defaultScrollRootId_DO_NOT_USE;
}
/**
*
*/
get stickyTop() {
switch (this.state.stickyMode) {
case 'pin-bottom':
return this.pinTop;
case 'stick':
const offsetTop = this.props.stickyHeaders && this.props.stickyHeaders.offsetTop;
if (typeof offsetTop === 'number' && this.shouldAddOverflowParentOffsetTop_DO_NOT_USE) {
const overflowParentOffsetTop = this.overflowParent ? this.overflowParent.top : 0;
return offsetTop + overflowParentOffsetTop;
} else {
return offsetTop;
}
default:
return undefined;
}
}
/**
*
* @example
*/
render() {
var _this$tableRef$curren;
const {
isNumberColumnEnabled,
layout,
renderWidth,
columnWidths,
stickyHeaders,
tableNode,
rendererAppearance,
isInsideOfBlockNode,
isInsideOfTable,
isinsideMultiBodiedExtension,
allowTableAlignment,
allowTableResizing,
isPresentational,
allowFixedColumnWidthOption
} = this.props;
const {
stickyMode
} = this.state;
const lineLengthFixedWidth = akEditorDefaultLayoutWidth;
let left;
let updatedLayout;
// The tableWidth and left offset logic below must stay aligned with the `breakout-ssr.tsx` logic
// Please consider changes below carefully to not negatively impact SSR
// `renderWidth` cannot be depended on during SSR
const isRenderWidthValid = !!renderWidth && renderWidth > 0;
const fullPageRendererWidthCSS = editorExperiment('platform_editor_preview_panel_responsiveness', true, {
exposure: true
}) ? 'calc(100cqw - var(--ak-renderer--full-page-gutter) * 2)' : `100cqw - ${FullPagePadding}px * 2`;
const renderWidthCSS = rendererAppearance === 'full-page' ? fullPageRendererWidthCSS : `100cqw`;
const calcDefaultLayoutWidthByAppearance = (rendererAppearance, tableNode) => {
if (rendererAppearance === 'full-width' && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
return [isRenderWidthValid ? Math.min(akEditorFullWidthLayoutWidth, renderWidth) : akEditorFullWidthLayoutWidth, `min(${akEditorFullWidthLayoutWidth}px, ${renderWidthCSS})`];
} else if (rendererAppearance === 'max' && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
return [isRenderWidthValid ? Math.min(akEditorMaxWidthLayoutWidth, renderWidth) : akEditorMaxWidthLayoutWidth, `min(${akEditorMaxWidthLayoutWidth}px, ${renderWidthCSS})`];
} else if (rendererAppearance === 'comment' && allowTableResizing && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
const tableContainerWidth = getTableContainerWidth(tableNode);
return [isRenderWidthValid ? renderWidth : tableContainerWidth, renderWidthCSS];
} else {
// custom width, or width mapped to breakpoint
const tableContainerWidth = getTableContainerWidth(tableNode);
return [isRenderWidthValid ? Math.min(tableContainerWidth, renderWidth) : tableContainerWidth, `min(${tableContainerWidth}px, ${renderWidthCSS})`];
}
};
const [tableWidth, tableWidthCSS] = calcDefaultLayoutWidthByAppearance(rendererAppearance, tableNode);
// Logic for table alignment in renderer
const isTableAlignStart = tableNode && tableNode.attrs && tableNode.attrs.layout === 'align-start' && allowTableAlignment;
const fullWidthLineLength = isRenderWidthValid ? Math.min(akEditorFullWidthLayoutWidth, renderWidth) : akEditorFullWidthLayoutWidth;
const fullWidthLineLengthCSS = `min(${akEditorFullWidthLayoutWidth}px, ${renderWidthCSS})`;
const maxWidthLineLength = isRenderWidthValid ? Math.min(akEditorMaxWidthLayoutWidth, renderWidth) : akEditorMaxWidthLayoutWidth;
const maxWidthLineLengthCSS = `min(${akEditorMaxWidthLayoutWidth}px, ${renderWidthCSS})`;
const commentLineLength = isRenderWidthValid ? renderWidth : lineLengthFixedWidth;
const isCommentAppearanceAndTableAlignmentEnabled = isCommentAppearance(rendererAppearance) && allowTableAlignment;
const lineLength = isFullWidthAppearance(rendererAppearance) ? fullWidthLineLength : isMaxWidthAppearance(rendererAppearance) && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) ? maxWidthLineLength : isCommentAppearanceAndTableAlignmentEnabled ? commentLineLength : lineLengthFixedWidth;
const lineLengthCSS = isFullWidthAppearance(rendererAppearance) ? fullWidthLineLengthCSS : isMaxWidthAppearance(rendererAppearance) && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) ? maxWidthLineLengthCSS : isCommentAppearanceAndTableAlignmentEnabled ? renderWidthCSS : `${lineLengthFixedWidth}px`;
// Setting fixTableSSRResizing to false while FG logic is true in tableNew
const fixTableSSRResizing = false;
const tableWidthNew = fixTableSSRResizing ? getTableContainerWidth(tableNode) : tableWidth;
const shouldCalculateLeftForAlignment = !isInsideOfBlockNode && !isInsideOfTable && isTableAlignStart && (isFullPageAppearance(rendererAppearance) && tableWidthNew <= lineLengthFixedWidth || isFullWidthAppearance(rendererAppearance) || (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) && isMaxWidthAppearance(rendererAppearance) || isCommentAppearanceAndTableAlignmentEnabled);
let leftCSS;
if (shouldCalculateLeftForAlignment) {
left = (tableWidth - lineLength) / 2;
leftCSS = `(${tableWidthCSS} - ${lineLengthCSS}) / 2`;
}
if (fixTableSSRResizing) {
if (!shouldCalculateLeftForAlignment && isFullPageAppearance(rendererAppearance)) {
// Note tableWidthCSS here is the renderer width
// When the screen is super wide we want table to break out.
// However if screen is smaller than 760px. We want table align to left.
leftCSS = `min(0px, ${lineLengthCSS} - ${tableWidthCSS}) / 2`;
}
} else {
if (!shouldCalculateLeftForAlignment && isFullPageAppearance(rendererAppearance) && tableWidthNew > lineLengthFixedWidth) {
left = lineLengthFixedWidth / 2 - tableWidth / 2;
}
}
const children = React.Children.toArray(this.props.children);
// Historically, tables in the full-width renderer had their layout set to 'default' which is deceiving.
// This check caters for those tables and helps with SSR logic
const isFullWidth = !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width) && rendererAppearance === 'full-width' && layout !== 'full-width';
if (isFullWidth) {
updatedLayout = 'full-width';
// if table has width explicity set, ensure SSR is handled
} else if (tableNode !== null && tableNode !== void 0 && tableNode.attrs.width) {
updatedLayout = 'custom';
} else {
updatedLayout = layout;
}
let finalTableContainerWidth = allowTableResizing ? tableWidthNew : 'inherit';
// We can only use CSS to determine the width when we have a known width in container.
// When appearance is full-page, full-width or comment we use CSS based width calculation.
// Otherwise it's fixed table width (customized width) or inherit.
if ((rendererAppearance === 'full-page' || rendererAppearance === 'full-width' || rendererAppearance === 'max') && fixTableSSRResizing) {
finalTableContainerWidth = allowTableResizing ? `calc(${tableWidthCSS})` : 'inherit';
}
if (rendererAppearance === 'comment' && allowTableResizing && !allowTableAlignment) {
// If table alignment is disabled and table width is akEditorDefaultLayoutWidth = 760,
// it is most likely a table created before "Support Table in Comments" FF was enabled
// and we would see a bug ED-24795. A table created before "Support Table in Comments",
// should inhirit the width of the renderer container.
// !NOTE: it a table resized to 760 is copied from 'full-page' editor and pasted in comment editor
// where (allowTableResizing && !allowTableAlignment), the table will loose 760px width.
finalTableContainerWidth = tableNode !== null && tableNode !== void 0 && tableNode.attrs.width && (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.width) !== akEditorDefaultLayoutWidth ? fixTableSSRResizing ? `calc(${tableWidthCSS})` : tableWidth : 'inherit';
}
if (rendererAppearance === 'comment' && allowTableResizing && allowTableAlignment) {
// If table alignment is enabled and layout is not 'align-start' or 'center', we are loading a table that was
// created before "Support Table in Comments" FF was enabled. So the table should have the same width as renderer container
// instead of 760 that was set on tableNode when the table had been published.
finalTableContainerWidth = ((tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout) === 'align-start' || (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout) === 'center') && tableNode !== null && tableNode !== void 0 && tableNode.attrs.width ? fixTableSSRResizing ? `calc(${tableWidthCSS})` : tableWidth : 'inherit';
}
const isContentModeTable = isTableInContentMode({
tableNode,
isSupported: isContentModeSupported({
allowTableResizing,
rendererAppearance
}),
isTableNested: isInsideOfBlockNode || isInsideOfTable
}) && expValEquals('platform_editor_table_fit_to_content_auto_convert', 'isEnabled', true);
let style;
if (fixTableSSRResizing) {
style = {
...(isContentModeTable && {
'--renderer-table-max-width': renderWidthCSS
}),
width: finalTableContainerWidth,
left: leftCSS ? `calc(${leftCSS})` : undefined,
marginLeft: shouldCalculateLeftForAlignment && leftCSS !== undefined ? `calc(-1 * (${leftCSS}))` : undefined
};
} else {
style = {
...(isContentModeTable && {
'--renderer-table-max-width': `${renderWidth}px`
}),
width: finalTableContainerWidth,
left: left,
marginLeft: shouldCalculateLeftForAlignment && left !== undefined ? -left : undefined
};
}
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: `${TableSharedCssClassName.TABLE_CONTAINER} ${this.props.shadowClassNames || ''}`,
"data-layout": updatedLayout,
ref: this.props.handleRef
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
,
style: style
}, isStickyScrollbarEnabled(this.props.rendererAppearance) && /*#__PURE__*/React.createElement("div", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: TableSharedCssClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP,
"data-testid": "sticky-scrollbar-sentinel-top"
}), stickyHeaders && tableCanBeSticky(tableNode, children) && /*#__PURE__*/React.createElement(StickyTable, {
isNumberColumnEnabled: isNumberColumnEnabled,
tableWidth: tableWidth,
layout: layout,
renderWidth: renderWidth,
handleRef: this.props.handleRef,
shadowClassNames: this.props.shadowClassNames,
top: this.stickyTop,
mode: stickyMode,
innerRef: this.stickyWrapperRef,
wrapperWidth: this.state.wrapperWidth,
columnWidths: columnWidths,
rowHeight: this.state.headerRowHeight,
tableNode: tableNode,
rendererAppearance: rendererAppearance,
allowTableResizing: allowTableResizing,
allowFixedColumnWidthOption: allowFixedColumnWidthOption
}, [children && children[0]]), /*#__PURE__*/React.createElement(TableWrapper, {
wrapperRef: this.wrapperRef,
onScroll: this.props.stickyHeaders ? this.onWrapperScrolled : undefined,
stickyHeaders: stickyHeaders,
tabIndex: this.props.tabIndex
}, /*#__PURE__*/React.createElement(Table, {
innerRef: this.tableRef,
columnWidths: columnWidths,
layout: layout,
isNumberColumnEnabled: isNumberColumnEnabled,
renderWidth: renderWidth,
tableNode: tableNode,
rendererAppearance: rendererAppearance,
isInsideOfBlockNode: isInsideOfBlockNode,
isInsideOfTable: isInsideOfTable,
isinsideMultiBodiedExtension: isinsideMultiBodiedExtension,
allowTableResizing: allowTableResizing,
isPresentational: isPresentational,
allowFixedColumnWidthOption: allowFixedColumnWidthOption
}, this.grabFirstRowRef(children))), isStickyScrollbarEnabled(this.props.rendererAppearance) && /*#__PURE__*/React.createElement("div", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: TableSharedCssClassName.TABLE_STICKY_SCROLLBAR_CONTAINER,
ref: this.stickyScrollbarRef,
style: {
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
height: "var(--ds-space-250, 20px)",
// MAX_BROWSER_SCROLLBAR_HEIGHT
// Follow editor to hide by default so it does not show empty gap in SSR
// https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/master/platform/packages/editor/editor-plugin-table/src/nodeviews/TableComponent.tsx#957
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
display: fixTableSSRResizing ? 'none' : 'block',
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
width: '100%'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: (_this$tableRef$curren = this.tableRef.current) === null || _this$tableRef$curren === void 0 ? void 0 : _this$tableRef$curren.clientWidth,
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
height: '100%'
}
})), isStickyScrollbarEnabled(this.props.rendererAppearance) && /*#__PURE__*/React.createElement("div", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: TableSharedCssClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_BOTTOM,
"data-testid": "sticky-scrollbar-sentinel-bottom"
}), /*#__PURE__*/React.createElement(RefSyncBlockFakeBorders, {
isNumberColumnEnabled: isNumberColumnEnabled
})));
}
}
/**
*
*/
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/react/no-class-components
export class TableProcessor extends React.Component {
constructor(...args) {
super(...args);
_defineProperty(this, "state", {
tableOrderStatus: undefined
});
// adds sortable + re-orders children
_defineProperty(this, "addSortableColumn", childrenArray => {
const {
tableNode,
allowColumnSorting,
smartCardStorage
} = this.props;
const {
tableOrderStatus
} = this.state;
if (allowColumnSorting && isHeaderRowEnabled(childrenArray) && tableNode && !hasMergedCell(tableNode)) {
return addSortableColumn(orderChildren(childrenArray, tableNode, smartCardStorage, tableOrderStatus), tableOrderStatus, this.changeSortOrder);
}
return childrenArray;
});
_defineProperty(this, "changeSortOrder", (columnIndex, sortOrder) => {
this.setState({
tableOrderStatus: {
columnIndex,
order: sortOrder
}
});
});
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_defineProperty(this, "addNumberColumnIndexes", rows => {
const {
isNumberColumnEnabled
} = this.props;
const headerRowEnabled = isHeaderRowEnabled(rows);
return React.Children.map(rows, (row, index) => {
return /*#__PURE__*/React.cloneElement(React.Children.only(row), {
isNumberColumnEnabled,
index: headerRowEnabled ? index === 0 ? '' : index : index + 1
});
});
});
}
/**
*
* @example
*/
render() {
const {
children
} = this.props;
if (!children) {
return null;
}
const childrenArray = React.Children.toArray(children);
const orderedChildren = compose(this.addNumberColumnIndexes, this.addSortableColumn
// @ts-expect-error TS2345: Argument of type '(ReactChild | ReactFragment | ReactPortal)[]' is not assignable to parameter of type 'ReactElement<any, string | JSXElementConstructor<any>>[]'
)(childrenArray);
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
return /*#__PURE__*/React.createElement(TableContainer, this.props, orderedChildren);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const TableWithShadowsAndContainerStyles = overflowShadow(TableProcessorWithContainerStyles, {
/**
* The :scope is in reference to table container and we are selecting only
* direct children that match the table node wrapper selector, not their
* descendants.
*/
overflowSelector: `:scope > .${TableSharedCssClassName.TABLE_NODE_WRAPPER}`,
useShadowObserver: true
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const TableWithShadows = overflowShadow(TableProcessor, {
/**
* The :scope is in reference to table container and we are selecting only
* direct children that match the table node wrapper selector, not their
* descendants.
*/
overflowSelector: `:scope > .${TableSharedCssClassName.TABLE_NODE_WRAPPER}`,
useShadowObserver: true
});
const TableWithWidth = props => {
if (fg('platform-ssr-table-resize')) {
var _props$columnWidths;
const colWidthsSum =
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
((_props$columnWidths = props.columnWidths) === null || _props$columnWidths === void 0 ? void 0 : _props$columnWidths.reduce((total, val) => total + val, 0)) || 0;
if (colWidthsSum || props.allowTableResizing) {
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
return /*#__PURE__*/React.createElement(TableWithShadowsAndContainerStyles, props);
}
return /*#__PURE__*/React.createElement(TableProcessorWithContainerStyles
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, props);
} else {
return /*#__PURE__*/React.createElement(WidthConsumer, null, ({
width
}) => {
var _props$columnWidths2;
const renderWidth = props.rendererAppearance === 'full-page' ? width - FullPagePadding * 2 : width;
const colWidthsSum =
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
((_props$columnWidths2 = props.columnWidths) === null || _props$columnWidths2 === void 0 ? void 0 : _props$columnWidths2.reduce((total, val) => total + val, 0)) || 0;
if (colWidthsSum || props.allowTableResizing) {
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
return /*#__PURE__*/React.createElement(TableWithShadows, _extends({
renderWidth: renderWidth
}, props));
}
// there should not be a case when colWidthsSum is 0 and table is in overflow state - so no need to render shadows in this case
return /*#__PURE__*/React.createElement(TableProcessor, _extends({
renderWidth: renderWidth
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, props));
});
}
};
const _default_1 = withSmartCardStorage(TableWithWidth);
export default _default_1;