I found a solution that requires very little code based on a few discussions on these forums. I hope this will help someone:
function chainTransactions(...commands: EditorCommand[]): EditorCommand {
return (state, dispatch): boolean => {
const dispatcher = (tr: Transaction) => {
state = state.apply(tr);
dispatch(tr);
};
const last = commands.pop();
const reduced = commands.reduce((result, command) => {
return result || command(state, dispatcher);
}, false);
return reduced && last !== undefined && last(state, dispatch);
};
}
function toggleList(listType: NodeType, schema: Schema, attrs: any): EditorCommand {
return function (state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
if (!dispatch) return true;
const currentNode = getSelectedNodeType(state);
const oppositeListOf: { [key: string]: string } = {
bullet_list: 'ordered_list',
ordered_list: 'bullet_list',
};
let transactions: EditorCommand;
if (currentNode.name === listType.name) transactions = liftListItem(schema.nodes.list_item);
else if (oppositeListOf[currentNode.name] === listType.name)
transactions = chainTransactions(liftListItem(schema.nodes.list_item), wrapInList(listType, attrs));
else transactions = wrapInList(listType, attrs);
return transactions(state, dispatch);
};
}
export function toggleListItem(nodeType: NodeType, schema: Schema, options: any): MenuItem {
return cmdItem(toggleList(nodeType, schema, options.attrs), { ...options, active: isListActive(nodeType) });
}