import { useCallback , useMemo , useState } from 'react' ; import { Replace } from '@remirror/core' ; import type { MentionChangeHandler , MentionChangeHandlerCommand , MentionExtensionAttributes , } from '@remirror/extension-mention' ; import { MentionExtension } from '@remirror/extension-mention' ; import { ChangeReason , ExitReason , SuggestChangeHandlerProps } from '@remirror/pm/suggest' ; import { useExtension , useHelpers } from '@remirror/react-core' ; import { MenuNavigationOptions , useMenuNavigation , UseMenuNavigationReturn , } from './use-menu-navigation' ; export interface MentionState < Data extends MentionExtensionAttributes = MentionExtensionAttributes > extends Pick < SuggestChangeHandlerProps , 'name' | 'query' | 'text' | 'range' > { /**
     * This command when the mention is active.
     */ command : ( item : Data ) => void ; /**
     * The reason for the change.
     */ reason : ChangeReason ; } export interface UseMentionReturn < Data extends MentionExtensionAttributes = MentionExtensionAttributes > extends UseMenuNavigationReturn < Data > { state : MentionState < Data > | null ; } param list export function useMention < Data extends MentionExtensionAttributes = MentionExtensionAttributes > ( props ) { const { items , ignoreMatchesOnDismiss = true , onExit , direction , dismissKeys , focusOnClick , submitKeys , } = props ; const [ state , setState ] = useState < MentionState | null > ( null ) ; const helpers = useHelpers ( ) ; const isOpen = ! ! state ; const onDismiss = useCallback ( ( ) => { if ( ! state ) { return false ; } const { range , name } = state ; if ( ignoreMatchesOnDismiss ) { helpers . getSuggestMethods ( ) . addIgnored ( { from : range . from , name , specific : true } ) ; } setState ( null ) ; return true ; } , [ helpers , ignoreMatchesOnDismiss , state ] ) ; const onSubmit = useCallback ( ( item ) => { if ( ! state ) { return false ; } const { command } = state ; command ( item ) ; return true ; } , [ state ] ) ; const menu = useMenuNavigation < Data > ( { items , isOpen , onDismiss , onSubmit , direction , dismissKeys , focusOnClick , submitKeys , } ) ; const { setIndex } = menu ; /**
     * The is the callback for when a suggestion is changed.
     */ const onChange = useCallback ( ( props , cmd ) => { const { query , text , range , ignoreNextExit , name , exitReason , changeReason , textAfter , defaultAppendTextValue , } = props ; if ( changeReason ) { const command = ( attrs ) => { ignoreNextExit ( ) ; const regex = /^\s+/ ; const appendText = regex . test ( textAfter ) ? '' : defaultAppendTextValue ; cmd ( { appendText , ... attrs } ) ; setState ( null ) ; } ; if ( changeReason !== ChangeReason . Move ) { setIndex ( 0 ) ; } setState ( { reason : changeReason , name , query , text , range , command } ) ; return ; } if ( ! exitReason || ! onExit ) { setState ( null ) ; return ; } const exitCommand = ( attrs ) => { cmd ( { appendText : '' , ... attrs } ) ; } ; onExit ( { reason : exitReason , name , query , text , range } , exitCommand ) ; setState ( null ) ; } , [ setIndex , onExit ] ) ; useExtension ( MentionExtension , ( { addHandler } ) => addHandler ( 'onChange' , onChange ) , [ onChange ] ) ; return useMemo ( ( ) => ( { ... menu , state } ) , [ menu , state ] ) ; } export interface UseMentionProps < Data extends MentionExtensionAttributes = MentionExtensionAttributes > extends MenuNavigationOptions { /**
     * The list of data from which an index can be calculated. Must include at
     * least an `id` and a `label`.
     */ items : Data [ ] ; /**
     * This method is called when a user induced exit happens before a mention has
     * been created. It receives the state, and gives the consumer of this hook
     * the opportunity to manually create their own mention
     *
     * Leave this undefined to ignore exits.
     *
     * To enable automatic exit handling. The following will automatically set the
     * id to be the query and the label to be the full matching text. Extra attrs
     * like `href` can be added by you to the attrs object parameter.
     *
     * ```ts
     * const mentionState = useMention({ items, onExit(_, command) => command(), });
     * ```
     */ onExit ? : UseMentionExitHandler < Data > ; default ignoreMatchesOnDismiss ? : boolean ; } export type UseMentionExitHandler < Data extends MentionExtensionAttributes = MentionExtensionAttributes > = ( props : OnExitProps < Data > , command : ( attrs ? : Partial < Data > ) => void ) => void ; type OnExitProps < Data extends MentionExtensionAttributes = MentionExtensionAttributes > = Replace < Omit < MentionState < Data > , 'command' > , { reason : ExitReason ; } > ;