Skip to content

Instantly share code, notes, and snippets.

@paxapy
Created March 24, 2021 09:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paxapy/c868759e09d89ed32e39bb0afc9ab24a to your computer and use it in GitHub Desktop.
Save paxapy/c868759e09d89ed32e39bb0afc9ab24a to your computer and use it in GitHub Desktop.
prosemirror list toggle set.
type PredicateCommand = (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean;
/**
* Creates a new EditorCommand that wraps/unwraps the selection in a given list itemType.
* To be used by list and list item types.
*/
export function toggleListNode(nodeType: NodeType): EditorCommand {
return {
enable: () => true,
active: (state) => isNodeActive(state, nodeType),
run: (state, dispatch) => {
const itemType = getListItemType(nodeType, state);
if (isNodeActive(state, nodeType)) {
return liftListItem(itemType)(state, dispatch);
} else if (listNodeActive(state)) {
const predicate = chainTransactions(liftListItem(itemType), wrapInList(nodeType));
return predicate(state, dispatch);
} else {
return wrapInList(nodeType)(state, dispatch);
}
},
};
}
/**
* Returns list item type by list node type and state (used to get schema).
*/
function getListItemType(nodeType: NodeType, state: EditorState): NodeType {
const nodes = state.schema.nodes;
const itemTypeMap: { [key: string]: NodeType } = {
bullet_list: nodes.list_item,
ordered_list: nodes.list_item,
check_list: nodes.check_list_item,
};
return itemTypeMap[nodeType.name];
}
/**
* Chain passed commands with consenquent state applyment.
*/
function chainTransactions(...commands: PredicateCommand[]): PredicateCommand {
return (state, dispatch): boolean => {
const dispatcher = (tr: Transaction): void => {
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);
};
}
/**
* Checks if the the active node is one of the list nodes.
*/
export function listNodeActive(state: EditorState): boolean {
const listTypes = ['bullet_list', 'ordered_list'];
const predicate = hasParentNode((node) => listTypes.includes(node.type.name));
return predicate(state.selection);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment