prosemirror-flat-list
Version:
Powerful list support for ProseMirror
65 lines (55 loc) • 1.77 kB
text/typescript
import type { Command } from 'prosemirror-state'
import type { ListAttributes, ProsemirrorNode } from '../types'
import { isListNode } from '../utils/is-list-node'
import { setSafeSelection } from './set-safe-selection'
/**
* @public @group Commands
*/
export interface ToggleCollapsedOptions {
/**
* If this value exists, the command will set the `collapsed` attribute to
* this value instead of toggle it.
*/
collapsed?: boolean
/**
* An optional function to accept a list node and return whether or not this
* node can toggle its `collapsed` attribute.
*/
isToggleable?: (node: ProsemirrorNode) => boolean
}
/**
* Return a command function that toggle the `collapsed` attribute of the list node.
*
* @public @group Commands
*/
export function createToggleCollapsedCommand(
options: ToggleCollapsedOptions = {},
): Command {
const { collapsed = undefined, isToggleable = defaultIsToggleable } = options
const toggleCollapsed: Command = (state, dispatch) => {
const { $from } = state.selection
for (let depth = $from.depth; depth >= 0; depth--) {
const node = $from.node(depth)
if (isListNode(node) && isToggleable(node)) {
if (dispatch) {
const pos = $from.before(depth)
const attrs = node.attrs as ListAttributes
const tr = state.tr
tr.setNodeAttribute(pos, 'collapsed', collapsed ?? !attrs.collapsed)
dispatch(setSafeSelection(tr))
}
return true
}
}
return false
}
return toggleCollapsed
}
function defaultIsToggleable(node: ProsemirrorNode): boolean {
const attrs = node.attrs as ListAttributes
return (
attrs.kind === 'toggle' &&
node.childCount >= 2 &&
!isListNode(node.firstChild)
)
}