@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
100 lines (99 loc) • 3.6 kB
JavaScript
import { tableCellBorderWidth, tableMarginTop } from '@atlaskit/editor-common/styles';
import { closestElement, containsClassName, parsePx } from '@atlaskit/editor-common/utils';
import { TableCssClassName as ClassName } from '../../../types';
import { getPluginState as getMainPluginState } from '../../plugin-factory';
import { colWidthsForRow } from '../../utils/column-controls';
import { getRowHeights } from '../../utils/row-controls';
export const updateControls = () => state => {
const {
tableRef
} = getMainPluginState(state);
if (!tableRef) {
return;
}
const tr = tableRef.querySelector('tr');
if (!tr) {
return;
}
const wrapper = tableRef.parentElement;
if (!(wrapper && wrapper.parentElement)) {
return;
}
const rowControls = wrapper.parentElement.querySelectorAll(`.${ClassName.ROW_CONTROLS_BUTTON_WRAP}`);
const numberedRows = wrapper.parentElement.querySelectorAll(ClassName.NUMBERED_COLUMN_BUTTON);
syncStickyRowToTable(tableRef);
const rowHeights = getRowHeights(tableRef);
// update rows controls height on resize
for (let i = 0, count = rowControls.length; i < count; i++) {
const height = rowHeights[i];
if (height) {
rowControls[i].style.height = `${height}px`;
if (numberedRows.length) {
numberedRows[i].style.height = `${height}px`;
}
}
}
};
export const isClickNear = (event, click) => {
const dx = click.x - event.clientX,
dy = click.y - event.clientY;
return dx * dx + dy * dy < 100;
};
export const getResizeCellPos = (view, event) => {
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
const target = event.target;
if (!containsClassName(target, ClassName.RESIZE_HANDLE_DECORATION)) {
return null;
}
const tableCell = closestElement(target, 'td, th');
if (!tableCell) {
return null;
}
const cellStartPosition = view.posAtDOM(tableCell, 0);
return cellStartPosition - 1;
};
export const updateStickyMargins = table => {
const row = table.querySelector('tr.sticky');
if (!row) {
table.style.marginTop = '';
return;
}
const paddingTop = parsePx(window.getComputedStyle(row).paddingTop || '') || 0;
const firstRowHeight = row.getBoundingClientRect().height - paddingTop - tableCellBorderWidth;
table.style.marginTop = `${tableMarginTop + firstRowHeight}px`;
};
const applyColWidthsToStickyRow = (colGroup, headerRow) => {
// sync column widths for the sticky row
const newCols = colWidthsForRow(headerRow);
if (newCols) {
headerRow.style.gridTemplateColumns = newCols;
}
};
export const syncStickyRowToTable = tableRef => {
if (!tableRef) {
return;
}
const headerRow = tableRef.querySelector('tr[data-header-row]');
if (!headerRow) {
return;
}
applyColWidthsToStickyRow(tableRef.querySelector('colgroup'), headerRow);
applyTableWidthToStickyRow(tableRef, headerRow);
};
const applyTableWidthToStickyRow = (tableRef, headerRow) => {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const tbody = tableRef.querySelector('tbody');
const wrapper = tableRef.parentElement;
if (tbody && wrapper) {
// when resizing in Chrome, clientWidth will give us 759px
// but toggling the sticky class will reset it to 760px.
//
// both elements in the dom + inspector will
// be the same width but at layout will be different..
const newWidth = Math.min(tbody.offsetWidth + 1, wrapper.offsetWidth);
headerRow.style.width = `${newWidth}px`;
headerRow.scrollLeft = wrapper.scrollLeft;
}
};