UNPKG

@atlaskit/adf-schema

Version:

Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs

334 lines (319 loc) 14.4 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import { hexToEditorBackgroundPaletteRawValue } from '../../utils/editor-palette'; import { B100, B50, B75, G200, G50, G75, hexToRgba, isHex, isRgb, N0, N20, N60, N800, P100, P50, P75, R100, R50, R75, rgbToHex, T100, T50, T75, Y200, Y50, Y75 } from '../../utils/colors'; import { uuid } from '../../utils/uuid'; import { getDarkModeLCHColor } from '../../utils/lch-color-inversion'; import { table as tableFactory, tableWithNestedTable as tableWithNestedTableFactory, tableRow as tableRowFactory, tableRowWithNestedTable as tableRowWithNestedTableFactory, tableHeader as tableHeaderFactory, tableHeaderWithNestedTable as tableHeaderWithNestedTableFactory, tableCell as tableCellFactory, tableCellWithNestedTable as tableCellWithNestedTableFactory } from '../../next-schema/generated/nodeTypes'; export var tablePrefixSelector = 'pm-table'; export var tableCellSelector = "".concat(tablePrefixSelector, "-cell-content-wrap"); export var tableHeaderSelector = "".concat(tablePrefixSelector, "-header-content-wrap"); export var tableCellContentWrapperSelector = "".concat(tablePrefixSelector, "-cell-nodeview-wrapper"); export var tableCellContentDomSelector = "".concat(tablePrefixSelector, "-cell-nodeview-content-dom"); var DEFAULT_TABLE_HEADER_CELL_BACKGROUND = N20.toLocaleLowerCase(); export var getCellAttrs = function getCellAttrs(dom) { var defaultValues = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var widthAttr = dom.getAttribute('data-colwidth'); var width = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(',').map(function (str) { return Number(str); }) : null; var colspan = Number(dom.getAttribute('colspan') || 1); var backgroundColor = dom.style.backgroundColor; /** * We have pivoted to store background color information in * data-cell-background. * We will have original hex code (which we map to DST token) * stored in data-cell-background, use that. * 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 */ var dataCellBackground = dom.getAttribute('data-cell-background'); var dataCellBackgroundHexCode = dataCellBackground && isHex(dataCellBackground) ? dataCellBackground : undefined; // ignore setting background attr if ds neutral token is detected if (backgroundColor.includes('--ds-background-neutral')) { backgroundColor = ''; } else { if (backgroundColor && isRgb(backgroundColor)) { var result = rgbToHex(backgroundColor); if (result !== null) { backgroundColor = result; } } } var backgroundHexCode = dataCellBackgroundHexCode || (backgroundColor && backgroundColor !== defaultValues['background'] ? backgroundColor : null); return { colspan: colspan, rowspan: Number(dom.getAttribute('rowspan') || 1), colwidth: width && width.length === colspan ? width : null, background: backgroundHexCode }; }; // these are for test only var testGlobalTheme; export var setGlobalTheme = function setGlobalTheme(theme) { testGlobalTheme = theme; }; // This is a minimal duplication of the method from @atlaskit/tokens // to minimise the number of dependencies required as these changes are expected // to be patched onto CR8. var getGlobalTheme = function getGlobalTheme() { // This should only be hit during tests. // // At time of writing Jest mocks are not working in this repository. if (testGlobalTheme) { return { colorMode: testGlobalTheme }; } var element = document.documentElement; var colorMode = element.getAttribute('data-color-mode') || ''; return { colorMode: colorMode }; }; var cssVariablePattern = /^var\(--.*\)$/; /** * gets cell dom attributes based on node attributes * @returns CellDomAttrs */ export var getCellDomAttrs = function getCellDomAttrs(node) { var attrs = {}; var nodeType = node.type.name; if (node.attrs.colspan !== 1) { attrs.colspan = node.attrs.colspan; } if (node.attrs.rowspan !== 1) { attrs.rowspan = node.attrs.rowspan; } if (node.attrs.colwidth) { attrs['data-colwidth'] = node.attrs.colwidth.join(','); } if (node.attrs.background) { var background = node.attrs.background; // to ensure that we don't overwrite product's style: // - it clears background color for <th> if its set to gray // - it clears background color for <td> if its set to white // - it clears background color for <th> if ds neutral token is detected var ignored = nodeType === 'tableHeader' && background === tableBackgroundColorNames.get('light gray') || nodeType === 'tableCell' && background === tableBackgroundColorNames.get('white') || nodeType === 'tableHeader' && background.includes('--ds-background-neutral'); if (ignored) { attrs.style = ''; } else { var color = isRgb(background) && rgbToHex(background) ? rgbToHex(background) : background; /** * 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(color); if (tokenColor) { attrs.style = "background-color: ".concat(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(color)) { attrs.style = "background-color: ".concat(color, ";"); } else { // if we have a custom color, we need to check if we are in dark mode if (getGlobalTheme().colorMode === 'dark') { // if we have a custom color, we need to check if we are in dark mode attrs.style = "background-color: ".concat(getDarkModeLCHColor(color), ";"); } else { // if we are in light mode, we can just set the color attrs.style = "background-color: ".concat(background, ";"); } } /** * 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 (color) { attrs['data-cell-background'] = color; } attrs.colorname = tableBackgroundColorPalette.get(color); } } if (nodeType === 'tableHeader') { attrs.class = tableHeaderSelector; } else { attrs.class = tableCellSelector; } return attrs; }; export var tableBackgroundColorPalette = new Map(); export var tableBackgroundBorderColor = hexToRgba(N800, 0.12) || N0; export var tableBackgroundColorNames = new Map(); [[N0, 'White'], [B50, 'Light blue'], [T50, 'Light teal'], [G50, 'Light green'], [Y50, 'Light yellow'], [R50, 'Light red'], [P50, 'Light purple'], [N20, 'Light gray'], [B75, 'Blue'], [T75, 'Teal'], [G75, 'Green'], [Y75, 'Yellow'], [R75, 'Red'], [P75, 'Purple'], [N60, 'Gray'], [B100, 'Dark blue'], [T100, 'Dark teal'], [G200, 'Dark green'], [Y200, 'Dark yellow'], [R100, 'Dark red'], [P100, 'Dark purple']].forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), colorValue = _ref2[0], colorName = _ref2[1]; tableBackgroundColorPalette.set(colorValue.toLowerCase(), colorName); tableBackgroundColorNames.set(colorName.toLowerCase(), colorValue.toLowerCase()); }); /** * @name table_node */ /** * @name table_row_node */ /** * @name table_cell_content * @minItems 1 * @allowUnsupportedBlock true */ /** * @name table_cell_node */ /** * @name table_header_node */ // table nodes with nested tables support var tableNodeSpecOptions = { parseDOM: [{ tag: 'table', getAttrs: function getAttrs(node) { var _dom$parentElement; var dom = node; var breakoutWrapper = (_dom$parentElement = dom.parentElement) === null || _dom$parentElement === void 0 ? void 0 : _dom$parentElement.parentElement; return { isNumberColumnEnabled: dom.getAttribute('data-number-column') === 'true', layout: // copying from editor dom.getAttribute('data-layout') || (// copying from renderer breakoutWrapper === null || breakoutWrapper === void 0 ? void 0 : breakoutWrapper.getAttribute('data-layout')) || 'default', __autoSize: dom.getAttribute('data-autosize') === 'true', localId: dom.getAttribute('data-table-local-id') || uuid.generate(), width: Number(dom.getAttribute('data-table-width')) || null, displayMode: dom.getAttribute('data-table-display-mode') || null }; } }], toDOM: function toDOM(node) { var attrs = { 'data-number-column': node.attrs.isNumberColumnEnabled, 'data-layout': node.attrs.layout, 'data-autosize': node.attrs.__autoSize, 'data-table-local-id': node.attrs.localId, 'data-table-width': node.attrs.width, 'data-table-display-mode': node.attrs.displayMode }; return ['table', attrs, ['tbody', 0]]; } }; // TODO: Fix any, potential issue. ED-5048 var createTableSpec = function createTableSpec() { return tableFactory(tableNodeSpecOptions); }; // TODO: assuming breaking changes aren't allowed, so retaining both exports /** Includes table width attribute */ export var table = createTableSpec(); /** @deprecated Do not use, instead use the regular `table` export */ export var tableWithCustomWidth = createTableSpec(); export var tableStage0 = createTableSpec(); var shouldIncludeAttribute = function shouldIncludeAttribute(key, value) { return !key.startsWith('__') && (key !== 'localId' || !!value); }; export var tableToJSON = function tableToJSON(node) { return { attrs: Object.keys(node.attrs).filter(function (key) { return shouldIncludeAttribute(key, node.attrs[key]); }).reduce(function (obj, key) { return _objectSpread(_objectSpread({}, obj), {}, _defineProperty({}, key, node.attrs[key])); }, {}) }; }; var tableRowNodeSpecOptions = { parseDOM: [{ tag: 'tr' }], toDOM: function toDOM() { return ['tr', 0]; } }; export var tableRow = tableRowFactory(tableRowNodeSpecOptions); var cellAttrs = { colspan: { default: 1 }, rowspan: { default: 1 }, colwidth: { default: null }, background: { default: null } }; var tableCellNodeSpecOptions = { parseDOM: [ // Ignore number cell copied from renderer { tag: '.ak-renderer-table-number-column', ignore: true }, { tag: 'td', getAttrs: function getAttrs(dom) { return getCellAttrs(dom); } }], toDOM: function toDOM(node) { return ['td', getCellDomAttrs(node), 0]; } }; export var tableCell = tableCellFactory(tableCellNodeSpecOptions); export var toJSONTableCell = function toJSONTableCell(node) { return { attrs: Object.keys(node.attrs).reduce(function (obj, key) { if (cellAttrs[key].default !== node.attrs[key]) { obj[key] = node.attrs[key]; } return obj; }, {}) }; }; var tableHeaderNodeSpecOptions = { parseDOM: [{ tag: 'th', getAttrs: function getAttrs(dom) { return getCellAttrs(dom, { background: DEFAULT_TABLE_HEADER_CELL_BACKGROUND }); } }], toDOM: function toDOM(node) { return ['th', getCellDomAttrs(node), 0]; } }; export var tableHeader = tableHeaderFactory(tableHeaderNodeSpecOptions); export var toJSONTableHeader = toJSONTableCell; // table nodes with nested table support export var tableWithNestedTable = tableWithNestedTableFactory(tableNodeSpecOptions); export var tableRowWithNestedTable = tableRowWithNestedTableFactory(tableRowNodeSpecOptions); export var tableCellWithNestedTable = tableCellWithNestedTableFactory(tableCellNodeSpecOptions); export var tableHeaderWithNestedTable = tableHeaderWithNestedTableFactory(tableHeaderNodeSpecOptions);