UNPKG

@atlaskit/editor-plugin-block-menu

Version:

BlockMenu plugin for @atlaskit/editor-core

126 lines • 6.26 kB
import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection/utils'; import { Fragment } from '@atlaskit/editor-prosemirror/model'; import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled'; import { isTransformDisabledBasedOnStepsConfig } from '../editor-commands/transform-node-utils/transform'; import { toNodeTypeValue } from '../editor-commands/transform-node-utils/types'; import { getBlockNodesInRange, getTargetNodeTypeNameInContext } from '../editor-commands/transform-node-utils/utils'; import { getSingleTransformSourceNode, isExtensionTransformSource } from './transformSource'; const getTargetMarks = (schema, currentMarks, marksToAdd, marksToRemove) => { if (!marksToAdd && !marksToRemove) { return undefined; } let targetMarks = currentMarks; for (const name of marksToRemove !== null && marksToRemove !== void 0 ? marksToRemove : []) { const markType = schema.marks[name]; if (markType) { targetMarks = markType.removeFromSet(targetMarks); } } for (const [name, attrs] of Object.entries(marksToAdd !== null && marksToAdd !== void 0 ? marksToAdd : {})) { const markType = schema.marks[name]; if (markType) { targetMarks = markType.create(attrs).addToSet(markType.removeFromSet(targetMarks)); } } return targetMarks; }; export const canParentContainNodeType = (schema, selectedNodeTypeName, parentNode, nodeTypeName, nodeTypeAttrs, selectedNode, marksToAdd, marksToRemove) => { const adjustedNodeTypeName = getTargetNodeTypeNameInContext(nodeTypeName, true, parentNode, schema); if (!adjustedNodeTypeName) { return false; } const nodeType = schema.nodes[adjustedNodeTypeName]; let content = null; const nodesThatCantBeNestedInNestedExpand = ['blockCard', 'embedCard', 'table']; if (nodesThatCantBeNestedInNestedExpand.includes(selectedNodeTypeName) && (adjustedNodeTypeName === 'expand' || adjustedNodeTypeName === 'nestedExpand')) { const node = schema.nodes[selectedNodeTypeName]; content = node.createAndFill(); } if (isExperimentEnabled('platform_editor_block_menu_small_text') && selectedNode && (marksToAdd || marksToRemove)) { const targetMarks = getTargetMarks(schema, selectedNode.marks, marksToAdd, marksToRemove); const targetNode = nodeType.createAndFill(nodeTypeAttrs, content, targetMarks); return Boolean(targetNode && parentNode.type.validContent(Fragment.from(targetNode))); } return parentNode.type.validContent(Fragment.from(nodeType.createAndFill(nodeTypeAttrs, content))); }; const isHeadingToHeadingTransformEnabled = (selectedNode, targetNodeTypeAttrs) => { var _selectedNode$attrs; const selectedLevel = (_selectedNode$attrs = selectedNode.attrs) === null || _selectedNode$attrs === void 0 ? void 0 : _selectedNode$attrs.level; const targetLevel = targetNodeTypeAttrs === null || targetNodeTypeAttrs === void 0 ? void 0 : targetNodeTypeAttrs.level; if (selectedLevel === undefined || targetLevel === undefined) { return false; } return selectedLevel !== targetLevel; }; const isTransformEnabledForNode = (node, targetNodeTypeName, targetNodeTypeAttrs, marksToAdd, marksToRemove, isNested, parent, schema) => { const selectedNodeTypeName = toNodeTypeValue(node.type.name); if (!selectedNodeTypeName) { return false; } if (selectedNodeTypeName === targetNodeTypeName) { const removesTargetMarks = marksToRemove === null || marksToRemove === void 0 ? void 0 : marksToRemove.some(name => { const markType = schema.marks[name]; return markType ? Boolean(markType.isInSet(node.marks)) : false; }); const addsOrReplacesTargetMarks = Object.entries(marksToAdd !== null && marksToAdd !== void 0 ? marksToAdd : {}).some(([name, attrs]) => { var _markType$isInSet; const markType = schema.marks[name]; return markType ? !((_markType$isInSet = markType.isInSet(node.marks)) !== null && _markType$isInSet !== void 0 && _markType$isInSet.eq(markType.create(attrs))) : false; }); if (removesTargetMarks || addsOrReplacesTargetMarks) { if (isNested && !canParentContainNodeType(schema, selectedNodeTypeName, parent, targetNodeTypeName, targetNodeTypeAttrs, node, marksToAdd, marksToRemove)) { return false; } return true; } } const isDisabledByStepsConfig = isTransformDisabledBasedOnStepsConfig(selectedNodeTypeName, targetNodeTypeName); if (isDisabledByStepsConfig) { return false; } if (selectedNodeTypeName === 'heading' && targetNodeTypeName === 'heading') { return isHeadingToHeadingTransformEnabled(node, targetNodeTypeAttrs); } if (isNested && !canParentContainNodeType(schema, selectedNodeTypeName, parent, targetNodeTypeName, targetNodeTypeAttrs, node, marksToAdd, marksToRemove)) { return false; } return true; }; export const isTransformToTargetDisabled = ({ selection, targetNodeTypeName, targetNodeTypeAttrs, targetNodeMarkChanges, transformRegistry }) => { const { range } = expandSelectionToBlockRange(selection); if (!range) { return false; } const sourceNode = getSingleTransformSourceNode(selection, range); if (isExtensionTransformSource(sourceNode)) { var _transformRegistry$re; return (transformRegistry === null || transformRegistry === void 0 ? void 0 : (_transformRegistry$re = transformRegistry.resolve({ source: sourceNode.toJSON(), targetTypeName: targetNodeTypeName })) === null || _transformRegistry$re === void 0 ? void 0 : _transformRegistry$re.status) !== 'supported'; } const selectedNodes = getBlockNodesInRange(range); const parent = range.parent; const isNested = range.depth >= 1; const { schema } = selection.$from.doc.type; const { marksToAdd, marksToRemove } = targetNodeMarkChanges !== null && targetNodeMarkChanges !== void 0 ? targetNodeMarkChanges : {}; const supportedTargetNodeTypeName = toNodeTypeValue(targetNodeTypeName); if (!supportedTargetNodeTypeName) { return true; } const isEnabledForAnyNode = selectedNodes.some(node => isTransformEnabledForNode(node, supportedTargetNodeTypeName, targetNodeTypeAttrs, marksToAdd, marksToRemove, isNested, parent, schema)); return !isEnabledForAnyNode; };