| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 | 
							- import {
 
-   useCallback,
 
-   useEffect,
 
-   useRef,
 
-   useState,
 
- } from 'react'
 
- import type { Dispatch, RefObject, SetStateAction } from 'react'
 
- import type {
 
-   Klass,
 
-   LexicalCommand,
 
-   LexicalEditor,
 
-   TextNode,
 
- } from 'lexical'
 
- import {
 
-   $getNodeByKey,
 
-   $getSelection,
 
-   $isDecoratorNode,
 
-   $isNodeSelection,
 
-   COMMAND_PRIORITY_LOW,
 
-   KEY_BACKSPACE_COMMAND,
 
-   KEY_DELETE_COMMAND,
 
- } from 'lexical'
 
- import type { EntityMatch } from '@lexical/text'
 
- import {
 
-   mergeRegister,
 
- } from '@lexical/utils'
 
- import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection'
 
- import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
 
- import { $isContextBlockNode } from './plugins/context-block/node'
 
- import { DELETE_CONTEXT_BLOCK_COMMAND } from './plugins/context-block'
 
- import { $isHistoryBlockNode } from './plugins/history-block/node'
 
- import { DELETE_HISTORY_BLOCK_COMMAND } from './plugins/history-block'
 
- import { $isQueryBlockNode } from './plugins/query-block/node'
 
- import { DELETE_QUERY_BLOCK_COMMAND } from './plugins/query-block'
 
- import type { CustomTextNode } from './plugins/custom-text/node'
 
- import { registerLexicalTextEntity } from './utils'
 
- export type UseSelectOrDeleteHanlder = (nodeKey: string, command?: LexicalCommand<undefined>) => [RefObject<HTMLDivElement>, boolean]
 
- export const useSelectOrDelete: UseSelectOrDeleteHanlder = (nodeKey: string, command?: LexicalCommand<undefined>) => {
 
-   const ref = useRef<HTMLDivElement>(null)
 
-   const [editor] = useLexicalComposerContext()
 
-   const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)
 
-   const handleDelete = useCallback(
 
-     (event: KeyboardEvent) => {
 
-       const selection = $getSelection()
 
-       const nodes = selection?.getNodes()
 
-       if (
 
-         !isSelected
 
-         && nodes?.length === 1
 
-         && (
 
-           ($isContextBlockNode(nodes[0]) && command === DELETE_CONTEXT_BLOCK_COMMAND)
 
-           || ($isHistoryBlockNode(nodes[0]) && command === DELETE_HISTORY_BLOCK_COMMAND)
 
-           || ($isQueryBlockNode(nodes[0]) && command === DELETE_QUERY_BLOCK_COMMAND)
 
-         )
 
-       )
 
-         editor.dispatchCommand(command, undefined)
 
-       if (isSelected && $isNodeSelection(selection)) {
 
-         event.preventDefault()
 
-         const node = $getNodeByKey(nodeKey)
 
-         if ($isDecoratorNode(node)) {
 
-           if (command)
 
-             editor.dispatchCommand(command, undefined)
 
-           node.remove()
 
-           return true
 
-         }
 
-       }
 
-       return false
 
-     },
 
-     [isSelected, nodeKey, command, editor],
 
-   )
 
-   const handleSelect = useCallback((e: MouseEvent) => {
 
-     e.stopPropagation()
 
-     clearSelection()
 
-     setSelected(true)
 
-   }, [setSelected, clearSelection])
 
-   useEffect(() => {
 
-     const ele = ref.current
 
-     if (ele)
 
-       ele.addEventListener('click', handleSelect)
 
-     return () => {
 
-       if (ele)
 
-         ele.removeEventListener('click', handleSelect)
 
-     }
 
-   }, [handleSelect])
 
-   useEffect(() => {
 
-     return mergeRegister(
 
-       editor.registerCommand(
 
-         KEY_DELETE_COMMAND,
 
-         handleDelete,
 
-         COMMAND_PRIORITY_LOW,
 
-       ),
 
-       editor.registerCommand(
 
-         KEY_BACKSPACE_COMMAND,
 
-         handleDelete,
 
-         COMMAND_PRIORITY_LOW,
 
-       ),
 
-     )
 
-   }, [editor, clearSelection, handleDelete])
 
-   return [ref, isSelected]
 
- }
 
- export type UseTriggerHandler = () => [RefObject<HTMLDivElement>, boolean, Dispatch<SetStateAction<boolean>>]
 
- export const useTrigger: UseTriggerHandler = () => {
 
-   const triggerRef = useRef<HTMLDivElement>(null)
 
-   const [open, setOpen] = useState(false)
 
-   const handleOpen = useCallback((e: MouseEvent) => {
 
-     e.stopPropagation()
 
-     setOpen(v => !v)
 
-   }, [])
 
-   useEffect(() => {
 
-     const trigger = triggerRef.current
 
-     if (trigger)
 
-       trigger.addEventListener('click', handleOpen)
 
-     return () => {
 
-       if (trigger)
 
-         trigger.removeEventListener('click', handleOpen)
 
-     }
 
-   }, [handleOpen])
 
-   return [triggerRef, open, setOpen]
 
- }
 
- export function useLexicalTextEntity<T extends TextNode>(
 
-   getMatch: (text: string) => null | EntityMatch,
 
-   targetNode: Klass<T>,
 
-   createNode: (textNode: CustomTextNode) => T,
 
- ) {
 
-   const [editor] = useLexicalComposerContext()
 
-   useEffect(() => {
 
-     return mergeRegister(...registerLexicalTextEntity(editor, getMatch, targetNode, createNode))
 
-   }, [createNode, editor, getMatch, targetNode])
 
- }
 
- export type MenuTextMatch = {
 
-   leadOffset: number
 
-   matchingString: string
 
-   replaceableString: string
 
- }
 
- export type TriggerFn = (
 
-   text: string,
 
-   editor: LexicalEditor,
 
- ) => MenuTextMatch | null
 
- export const PUNCTUATION = '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;'
 
- export function useBasicTypeaheadTriggerMatch(
 
-   trigger: string,
 
-   { minLength = 1, maxLength = 75 }: { minLength?: number; maxLength?: number },
 
- ): TriggerFn {
 
-   return useCallback(
 
-     (text: string) => {
 
-       const validChars = `[${PUNCTUATION}\\s]`
 
-       const TypeaheadTriggerRegex = new RegExp(
 
-         '(.*)('
 
-           + `[${trigger}]`
 
-           + `((?:${validChars}){0,${maxLength}})`
 
-           + ')$',
 
-       )
 
-       const match = TypeaheadTriggerRegex.exec(text)
 
-       if (match !== null) {
 
-         const maybeLeadingWhitespace = match[1]
 
-         const matchingString = match[3]
 
-         if (matchingString.length >= minLength) {
 
-           return {
 
-             leadOffset: match.index + maybeLeadingWhitespace.length,
 
-             matchingString,
 
-             replaceableString: match[2],
 
-           }
 
-         }
 
-       }
 
-       return null
 
-     },
 
-     [maxLength, minLength, trigger],
 
-   )
 
- }
 
 
  |