@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
148 lines (145 loc) • 6.77 kB
JavaScript
import { ACTION_SUBJECT, EVENT_TYPE, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
import { TableSharedCssClassName } from '@atlaskit/editor-common/styles';
import { findTable } from '@atlaskit/editor-tables/utils';
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
import { hasTableColumnBeenResized } from '../table-resizing/utils/colgroup';
import { applyTableMeasurement, getTableMeasurement } from '../transforms/content-mode';
import { ALIGN_START } from './alignment';
export const isTableInContentMode = ({
allowColumnResizing,
allowTableResizing,
isFullPageEditor,
isTableNested,
node
}) => {
if (!expValEqualsNoExposure('platform_editor_table_fit_to_content_auto_convert', 'isEnabled', true)) {
return false;
}
if (!node || isTableNested) {
return false;
}
return isContentModeSupported({
allowColumnResizing,
allowTableResizing,
isFullPageEditor
}) && !hasTableBeenResized(node) && node.attrs.layout === ALIGN_START;
};
export const isContentModeSupported = ({
allowColumnResizing,
allowTableResizing,
isFullPageEditor
}) => {
return allowColumnResizing && allowTableResizing && isFullPageEditor;
};
export const hasTableBeenResized = node => node.attrs.width !== null || hasTableColumnBeenResized(node);
/**
* Iterates all top-level tables in the document, and for those in content mode,
* measures rendered column widths and sets colwidth + table width attributes
* in a single batched transaction.
*/
export const applyMeasuredWidthToAllTables = (view, pluginInjectionApi) => {
const {
state: {
doc,
schema
}
} = view;
let tr = view.state.tr;
const {
table
} = schema.nodes;
let modified = false;
const measuredTables = [];
// modify only top-level tables
doc.forEach((node, offset) => {
if (node.type !== table || hasTableBeenResized(node) && node.attrs.layout !== ALIGN_START) {
return;
}
const domNode = view.domAtPos(offset + 1).node;
const tableWrapper = domNode instanceof HTMLElement ? domNode.closest(`.${TableSharedCssClassName.TABLE_VIEW_CONTENT_WRAP}`) : null;
const tableRef = tableWrapper === null || tableWrapper === void 0 ? void 0 : tableWrapper.querySelector('table');
if (!tableRef) {
return;
}
measuredTables.push({
node,
offset,
measurement: getTableMeasurement(tableRef)
});
});
measuredTables.forEach(({
node,
offset,
measurement
}) => {
tr = applyTableMeasurement(tr, node, measurement, offset);
modified = true;
});
if (modified) {
var _pluginInjectionApi$a, _pluginInjectionApi$a2, _pluginInjectionApi$w, _pluginInjectionApi$w2, _pluginInjectionApi$w3;
pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : (_pluginInjectionApi$a2 = _pluginInjectionApi$a.actions) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : _pluginInjectionApi$a2.attachAnalyticsEvent({
action: TABLE_ACTION.FIT_TO_CONTENT_AUTO_CONVERTED,
actionSubject: ACTION_SUBJECT.TABLE,
actionSubjectId: null,
eventType: EVENT_TYPE.TRACK,
attributes: {
editorContainerWidth: (_pluginInjectionApi$w = pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$w2 = pluginInjectionApi.width) === null || _pluginInjectionApi$w2 === void 0 ? void 0 : (_pluginInjectionApi$w3 = _pluginInjectionApi$w2.sharedState.currentState()) === null || _pluginInjectionApi$w3 === void 0 ? void 0 : _pluginInjectionApi$w3.width) !== null && _pluginInjectionApi$w !== void 0 ? _pluginInjectionApi$w : 0,
totalTablesResized: measuredTables.length,
measurements: measuredTables.map(({
measurement
}) => ({
tableWidth: measurement.tableWidth,
totalColumnCount: measurement.colWidths.length
}))
}
})(tr);
view.dispatch(tr.setMeta('addToHistory', false));
}
};
export const applyMeasuredWidthToSelectedTable = (view, api) => {
var _api$analytics, _api$analytics$action, _api$width$sharedStat, _api$width, _api$width$sharedStat2;
const tableObject = findTable(view.state.selection);
if (!tableObject) {
return;
}
const {
node,
pos
} = tableObject;
const tableState = api === null || api === void 0 ? void 0 : api.table.sharedState.currentState();
if (!(tableState !== null && tableState !== void 0 && tableState.tableRef)) {
return;
}
const tableRef = tableState.tableRef;
// Instead of dispatching a transaction to "strip widths" and then waiting
// for a rAF to measure natural column widths, instea directly update the DOM elements and
// take a measurement.
const cols = Array.from(tableRef.querySelectorAll(':scope > colgroup > col'));
const contentWrap = tableRef.closest(`.${TableSharedCssClassName.TABLE_VIEW_CONTENT_WRAP}`);
const resizerContainer = contentWrap === null || contentWrap === void 0 ? void 0 : contentWrap.querySelector(`.${TableSharedCssClassName.TABLE_RESIZER_CONTAINER}`);
const resizerItem = resizerContainer === null || resizerContainer === void 0 ? void 0 : resizerContainer.querySelector('.resizer-item.display-handle');
tableRef.style.width = '';
tableRef.style.tableLayout = 'auto';
cols.forEach(col => col.style.width = '');
if (resizerContainer) {
resizerContainer.style.width = 'max-content';
resizerContainer.style.setProperty('--ak-editor-table-width', 'max-content');
}
if (resizerItem) {
resizerItem.style.width = 'max-content';
}
const measurement = getTableMeasurement(tableRef);
const tr = applyTableMeasurement(view.state.tr, node, measurement, pos);
api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : _api$analytics$action.attachAnalyticsEvent({
action: TABLE_ACTION.FIT_TO_CONTENT_ON_DEMAND,
actionSubject: ACTION_SUBJECT.TABLE,
actionSubjectId: null,
eventType: EVENT_TYPE.TRACK,
attributes: {
editorContainerWidth: (_api$width$sharedStat = api === null || api === void 0 ? void 0 : (_api$width = api.width) === null || _api$width === void 0 ? void 0 : (_api$width$sharedStat2 = _api$width.sharedState.currentState()) === null || _api$width$sharedStat2 === void 0 ? void 0 : _api$width$sharedStat2.width) !== null && _api$width$sharedStat !== void 0 ? _api$width$sharedStat : 0,
tableWidth: measurement.tableWidth,
totalColumnCount: measurement.colWidths.length
}
})(tr);
view.dispatch(tr);
};