import { ApplySchemaAttributes , command , CommandFunction , extension , ExtensionPriority , ExtensionTag , isBoolean , isNodeSelection , KeyBindings , NodeExtension , NodeExtensionSpec , NodeSpecOverride , NodeViewMethod , ProsemirrorAttributes , ProsemirrorNode , Static , } from '@remirror/core' ; import { NodeType } from '@remirror/pm/model' ; import { NodeSelection } from '@remirror/pm/state' ; import { ExtensionListTheme } from '@remirror/theme' ; import { liftListItemOutOfList , splitListItem } from './list-commands' ; import { createCustomMarkListItemNodeView } from './list-item-node-view' ; import { ListItemSharedExtension } from './list-item-shared-extension' ; /**
 * Creates the node for a list item.
 */ @ extension < ListItemOptions > ( { defaultOptions : { enableCollapsible : false } , staticKeys : [ 'enableCollapsible' ] , } ) export class ListItemExtension extends NodeExtension < ListItemOptions > { get name ( ) { return 'listItem' as const ; } createTags ( ) { return [ ExtensionTag . ListItemNode ] ; } createNodeSpec ( extra , override ) { return { content : 'paragraph block*' , defining : true , draggable : false , ... override , attrs : { ... extra . defaults ( ) , closed : { default : false } , nested : { default : false } , } , parseDOM : [ { tag : 'li' , getAttrs : extra . parse , priority : ExtensionPriority . Lowest , } , ... ( override . parseDOM ?? [ ] ) , ] , toDOM : ( node ) => { const attrs = extra . dom ( node ) ; return [ 'li' , attrs , 0 ] ; } , } ; } createNodeViews ( ) { if ( ! this . options . enableCollapsible ) { return { } ; } return ( node , view , getPos ) => { const mark = document . createElement ( 'div' ) ; mark . classList . add ( ExtensionListTheme . COLLAPSIBLE_LIST_ITEM_BUTTON ) ; mark . contentEditable = 'false' ; mark . addEventListener ( 'click' , ( ) => { if ( mark . classList . contains ( 'disabled' ) ) { return ; } const pos = ( getPos as ( ) => number ) ( ) ; const selection = NodeSelection . create ( view . state . doc , pos ) ; view . dispatch ( view . state . tr . setSelection ( selection ) ) ; this . store . commands . toggleListItemClosed ( ) ; return true ; } ) ; return createCustomMarkListItemNodeView ( { mark , node , updateDOM : updateNodeViewDOM , updateMark : updateNodeViewMark , } ) ; } ; } createKeymap ( ) { return { Enter : splitListItem ( this . type ) , } ; } createExtensions ( ) { return [ new ListItemSharedExtension ( ) ] ; } param closed @ command ( ) toggleListItemClosed ( closed ? ) { return ( { state : { tr , selection } , dispatch } ) => { if ( ! isNodeSelection ( selection ) || selection . node . type . name !== this . name ) { return false ; } const { node , from } = selection ; closed = isBoolean ( closed ) ? closed : ! node . attrs . closed ; dispatch ?. ( tr . setNodeMarkup ( from , undefined , { ... node . attrs , closed } ) ) ; return true ; } ; } /**
     * Lift the content inside a list item around the selection out of list
     */ @ command ( ) liftListItemOutOfList ( listItemType ? ) { return liftListItemOutOfList ( listItemType ?? this . type ) ; } } function updateNodeViewDOM ( node , dom ) { node . attrs . closed ? dom . classList . add ( ExtensionListTheme . COLLAPSIBLE_LIST_ITEM_CLOSED ) : dom . classList . remove ( ExtensionListTheme . COLLAPSIBLE_LIST_ITEM_CLOSED ) ; } function updateNodeViewMark ( node , mark ) { node . childCount <= 1 ? mark . classList . add ( 'disabled' ) : mark . classList . remove ( 'disabled' ) ; } export interface ListItemOptions { /**
     * Set this to true to support toggling.
     */ enableCollapsible ? : Static < boolean > ; } export type ListItemAttributes = ProsemirrorAttributes < { default closed : boolean ; default nested : boolean ; } > ; declare global { namespace Remirror { interface AllExtensions { listItem : ListItemExtension ; } } }