@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
113 lines (109 loc) • 4.04 kB
JavaScript
// #region Imports
import { TableSortStep } from '@atlaskit/custom-steps';
import { isTextInput } from '@atlaskit/editor-common/utils';
// @ts-ignore -- ReadonlyTransaction is a local declaration and will cause a TS2305 error in CCFE typecheck
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
import { findTable } from '@atlaskit/editor-tables/utils';
import { defaultTableSelection } from './default-table-selection';
import { pluginKey as tableResizingPluginKey } from './table-resizing/plugin-key';
import { isTableCollapsible } from './utils/collapse';
import { checkIfHeaderColumnEnabled, checkIfHeaderRowEnabled, checkIfNumberColumnEnabled } from './utils/nodes';
const nextTableSorting = (tr, table) => {
const tableSortStep = tr.steps.find(step => step instanceof TableSortStep);
return tableSortStep && table && table.pos === tableSortStep.pos ? tableSortStep.next : undefined;
};
const nextResizeHandleColumnIndex = (tr, resizeHandleColumnIndex) => {
if (tr.getMeta(tableResizingPluginKey)) {
return undefined;
}
return resizeHandleColumnIndex;
};
const updateTargetCellPosition = ({
tr,
table
}) => pluginState => {
const tableNode = table && table.node;
if (!tableNode) {
return {
...pluginState,
targetCellPosition: undefined
};
}
const {
tableCell,
tableHeader
} = tr.doc.type.schema.nodes;
const cell = findParentNodeOfType([tableCell, tableHeader])(tr.selection);
const targetCellPosition = cell ? cell.pos : undefined;
if (pluginState.targetCellPosition === targetCellPosition) {
return pluginState;
}
return {
...pluginState,
targetCellPosition
};
};
const updateTableNodePluginState = ({
tr,
table
}) => pluginState => {
const tableNode = table && table.node;
if (!tableNode || isTextInput(tr)) {
return pluginState;
}
return {
...pluginState,
...defaultTableSelection,
tableNode,
ordering: nextTableSorting(tr, table),
resizeHandleColumnIndex: nextResizeHandleColumnIndex(tr, pluginState.resizeHandleColumnIndex),
isNumberColumnEnabled: checkIfNumberColumnEnabled(tr.selection),
isHeaderColumnEnabled: checkIfHeaderColumnEnabled(tr.selection),
isHeaderRowEnabled: checkIfHeaderRowEnabled(tr.selection)
};
};
const updateCollapseHandler = ({
tr,
table
}) => pluginState => {
const tableNode = table && table.node;
const schema = tr.doc.type.schema;
const allowCollapse = pluginState.pluginConfig.allowCollapse;
const isExpandInSchema = schema.nodes.expand !== undefined;
const isCollapseEnabled = allowCollapse && isExpandInSchema;
/**
* If we don't have focus, or collapse isn't allowed, or a table node doesn't
* exist, we don't need to waste extra checks below
*/
if (!pluginState.editorHasFocus || !isCollapseEnabled || !tableNode) {
return pluginState;
}
const expandNodeType = schema.nodes.expand;
const isTableCollapsed = expandNodeType && !!findParentNodeOfType(expandNodeType)(tr.selection);
const trCanBeCollapsed = isTableCollapsible(tr).tableIsCollapsible;
// We're focused on a table + we're not inside an expand
const canCollapseTable = !!pluginState.tableNode &&
// is it already collapsed?
!isTableCollapsed && !!trCanBeCollapsed;
if (pluginState.isTableCollapsed !== isTableCollapsed || pluginState.canCollapseTable !== canCollapseTable) {
return {
...pluginState,
isTableCollapsed,
canCollapseTable
};
}
return pluginState;
};
const buildPluginState = builders => props => pluginState => {
if (!props.table) {
return pluginState.targetCellPosition ? {
...pluginState,
targetCellPosition: undefined
} : pluginState;
}
return builders.reduce((_pluginState, transform) => transform(props)(_pluginState), pluginState);
};
export const handleDocOrSelectionChanged = (tr, pluginState) => buildPluginState([updateTargetCellPosition, updateTableNodePluginState, updateCollapseHandler])({
tr,
table: findTable(tr.selection)
})(pluginState);