@atlaskit/renderer
Version:
Renderer component
285 lines (282 loc) • 11.9 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import React from 'react';
import { tableBackgroundColorPalette, getDarkModeLCHColor } from '@atlaskit/adf-schema';
import { useThemeObserver } from '@atlaskit/tokens';
import { SortOrder } from '@atlaskit/editor-common/types';
import { hexToEditorBackgroundPaletteRawValue } from '@atlaskit/editor-palette';
import { SortingIcon } from '@atlaskit/editor-common/table';
import { MODE, PLATFORM } from '../../analytics/events';
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
import { RendererCssClassName } from '../../consts';
import { useIntl } from 'react-intl';
import { tableCellMessages } from '../../messages';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
var IgnoreSorting = ['LABEL', 'INPUT'];
var nextStatusOrder = function nextStatusOrder(currentSortOrder) {
switch (currentSortOrder) {
case SortOrder.NO_ORDER:
return SortOrder.ASC;
case SortOrder.ASC:
return SortOrder.DESC;
case SortOrder.DESC:
return SortOrder.NO_ORDER;
}
return SortOrder.NO_ORDER;
};
var getSortOrderLabel = function getSortOrderLabel(intl, currentSortOrder) {
var noneSortingLabel = tableCellMessages.noneSortingLabel,
ascSortingLabel = tableCellMessages.ascSortingLabel,
descSortingLabel = tableCellMessages.descSortingLabel;
switch (currentSortOrder) {
case SortOrder.NO_ORDER:
return intl.formatMessage(noneSortingLabel);
case SortOrder.ASC:
return intl.formatMessage(ascSortingLabel);
case SortOrder.DESC:
return intl.formatMessage(descSortingLabel);
default:
return intl.formatMessage(noneSortingLabel);
}
};
var getDataAttributes = function getDataAttributes(colwidth, background, cellEdgeProps, valign) {
var attrs = {};
if (colwidth) {
attrs['data-colwidth'] = colwidth.join(',');
}
if (expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true)) {
if (cellEdgeProps !== null && cellEdgeProps !== void 0 && cellEdgeProps.reachesTop) {
attrs['data-reaches-top'] = true;
}
if (cellEdgeProps !== null && cellEdgeProps !== void 0 && cellEdgeProps.reachesBottom) {
attrs['data-reaches-bottom'] = true;
}
if (cellEdgeProps !== null && cellEdgeProps !== void 0 && cellEdgeProps.reachesLeft) {
attrs['data-reaches-left'] = true;
}
if (cellEdgeProps !== null && cellEdgeProps !== void 0 && cellEdgeProps.reachesRight) {
attrs['data-reaches-right'] = true;
}
}
/**
* Storing hex code in data-cell-background because
* we want to have DST token (css variable) or
* DST token value (value (hex code) of css variable) in
* inline style to correct render table cell background
* based on selected theme.
* Currently we rely on background color hex code stored in
* inline style.
* Because of that when we copy and paste table, we end up
* having DST token or DST token value in ADF instead of
* original hex code which we map to DST token.
* So, introducing data-cell-background.
* More details at https://product-fabric.atlassian.net/wiki/spaces/EUXQ/pages/3472556903/Tokenising+tableCell+background+colors#Update-toDom-and-parseDom-to-store-and-read-background-color-from-data-cell-background-attribute.4
*/
if (background) {
attrs['data-cell-background'] = background;
}
if (valign && expValEqualsNoExposure('platform_editor_table_menu_updates', 'isEnabled', true)) {
attrs['data-valign'] = valign;
}
return attrs;
};
// Ignored via go/ees005
// eslint-disable-next-line require-unicode-regexp
var cssVariablePattern = /^var\(--.*\)$/;
var getStyle = function getStyle(_ref) {
var background = _ref.background,
colGroupWidth = _ref.colGroupWidth,
offsetTop = _ref.offsetTop,
colorMode = _ref.colorMode,
valign = _ref.valign;
var style = {};
if (background &&
// ignore setting inline styles if ds neutral token is detected
!background.includes('--ds-background-neutral')) {
/**
* The Editor supports users pasting content from external sources with custom table cell backgrounds and having those
* backgrounds persisted.
*
* This feature predates the introduction of dark mode.
*
* Without the inversion logic below, tokenised content (ie. text), can be hard to read when the user loads the page in dark mode.
*
* This introduces inversion of the presentation of the custom background color when the user is in dark mode.
*
* This can be done without additional changes to account for users copying and pasting content inside the Editor, because of
* how we detect table cell background colors copied from external editor sources. Where we load the background color from a
* seperate attribute (data-cell-background), instead of the inline style.
*
* See the following document for more details on this behaviour
* https://hello.atlassian.net/wiki/spaces/CCECO/pages/2892247168/Unsupported+custom+table+cell+background+colors+in+dark+theme+Editor+Job+Story
*/
var tokenColor = hexToEditorBackgroundPaletteRawValue(background);
if (tokenColor) {
style.backgroundColor = tokenColor;
} else if (
/**
* There was previously a bug in dark mode where we would attempt to invert
* a design token in `getDarkModeLCHColor` causing issues.
* If it's a design token we should return it as is.
*/
cssVariablePattern.test(background)) {
style.backgroundColor = background;
} else {
// if we have a custom color, we need to check if we are in dark mode
if (colorMode === 'dark') {
// if we are in dark mode, we need to invert the color
style.backgroundColor = getDarkModeLCHColor(background);
} else {
// if we are in light mode, we can just set the color
style.backgroundColor = background;
}
}
}
if (colGroupWidth) {
style.width = colGroupWidth;
style.minWidth = colGroupWidth;
}
if (offsetTop !== undefined) {
style.top = offsetTop;
}
if (valign && expValEqualsNoExposure('platform_editor_table_menu_updates', 'isEnabled', true)) {
style.verticalAlign = valign;
}
return style;
};
var getWithCellProps = function getWithCellProps(WrapperComponent) {
return function WithCellProps(props) {
var _useThemeObserver = useThemeObserver(),
colorMode = _useThemeObserver.colorMode;
var children = props.children,
className = props.className,
onClick = props.onClick,
colwidth = props.colwidth,
colGroupWidth = props.colGroupWidth,
rowspan = props.rowspan,
colspan = props.colspan,
background = props.background,
offsetTop = props.offsetTop,
ariaSort = props.ariaSort,
reachesTop = props.reachesTop,
reachesBottom = props.reachesBottom,
reachesLeft = props.reachesLeft,
reachesRight = props.reachesRight,
valign = props.valign;
// This is used to set the background color of the cell
// to a dark mode color in mobile dark mode
var colorName = background ? tableBackgroundColorPalette.get(background) : '';
return /*#__PURE__*/React.createElement(WrapperComponent, _extends({
rowSpan: rowspan,
colSpan: colspan
// Note: When content from a renderer is pasted into an editor
// the background color is not taken from the inline style.
// Instead it is taken from the data-cell-background attribute
// (added via getDataAttributes below).
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
,
style: getStyle({
background: background,
colGroupWidth: colGroupWidth,
offsetTop: offsetTop,
colorMode: colorMode,
valign: valign
}),
colorname: colorName,
onClick: onClick
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
,
className: className
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, getDataAttributes(colwidth, background, {
reachesTop: reachesTop,
reachesBottom: reachesBottom,
reachesLeft: reachesLeft,
reachesRight: reachesRight
}, valign), {
"aria-sort": ariaSort
}), children);
};
};
var TH = getWithCellProps('th');
export var withSortableColumn = function withSortableColumn(WrapperComponent) {
return function THWithSortableColumn(props) {
var intl = useIntl();
var allowColumnSorting = props.allowColumnSorting,
onSorting = props.onSorting,
children = props.children,
sortOrdered = props.sortOrdered,
isHeaderRow = props.isHeaderRow;
var sortOrderedClassName = sortOrdered === SortOrder.NO_ORDER ? RendererCssClassName.SORTABLE_COLUMN_NO_ORDER : '';
if (!allowColumnSorting || !isHeaderRow) {
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
return /*#__PURE__*/React.createElement(WrapperComponent, props);
}
return /*#__PURE__*/React.createElement(WrapperComponent
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, _extends({}, props, {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: RendererCssClassName.SORTABLE_COLUMN_WRAPPER,
ariaSort: getSortOrderLabel(intl, sortOrdered)
}), /*#__PURE__*/React.createElement("div", {
className: RendererCssClassName.SORTABLE_COLUMN
}, children, /*#__PURE__*/React.createElement("figure", {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
className: "".concat(RendererCssClassName.SORTABLE_COLUMN_ICON_WRAPPER, " ").concat(sortOrderedClassName)
}, /*#__PURE__*/React.createElement(SortingIcon, {
isSortingAllowed: !!onSorting,
sortOrdered: sortOrdered,
onClick: sort,
onKeyDown: onKeyPress
}))));
function onKeyPress(event) {
var keys = [' ', 'Enter', 'Spacebar'];
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
var _ref2 = event.target,
tagName = _ref2.tagName;
// trigger sorting if space or enter are clicked but not when in an input field (template variables)
if (keys.includes(event.key) && !IgnoreSorting.includes(tagName)) {
event.preventDefault();
sort();
}
}
function sort() {
var fireAnalyticsEvent = props.fireAnalyticsEvent,
onSorting = props.onSorting,
columnIndex = props.columnIndex,
sortOrdered = props.sortOrdered;
if (onSorting && columnIndex != null) {
var sortOrder = nextStatusOrder(sortOrdered);
onSorting(columnIndex, sortOrder);
fireAnalyticsEvent && fireAnalyticsEvent({
action: ACTION.SORT_COLUMN,
actionSubject: ACTION_SUBJECT.TABLE,
attributes: {
platform: PLATFORM.WEB,
mode: MODE.RENDERER,
columnIndex: columnIndex,
sortOrder: sortOrder
},
eventType: EVENT_TYPE.TRACK
});
} else {
fireAnalyticsEvent && fireAnalyticsEvent({
action: ACTION.SORT_COLUMN_NOT_ALLOWED,
actionSubject: ACTION_SUBJECT.TABLE,
attributes: {
platform: PLATFORM.WEB,
mode: MODE.RENDERER
},
eventType: EVENT_TYPE.TRACK
});
}
}
};
};
export var TableHeader = withSortableColumn(TH);
var TD = getWithCellProps('td');
export var TableCell = TD;