hooks.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import {
  2. useCallback,
  3. useEffect,
  4. useState,
  5. } from 'react'
  6. import {
  7. $createParagraphNode,
  8. $getSelection,
  9. $isRangeSelection,
  10. $setSelection,
  11. COMMAND_PRIORITY_CRITICAL,
  12. FORMAT_TEXT_COMMAND,
  13. SELECTION_CHANGE_COMMAND,
  14. } from 'lexical'
  15. import {
  16. $getSelectionStyleValueForProperty,
  17. $patchStyleText,
  18. $setBlocksType,
  19. } from '@lexical/selection'
  20. import { INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list'
  21. import { mergeRegister } from '@lexical/utils'
  22. import {
  23. $isLinkNode,
  24. TOGGLE_LINK_COMMAND,
  25. } from '@lexical/link'
  26. import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
  27. import { useNoteEditorStore } from '../store'
  28. import { getSelectedNode } from '../utils'
  29. export const useCommand = () => {
  30. const [editor] = useLexicalComposerContext()
  31. const noteEditorStore = useNoteEditorStore()
  32. const handleCommand = useCallback((type: string) => {
  33. if (type === 'bold')
  34. editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')
  35. if (type === 'italic')
  36. editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')
  37. if (type === 'strikethrough')
  38. editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough')
  39. if (type === 'link') {
  40. editor.update(() => {
  41. const selection = $getSelection()
  42. if ($isRangeSelection(selection)) {
  43. const node = getSelectedNode(selection)
  44. const parent = node.getParent()
  45. const { setLinkAnchorElement } = noteEditorStore.getState()
  46. if ($isLinkNode(parent) || $isLinkNode(node)) {
  47. editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)
  48. setLinkAnchorElement()
  49. }
  50. else {
  51. editor.dispatchCommand(TOGGLE_LINK_COMMAND, '')
  52. setLinkAnchorElement(true)
  53. }
  54. }
  55. })
  56. }
  57. if (type === 'bullet') {
  58. const { selectedIsBullet } = noteEditorStore.getState()
  59. if (selectedIsBullet) {
  60. editor.update(() => {
  61. const selection = $getSelection()
  62. if ($isRangeSelection(selection))
  63. $setBlocksType(selection, () => $createParagraphNode())
  64. })
  65. }
  66. else {
  67. editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined)
  68. }
  69. }
  70. }, [editor, noteEditorStore])
  71. return {
  72. handleCommand,
  73. }
  74. }
  75. export const useFontSize = () => {
  76. const [editor] = useLexicalComposerContext()
  77. const [fontSize, setFontSize] = useState('12px')
  78. const [fontSizeSelectorShow, setFontSizeSelectorShow] = useState(false)
  79. const handleFontSize = useCallback((fontSize: string) => {
  80. editor.update(() => {
  81. const selection = $getSelection()
  82. if ($isRangeSelection(selection))
  83. $patchStyleText(selection, { 'font-size': fontSize })
  84. })
  85. }, [editor])
  86. const handleOpenFontSizeSelector = useCallback((newFontSizeSelectorShow: boolean) => {
  87. if (newFontSizeSelectorShow) {
  88. editor.update(() => {
  89. const selection = $getSelection()
  90. if ($isRangeSelection(selection))
  91. $setSelection(selection.clone())
  92. })
  93. }
  94. setFontSizeSelectorShow(newFontSizeSelectorShow)
  95. }, [editor])
  96. useEffect(() => {
  97. return mergeRegister(
  98. editor.registerUpdateListener(() => {
  99. editor.getEditorState().read(() => {
  100. const selection = $getSelection()
  101. if ($isRangeSelection(selection)) {
  102. const fontSize = $getSelectionStyleValueForProperty(selection, 'font-size', '12px')
  103. setFontSize(fontSize)
  104. }
  105. })
  106. }),
  107. editor.registerCommand(
  108. SELECTION_CHANGE_COMMAND,
  109. () => {
  110. const selection = $getSelection()
  111. if ($isRangeSelection(selection)) {
  112. const fontSize = $getSelectionStyleValueForProperty(selection, 'font-size', '12px')
  113. setFontSize(fontSize)
  114. }
  115. return false
  116. },
  117. COMMAND_PRIORITY_CRITICAL,
  118. ),
  119. )
  120. }, [editor])
  121. return {
  122. fontSize,
  123. handleFontSize,
  124. fontSizeSelectorShow,
  125. handleOpenFontSizeSelector,
  126. }
  127. }