@scottjgilbert/lexical-blog-editor 0.1.4 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/README.md +73 -67
  2. package/build/Editor.d.ts +8 -3
  3. package/build/Editor.d.ts.map +1 -1
  4. package/build/Editor.js +13 -8
  5. package/build/EditorExport.d.ts +4 -0
  6. package/build/EditorExport.d.ts.map +1 -0
  7. package/build/EditorExport.js +13 -0
  8. package/build/appSettings.d.ts +1 -1
  9. package/build/appSettings.js +1 -1
  10. package/build/buildHTMLConfig.d.ts +1 -1
  11. package/build/buildHTMLConfig.d.ts.map +1 -1
  12. package/build/buildHTMLConfig.js +35 -11
  13. package/build/context/FlashMessageContext.d.ts +2 -2
  14. package/build/context/FlashMessageContext.d.ts.map +1 -1
  15. package/build/context/FlashMessageContext.js +4 -3
  16. package/build/context/SharedHistoryContext.d.ts +3 -3
  17. package/build/context/SharedHistoryContext.d.ts.map +1 -1
  18. package/build/context/SharedHistoryContext.js +3 -2
  19. package/build/context/ToolbarContext.d.ts +1 -0
  20. package/build/context/ToolbarContext.d.ts.map +1 -1
  21. package/build/context/ToolbarContext.js +2 -0
  22. package/build/hooks/useModal.d.ts.map +1 -1
  23. package/build/hooks/useModal.js +1 -0
  24. package/build/hooks/useReport.d.ts +0 -7
  25. package/build/hooks/useReport.d.ts.map +1 -1
  26. package/build/hooks/useReport.js +1 -0
  27. package/build/index.css +283 -246
  28. package/build/index.d.ts +3 -3
  29. package/build/index.d.ts.map +1 -1
  30. package/build/index.js +2 -2
  31. package/build/nodes/CodeNode/CodeHighlightNode.d.ts +35 -0
  32. package/build/nodes/CodeNode/CodeHighlightNode.d.ts.map +1 -0
  33. package/build/nodes/CodeNode/CodeHighlightNode.js +88 -0
  34. package/build/nodes/CodeNode/CodeHighlighterShiki.d.ts +22 -0
  35. package/build/nodes/CodeNode/CodeHighlighterShiki.d.ts.map +1 -0
  36. package/build/nodes/CodeNode/CodeHighlighterShiki.js +644 -0
  37. package/build/nodes/CodeNode/CodeNode.d.ts +48 -0
  38. package/build/nodes/CodeNode/CodeNode.d.ts.map +1 -0
  39. package/build/nodes/CodeNode/CodeNode.js +367 -0
  40. package/build/nodes/CodeNode/FacadeShiki.d.ts +18 -0
  41. package/build/nodes/CodeNode/FacadeShiki.d.ts.map +1 -0
  42. package/build/nodes/CodeNode/FacadeShiki.js +159 -0
  43. package/build/nodes/CodeNode/FlatStructureUtils.d.ts +21 -0
  44. package/build/nodes/CodeNode/FlatStructureUtils.d.ts.map +1 -0
  45. package/build/nodes/CodeNode/FlatStructureUtils.js +85 -0
  46. package/build/nodes/CodeNode/invariant.d.ts +2 -0
  47. package/build/nodes/CodeNode/invariant.d.ts.map +1 -0
  48. package/build/nodes/CodeNode/invariant.js +6 -0
  49. package/build/nodes/DateTimeNode/DateTimeComponent.d.ts.map +1 -1
  50. package/build/nodes/DateTimeNode/DateTimeComponent.js +1 -0
  51. package/build/nodes/DateTimeNode/DateTimeNode.css +21 -0
  52. package/build/nodes/FigmaNode/FigmaNode.d.ts.map +1 -0
  53. package/build/nodes/FigmaNode/ServerFigmaNode.d.ts +21 -0
  54. package/build/nodes/FigmaNode/ServerFigmaNode.d.ts.map +1 -0
  55. package/build/nodes/FigmaNode/ServerFigmaNode.js +48 -0
  56. package/build/nodes/ImageComponent.d.ts.map +1 -1
  57. package/build/nodes/ImageComponent.js +1 -2
  58. package/build/nodes/ImageNode.d.ts +7 -7
  59. package/build/nodes/ImageNode.d.ts.map +1 -1
  60. package/build/nodes/ImageNode.js +30 -30
  61. package/build/nodes/LayoutContainerNode.d.ts +2 -2
  62. package/build/nodes/LayoutContainerNode.d.ts.map +1 -1
  63. package/build/nodes/LayoutContainerNode.js +10 -10
  64. package/build/nodes/PlaygroundNodes/PlaygroundNodes.d.ts.map +1 -0
  65. package/build/nodes/{PlaygroundNodes.js → PlaygroundNodes/PlaygroundNodes.js} +19 -21
  66. package/build/nodes/PlaygroundNodes/ServerPlaygroundNodes.d.ts +11 -0
  67. package/build/nodes/PlaygroundNodes/ServerPlaygroundNodes.d.ts.map +1 -0
  68. package/build/nodes/PlaygroundNodes/ServerPlaygroundNodes.js +65 -0
  69. package/build/nodes/TweetNode/ServerTweetNode.d.ts +20 -0
  70. package/build/nodes/TweetNode/ServerTweetNode.d.ts.map +1 -0
  71. package/build/nodes/TweetNode/ServerTweetNode.js +59 -0
  72. package/build/nodes/TweetNode/TweetNode.d.ts.map +1 -0
  73. package/build/nodes/YouTubeNode/ServerYouTubeNode.d.ts +21 -0
  74. package/build/nodes/YouTubeNode/ServerYouTubeNode.d.ts.map +1 -0
  75. package/build/nodes/YouTubeNode/ServerYouTubeNode.js +67 -0
  76. package/build/nodes/YouTubeNode/YouTubeNode.d.ts.map +1 -0
  77. package/build/plugins/ActionsPlugin/index.d.ts +0 -7
  78. package/build/plugins/ActionsPlugin/index.d.ts.map +1 -1
  79. package/build/plugins/ActionsPlugin/index.js +2 -1
  80. package/build/plugins/AutoEmbedPlugin/index.d.ts +2 -9
  81. package/build/plugins/AutoEmbedPlugin/index.d.ts.map +1 -1
  82. package/build/plugins/AutoEmbedPlugin/index.js +30 -29
  83. package/build/plugins/AutoLinkPlugin/index.d.ts +1 -1
  84. package/build/plugins/AutoLinkPlugin/index.d.ts.map +1 -1
  85. package/build/plugins/AutoLinkPlugin/index.js +3 -2
  86. package/build/plugins/CodeActionMenuPlugin/components/CopyButton/index.d.ts +1 -1
  87. package/build/plugins/CodeActionMenuPlugin/components/CopyButton/index.d.ts.map +1 -1
  88. package/build/plugins/CodeActionMenuPlugin/components/CopyButton/index.js +7 -6
  89. package/build/plugins/CodeActionMenuPlugin/components/PrettierButton/index.d.ts +2 -2
  90. package/build/plugins/CodeActionMenuPlugin/components/PrettierButton/index.d.ts.map +1 -1
  91. package/build/plugins/CodeActionMenuPlugin/components/PrettierButton/index.js +25 -24
  92. package/build/plugins/CodeActionMenuPlugin/index.d.ts +2 -9
  93. package/build/plugins/CodeActionMenuPlugin/index.d.ts.map +1 -1
  94. package/build/plugins/CodeActionMenuPlugin/index.js +22 -20
  95. package/build/plugins/CodeActionMenuPlugin/utils.d.ts.map +1 -1
  96. package/build/plugins/CodeActionMenuPlugin/utils.js +3 -2
  97. package/build/plugins/CodeHighlightPrismPlugin/index.d.ts +1 -1
  98. package/build/plugins/CodeHighlightPrismPlugin/index.d.ts.map +1 -1
  99. package/build/plugins/CodeHighlightPrismPlugin/index.js +4 -10
  100. package/build/plugins/CodeHighlightShikiPlugin/index.d.ts +1 -1
  101. package/build/plugins/CodeHighlightShikiPlugin/index.d.ts.map +1 -1
  102. package/build/plugins/CodeHighlightShikiPlugin/index.js +3 -3
  103. package/build/plugins/CollapsiblePlugin/Collapsible.css +17 -1
  104. package/build/plugins/CollapsiblePlugin/index.d.ts +1 -1
  105. package/build/plugins/CollapsiblePlugin/index.d.ts.map +1 -1
  106. package/build/plugins/CollapsiblePlugin/index.js +11 -10
  107. package/build/plugins/ComponentPickerPlugin/index.d.ts.map +1 -1
  108. package/build/plugins/ComponentPickerPlugin/index.js +3 -8
  109. package/build/plugins/ContextMenuPlugin/index.d.ts +1 -1
  110. package/build/plugins/ContextMenuPlugin/index.d.ts.map +1 -1
  111. package/build/plugins/ContextMenuPlugin/index.js +15 -14
  112. package/build/plugins/DateTimePlugin/index.d.ts +2 -2
  113. package/build/plugins/DateTimePlugin/index.d.ts.map +1 -1
  114. package/build/plugins/DateTimePlugin/index.js +8 -14
  115. package/build/plugins/DragDropPastePlugin/index.d.ts +0 -7
  116. package/build/plugins/DragDropPastePlugin/index.d.ts.map +1 -1
  117. package/build/plugins/DragDropPastePlugin/index.js +12 -11
  118. package/build/plugins/DraggableBlockPlugin/index.css +6 -0
  119. package/build/plugins/DraggableBlockPlugin/index.d.ts +2 -2
  120. package/build/plugins/DraggableBlockPlugin/index.d.ts.map +1 -1
  121. package/build/plugins/DraggableBlockPlugin/index.js +23 -22
  122. package/build/plugins/EmojiPickerPlugin/index.d.ts +0 -7
  123. package/build/plugins/EmojiPickerPlugin/index.d.ts.map +1 -1
  124. package/build/plugins/EmojiPickerPlugin/index.js +1 -0
  125. package/build/plugins/EmojisPlugin/index.d.ts +1 -8
  126. package/build/plugins/EmojisPlugin/index.d.ts.map +1 -1
  127. package/build/plugins/EmojisPlugin/index.js +10 -16
  128. package/build/plugins/EquationsPlugin/index.d.ts +3 -3
  129. package/build/plugins/EquationsPlugin/index.d.ts.map +1 -1
  130. package/build/plugins/EquationsPlugin/index.js +14 -10
  131. package/build/plugins/FigmaPlugin/index.d.ts +2 -2
  132. package/build/plugins/FigmaPlugin/index.d.ts.map +1 -1
  133. package/build/plugins/FigmaPlugin/index.js +8 -14
  134. package/build/plugins/FloatingLinkEditorPlugin/index.css +11 -0
  135. package/build/plugins/FloatingLinkEditorPlugin/index.d.ts +3 -3
  136. package/build/plugins/FloatingLinkEditorPlugin/index.d.ts.map +1 -1
  137. package/build/plugins/FloatingLinkEditorPlugin/index.js +28 -27
  138. package/build/plugins/FloatingTextFormatToolbarPlugin/index.css +15 -0
  139. package/build/plugins/FloatingTextFormatToolbarPlugin/index.d.ts.map +1 -1
  140. package/build/plugins/FloatingTextFormatToolbarPlugin/index.js +2 -1
  141. package/build/plugins/ImagesPlugin/index.d.ts +3 -3
  142. package/build/plugins/ImagesPlugin/index.d.ts.map +1 -1
  143. package/build/plugins/ImagesPlugin/index.js +38 -37
  144. package/build/plugins/KeywordsPlugin/index.d.ts +1 -8
  145. package/build/plugins/KeywordsPlugin/index.d.ts.map +1 -1
  146. package/build/plugins/KeywordsPlugin/index.js +6 -12
  147. package/build/plugins/LayoutPlugin/InsertLayoutDialog.d.ts +2 -2
  148. package/build/plugins/LayoutPlugin/InsertLayoutDialog.d.ts.map +1 -1
  149. package/build/plugins/LayoutPlugin/InsertLayoutDialog.js +10 -9
  150. package/build/plugins/LayoutPlugin/LayoutPlugin.d.ts +1 -1
  151. package/build/plugins/LayoutPlugin/LayoutPlugin.d.ts.map +1 -1
  152. package/build/plugins/LayoutPlugin/LayoutPlugin.js +8 -14
  153. package/build/plugins/LinkPlugin/index.d.ts.map +1 -1
  154. package/build/plugins/LinkPlugin/index.js +1 -0
  155. package/build/plugins/MarkdownShortcutPlugin/index.d.ts.map +1 -1
  156. package/build/plugins/MarkdownShortcutPlugin/index.js +1 -0
  157. package/build/plugins/MarkdownTransformers/index.d.ts +1 -1
  158. package/build/plugins/MarkdownTransformers/index.d.ts.map +1 -1
  159. package/build/plugins/MarkdownTransformers/index.js +25 -25
  160. package/build/plugins/PasteLogPlugin/index.d.ts.map +1 -1
  161. package/build/plugins/PasteLogPlugin/index.js +1 -0
  162. package/build/plugins/ShortcutsPlugin/index.d.ts +0 -7
  163. package/build/plugins/ShortcutsPlugin/index.d.ts.map +1 -1
  164. package/build/plugins/ShortcutsPlugin/index.js +1 -0
  165. package/build/plugins/SpeechToTextPlugin/index.d.ts +2 -2
  166. package/build/plugins/SpeechToTextPlugin/index.d.ts.map +1 -1
  167. package/build/plugins/SpeechToTextPlugin/index.js +7 -11
  168. package/build/plugins/TabFocusPlugin/index.d.ts +0 -7
  169. package/build/plugins/TabFocusPlugin/index.d.ts.map +1 -1
  170. package/build/plugins/TabFocusPlugin/index.js +6 -5
  171. package/build/plugins/TableActionMenuPlugin/index.d.ts +1 -8
  172. package/build/plugins/TableActionMenuPlugin/index.d.ts.map +1 -1
  173. package/build/plugins/TableActionMenuPlugin/index.js +41 -40
  174. package/build/plugins/TableCellResizer/index.d.ts +2 -2
  175. package/build/plugins/TableCellResizer/index.d.ts.map +1 -1
  176. package/build/plugins/TableCellResizer/index.js +43 -42
  177. package/build/plugins/TableHoverActionsPlugin/index.d.ts +1 -8
  178. package/build/plugins/TableHoverActionsPlugin/index.d.ts.map +1 -1
  179. package/build/plugins/TableHoverActionsPlugin/index.js +19 -18
  180. package/build/plugins/TableHoverActionsV2Plugin/index.d.ts.map +1 -1
  181. package/build/plugins/TableHoverActionsV2Plugin/index.js +1 -0
  182. package/build/plugins/TablePlugin.d.ts +2 -2
  183. package/build/plugins/TablePlugin.d.ts.map +1 -1
  184. package/build/plugins/TablePlugin.js +11 -10
  185. package/build/plugins/TableScrollShadowPlugin/index.d.ts +0 -7
  186. package/build/plugins/TableScrollShadowPlugin/index.d.ts.map +1 -1
  187. package/build/plugins/TableScrollShadowPlugin/index.js +9 -8
  188. package/build/plugins/TestRecorderPlugin/index.d.ts +1 -8
  189. package/build/plugins/TestRecorderPlugin/index.d.ts.map +1 -1
  190. package/build/plugins/TestRecorderPlugin/index.js +45 -44
  191. package/build/plugins/ToolbarPlugin/fontSize.d.ts +2 -2
  192. package/build/plugins/ToolbarPlugin/fontSize.d.ts.map +1 -1
  193. package/build/plugins/ToolbarPlugin/fontSize.js +19 -18
  194. package/build/plugins/ToolbarPlugin/index.d.ts.map +1 -1
  195. package/build/plugins/ToolbarPlugin/index.js +68 -60
  196. package/build/plugins/ToolbarPlugin/languages.d.ts +14 -0
  197. package/build/plugins/ToolbarPlugin/languages.d.ts.map +1 -0
  198. package/build/plugins/ToolbarPlugin/languages.js +185 -0
  199. package/build/plugins/ToolbarPlugin/utils.d.ts +2 -2
  200. package/build/plugins/ToolbarPlugin/utils.js +21 -21
  201. package/build/plugins/TwitterPlugin/index.d.ts +2 -2
  202. package/build/plugins/TwitterPlugin/index.d.ts.map +1 -1
  203. package/build/plugins/TwitterPlugin/index.js +8 -14
  204. package/build/plugins/YouTubePlugin/index.d.ts +2 -2
  205. package/build/plugins/YouTubePlugin/index.d.ts.map +1 -1
  206. package/build/plugins/YouTubePlugin/index.js +8 -14
  207. package/build/themes/PlaygroundEditorTheme.css +301 -33
  208. package/build/themes/ViewerTheme.css +899 -0
  209. package/build/{plugins/MentionsPlugin/index.d.ts → themes/ViewerTheme.d.ts} +5 -3
  210. package/build/themes/ViewerTheme.d.ts.map +1 -0
  211. package/build/themes/ViewerTheme.js +124 -0
  212. package/build/themes/ViewerThemeComplete.css +1043 -0
  213. package/build/ui/ColorPicker.d.ts +2 -2
  214. package/build/ui/ColorPicker.d.ts.map +1 -1
  215. package/build/ui/ColorPicker.js +47 -46
  216. package/build/ui/DropDown.d.ts.map +1 -1
  217. package/build/ui/DropDown.js +1 -0
  218. package/build/ui/FlashMessage.d.ts +3 -3
  219. package/build/ui/FlashMessage.d.ts.map +1 -1
  220. package/build/ui/FlashMessage.js +3 -2
  221. package/build/ui/ImageResizer.d.ts +3 -3
  222. package/build/ui/ImageResizer.d.ts.map +1 -1
  223. package/build/ui/ImageResizer.js +20 -19
  224. package/build/ui/KatexEquationAlterer.css +3 -1
  225. package/build/ui/KatexEquationAlterer.d.ts.map +1 -1
  226. package/build/ui/KatexEquationAlterer.js +1 -0
  227. package/build/ui/KatexRenderer.d.ts.map +1 -1
  228. package/build/ui/KatexRenderer.js +1 -0
  229. package/build/ui/Modal.d.ts.map +1 -1
  230. package/build/ui/Modal.js +1 -0
  231. package/build/ui/Switch.d.ts +2 -2
  232. package/build/ui/Switch.d.ts.map +1 -1
  233. package/build/ui/Switch.js +3 -2
  234. package/build/ui/TextInput.d.ts.map +1 -1
  235. package/build/ui/TextInput.js +1 -0
  236. package/build/utils/ServerBlockWithAlignableContents.d.ts +22 -0
  237. package/build/utils/ServerBlockWithAlignableContents.d.ts.map +1 -0
  238. package/build/utils/ServerBlockWithAlignableContents.js +6 -0
  239. package/build/utils/focusUtils.d.ts.map +1 -1
  240. package/build/utils/focusUtils.js +4 -3
  241. package/build/utils/getDOMRangeRect.d.ts.map +1 -1
  242. package/build/utils/getDOMRangeRect.js +1 -0
  243. package/build/utils/setFloatingElemPosition.d.ts.map +1 -1
  244. package/build/utils/setFloatingElemPosition.js +5 -4
  245. package/build/utils/swipe.d.ts +0 -7
  246. package/build/utils/swipe.d.ts.map +1 -1
  247. package/build/utils/swipe.js +5 -11
  248. package/build/viewer/Viewer.d.ts +18 -0
  249. package/build/viewer/Viewer.d.ts.map +1 -0
  250. package/build/viewer/Viewer.js +105 -0
  251. package/build/viewer/client.d.ts +18 -0
  252. package/build/viewer/client.d.ts.map +1 -0
  253. package/build/viewer/client.js +97 -0
  254. package/build/viewer/index.d.ts +4 -0
  255. package/build/viewer/index.d.ts.map +1 -0
  256. package/build/viewer/index.js +2 -0
  257. package/package.json +58 -36
  258. package/build/collaboration.d.ts +0 -12
  259. package/build/collaboration.d.ts.map +0 -1
  260. package/build/collaboration.js +0 -32
  261. package/build/nodes/FigmaNode.d.ts.map +0 -1
  262. package/build/nodes/PageBreakNode/index.css +0 -64
  263. package/build/nodes/PageBreakNode/index.d.ts +0 -25
  264. package/build/nodes/PageBreakNode/index.d.ts.map +0 -1
  265. package/build/nodes/PageBreakNode/index.js +0 -83
  266. package/build/nodes/PlaygroundNodes.d.ts.map +0 -1
  267. package/build/nodes/PollComponent.d.ts +0 -17
  268. package/build/nodes/PollComponent.d.ts.map +0 -1
  269. package/build/nodes/PollComponent.js +0 -85
  270. package/build/nodes/PollNode.css +0 -165
  271. package/build/nodes/PollNode.d.ts +0 -51
  272. package/build/nodes/PollNode.d.ts.map +0 -1
  273. package/build/nodes/PollNode.js +0 -153
  274. package/build/nodes/StickyComponent.d.ts +0 -18
  275. package/build/nodes/StickyComponent.d.ts.map +0 -1
  276. package/build/nodes/StickyComponent.js +0 -155
  277. package/build/nodes/StickyNode.css +0 -37
  278. package/build/nodes/StickyNode.d.ts +0 -39
  279. package/build/nodes/StickyNode.d.ts.map +0 -1
  280. package/build/nodes/StickyNode.js +0 -66
  281. package/build/nodes/TweetNode.d.ts.map +0 -1
  282. package/build/nodes/YouTubeNode.d.ts.map +0 -1
  283. package/build/plugins/DocsPlugin/index.d.ts +0 -10
  284. package/build/plugins/DocsPlugin/index.d.ts.map +0 -1
  285. package/build/plugins/DocsPlugin/index.js +0 -4
  286. package/build/plugins/MaxLengthPlugin/index.d.ts +0 -11
  287. package/build/plugins/MaxLengthPlugin/index.d.ts.map +0 -1
  288. package/build/plugins/MaxLengthPlugin/index.js +0 -44
  289. package/build/plugins/MentionsPlugin/index.d.ts.map +0 -1
  290. package/build/plugins/MentionsPlugin/index.js +0 -562
  291. package/build/plugins/PageBreakPlugin/index.d.ts +0 -12
  292. package/build/plugins/PageBreakPlugin/index.d.ts.map +0 -1
  293. package/build/plugins/PageBreakPlugin/index.js +0 -34
  294. package/build/plugins/StickyPlugin/index.d.ts +0 -10
  295. package/build/plugins/StickyPlugin/index.d.ts.map +0 -1
  296. package/build/plugins/StickyPlugin/index.js +0 -19
  297. package/build/plugins/TreeViewPlugin/index.d.ts +0 -10
  298. package/build/plugins/TreeViewPlugin/index.d.ts.map +0 -1
  299. package/build/plugins/TreeViewPlugin/index.js +0 -7
  300. package/build/plugins/TypingPerfPlugin/index.d.ts +0 -10
  301. package/build/plugins/TypingPerfPlugin/index.d.ts.map +0 -1
  302. package/build/plugins/TypingPerfPlugin/index.js +0 -100
  303. package/build/plugins/VersionsPlugin/index.css +0 -57
  304. package/build/plugins/VersionsPlugin/index.d.ts +0 -14
  305. package/build/plugins/VersionsPlugin/index.d.ts.map +0 -1
  306. package/build/plugins/VersionsPlugin/index.js +0 -147
  307. /package/build/nodes/{FigmaNode.d.ts → FigmaNode/FigmaNode.d.ts} +0 -0
  308. /package/build/nodes/{FigmaNode.js → FigmaNode/FigmaNode.js} +0 -0
  309. /package/build/nodes/{PlaygroundNodes.d.ts → PlaygroundNodes/PlaygroundNodes.d.ts} +0 -0
  310. /package/build/nodes/{TweetNode.d.ts → TweetNode/TweetNode.d.ts} +0 -0
  311. /package/build/nodes/{TweetNode.js → TweetNode/TweetNode.js} +0 -0
  312. /package/build/nodes/{YouTubeNode.d.ts → YouTubeNode/YouTubeNode.d.ts} +0 -0
  313. /package/build/nodes/{YouTubeNode.js → YouTubeNode/YouTubeNode.js} +0 -0
@@ -0,0 +1,644 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import { $getCodeLineDirection, $getEndOfCodeInLine, $getFirstCodeNodeOfLine, $getLastCodeNodeOfLine, $getStartOfCodeInLine, CodeExtension, DEFAULT_CODE_LANGUAGE, } from "@lexical/code";
9
+ import { CodeNode, $isCodeNode } from "./CodeNode";
10
+ import { CodeHighlightNode, $isCodeHighlightNode } from "./CodeHighlightNode";
11
+ import { mergeRegister } from "@lexical/utils";
12
+ import { $createLineBreakNode, $createPoint, $createTabNode, $createTextNode, $getCaretRange, $getCaretRangeInDirection, $getNodeByKey, $getSelection, $getSiblingCaret, $getTextPointCaret, $insertNodes, $isLineBreakNode, $isRangeSelection, $isTabNode, $isTextNode, $normalizeCaret, $setSelectionFromCaretRange, COMMAND_PRIORITY_LOW, defineExtension, INDENT_CONTENT_COMMAND, INSERT_TAB_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_TAB_COMMAND, MOVE_TO_END, MOVE_TO_START, OUTDENT_CONTENT_COMMAND, safeCast, TextNode, } from "lexical";
13
+ import invariant from "./invariant";
14
+ import { $getHighlightNodes, isCodeLanguageLoaded, isCodeThemeLoaded, loadCodeLanguage, loadCodeTheme, } from "./FacadeShiki";
15
+ const DEFAULT_CODE_THEME = "one-light";
16
+ export const ShikiTokenizer = {
17
+ $tokenize(codeNode, language) {
18
+ return $getHighlightNodes(codeNode, language || this.defaultLanguage);
19
+ },
20
+ defaultLanguage: DEFAULT_CODE_LANGUAGE,
21
+ defaultTheme: DEFAULT_CODE_THEME,
22
+ };
23
+ function $textNodeTransform(node, editor, tokenizer) {
24
+ // Since CodeNode has flat children structure we only need to check
25
+ // if node's parent is a code node and run highlighting if so
26
+ const parentNode = node.getParent();
27
+ if ($isCodeNode(parentNode)) {
28
+ codeNodeTransform(parentNode, editor, tokenizer);
29
+ }
30
+ else if ($isCodeHighlightNode(node)) {
31
+ // When code block converted into paragraph or other element
32
+ // code highlight nodes converted back to normal text
33
+ node.replace($createTextNode(node.__text));
34
+ }
35
+ }
36
+ function updateCodeGutter(node, editor) {
37
+ const codeElement = editor.getElementByKey(node.getKey());
38
+ if (codeElement === null) {
39
+ return;
40
+ }
41
+ const children = node.getChildren();
42
+ const childrenLength = children.length;
43
+ // @ts-ignore: internal field
44
+ if (childrenLength === codeElement.__cachedChildrenLength) {
45
+ // Avoid updating the attribute if the children length hasn't changed.
46
+ return;
47
+ }
48
+ // @ts-ignore:: internal field
49
+ codeElement.__cachedChildrenLength = childrenLength;
50
+ let gutter = "1";
51
+ let count = 1;
52
+ for (let i = 0; i < childrenLength; i++) {
53
+ if ($isLineBreakNode(children[i])) {
54
+ gutter += "\n" + ++count;
55
+ }
56
+ }
57
+ codeElement.setAttribute("data-gutter", gutter);
58
+ }
59
+ // Using `skipTransforms` to prevent extra transforms since reformatting the code
60
+ // will not affect code block content itself.
61
+ //
62
+ // Using extra cache (`nodesCurrentlyHighlighting`) since both CodeNode and CodeHighlightNode
63
+ // transforms might be called at the same time (e.g. new CodeHighlight node inserted) and
64
+ // in both cases we'll rerun whole reformatting over CodeNode, which is redundant.
65
+ // Especially when pasting code into CodeBlock.
66
+ const nodesCurrentlyHighlighting = new Set();
67
+ function codeNodeTransform(node, editor, tokenizer) {
68
+ const nodeKey = node.getKey();
69
+ // When new code block inserted it might not have language selected
70
+ let language = node.getLanguage();
71
+ if (!language) {
72
+ language = tokenizer.defaultLanguage;
73
+ node.setLanguage(language);
74
+ }
75
+ let theme = node.getTheme();
76
+ if (!theme) {
77
+ theme = tokenizer.defaultTheme;
78
+ node.setTheme(theme);
79
+ }
80
+ // dynamic import of themes
81
+ let inFlight = false;
82
+ if (!isCodeThemeLoaded(theme)) {
83
+ loadCodeTheme(theme, editor, nodeKey);
84
+ inFlight = true;
85
+ }
86
+ // dynamic import of languages
87
+ if (isCodeLanguageLoaded(language)) {
88
+ if (!node.getIsSyntaxHighlightSupported()) {
89
+ node.setIsSyntaxHighlightSupported(true);
90
+ }
91
+ }
92
+ else {
93
+ if (node.getIsSyntaxHighlightSupported()) {
94
+ node.setIsSyntaxHighlightSupported(false);
95
+ }
96
+ loadCodeLanguage(language, editor, nodeKey);
97
+ inFlight = true;
98
+ }
99
+ if (inFlight) {
100
+ return;
101
+ }
102
+ if (nodesCurrentlyHighlighting.has(nodeKey)) {
103
+ return;
104
+ }
105
+ nodesCurrentlyHighlighting.add(nodeKey);
106
+ // Using nested update call to pass `skipTransforms` since we don't want
107
+ // each individual CodeHighlightNode to be transformed again as it's already
108
+ // in its final state
109
+ editor.update(() => {
110
+ $updateAndRetainSelection(nodeKey, () => {
111
+ const currentNode = $getNodeByKey(nodeKey);
112
+ if (!$isCodeNode(currentNode) || !currentNode.isAttached()) {
113
+ return false;
114
+ }
115
+ const lang = currentNode.getLanguage() || tokenizer.defaultLanguage;
116
+ const highlightNodes = tokenizer.$tokenize(currentNode, lang);
117
+ const diffRange = getDiffRange(currentNode.getChildren(), highlightNodes);
118
+ const { from, to, nodesForReplacement } = diffRange;
119
+ if (from !== to || nodesForReplacement.length) {
120
+ node.splice(from, to - from, nodesForReplacement);
121
+ return true;
122
+ }
123
+ return false;
124
+ });
125
+ }, {
126
+ onUpdate: () => {
127
+ nodesCurrentlyHighlighting.delete(nodeKey);
128
+ },
129
+ skipTransforms: true,
130
+ });
131
+ }
132
+ // Wrapping update function into selection retainer, that tries to keep cursor at the same
133
+ // position as before.
134
+ function $updateAndRetainSelection(nodeKey, updateFn) {
135
+ const node = $getNodeByKey(nodeKey);
136
+ if (!$isCodeNode(node) || !node.isAttached()) {
137
+ return;
138
+ }
139
+ const selection = $getSelection();
140
+ // If it's not range selection (or null selection) there's no need to change it,
141
+ // but we can still run highlighting logic
142
+ if (!$isRangeSelection(selection)) {
143
+ updateFn();
144
+ return;
145
+ }
146
+ const anchor = selection.anchor;
147
+ const anchorOffset = anchor.offset;
148
+ const isNewLineAnchor = anchor.type === "element" &&
149
+ $isLineBreakNode(node.getChildAtIndex(anchor.offset - 1));
150
+ let textOffset = 0;
151
+ // Calculating previous text offset (all text node prior to anchor + anchor own text offset)
152
+ if (!isNewLineAnchor) {
153
+ const anchorNode = anchor.getNode();
154
+ textOffset =
155
+ anchorOffset +
156
+ anchorNode.getPreviousSiblings().reduce((offset, _node) => {
157
+ return offset + _node.getTextContentSize();
158
+ }, 0);
159
+ }
160
+ const hasChanges = updateFn();
161
+ if (!hasChanges) {
162
+ return;
163
+ }
164
+ // Non-text anchors only happen for line breaks, otherwise
165
+ // selection will be within text node (code highlight node)
166
+ if (isNewLineAnchor) {
167
+ anchor.getNode().select(anchorOffset, anchorOffset);
168
+ return;
169
+ }
170
+ // If it was non-element anchor then we walk through child nodes
171
+ // and looking for a position of original text offset
172
+ node.getChildren().some((_node) => {
173
+ const isText = $isTextNode(_node);
174
+ if (isText || $isLineBreakNode(_node)) {
175
+ const textContentSize = _node.getTextContentSize();
176
+ if (isText && textContentSize >= textOffset) {
177
+ _node.select(textOffset, textOffset);
178
+ return true;
179
+ }
180
+ textOffset -= textContentSize;
181
+ }
182
+ return false;
183
+ });
184
+ }
185
+ // Finds minimal diff range between two nodes lists. It returns from/to range boundaries of prevNodes
186
+ // that needs to be replaced with `nodes` (subset of nextNodes) to make prevNodes equal to nextNodes.
187
+ function getDiffRange(prevNodes, nextNodes) {
188
+ let leadingMatch = 0;
189
+ while (leadingMatch < prevNodes.length) {
190
+ if (!isEqual(prevNodes[leadingMatch], nextNodes[leadingMatch])) {
191
+ break;
192
+ }
193
+ leadingMatch++;
194
+ }
195
+ const prevNodesLength = prevNodes.length;
196
+ const nextNodesLength = nextNodes.length;
197
+ const maxTrailingMatch = Math.min(prevNodesLength, nextNodesLength) - leadingMatch;
198
+ let trailingMatch = 0;
199
+ while (trailingMatch < maxTrailingMatch) {
200
+ trailingMatch++;
201
+ if (!isEqual(prevNodes[prevNodesLength - trailingMatch], nextNodes[nextNodesLength - trailingMatch])) {
202
+ trailingMatch--;
203
+ break;
204
+ }
205
+ }
206
+ const from = leadingMatch;
207
+ const to = prevNodesLength - trailingMatch;
208
+ const nodesForReplacement = nextNodes.slice(leadingMatch, nextNodesLength - trailingMatch);
209
+ return {
210
+ from,
211
+ nodesForReplacement,
212
+ to,
213
+ };
214
+ }
215
+ function isEqual(nodeA, nodeB) {
216
+ // Only checking for code highlight nodes, tabs and linebreaks. If it's regular text node
217
+ // returning false so that it's transformed into code highlight node
218
+ return (($isCodeHighlightNode(nodeA) &&
219
+ $isCodeHighlightNode(nodeB) &&
220
+ nodeA.__text === nodeB.__text &&
221
+ nodeA.__highlightType === nodeB.__highlightType &&
222
+ nodeA.__style === nodeB.__style) ||
223
+ ($isTabNode(nodeA) && $isTabNode(nodeB)) ||
224
+ ($isLineBreakNode(nodeA) && $isLineBreakNode(nodeB)));
225
+ }
226
+ /**
227
+ * Returns a boolean.
228
+ * Check that the selection span is within a single CodeNode.
229
+ * This is used to guard against executing handlers that can only be
230
+ * applied in a single CodeNode context
231
+ */
232
+ function $isSelectionInCode(selection) {
233
+ if (!$isRangeSelection(selection)) {
234
+ return false;
235
+ }
236
+ const anchorNode = selection.anchor.getNode();
237
+ const maybeAnchorCodeNode = $isCodeNode(anchorNode)
238
+ ? anchorNode
239
+ : anchorNode.getParent();
240
+ const focusNode = selection.focus.getNode();
241
+ const maybeFocusCodeNode = $isCodeNode(focusNode)
242
+ ? focusNode
243
+ : focusNode.getParent();
244
+ return ($isCodeNode(maybeAnchorCodeNode) &&
245
+ maybeAnchorCodeNode.is(maybeFocusCodeNode));
246
+ }
247
+ /**
248
+ * Returns an Array of code lines
249
+ * Take the sequence of LineBreakNode | TabNode | CodeHighlightNode forming
250
+ * the selection and split it by LineBreakNode.
251
+ * If the selection ends at the start of the last line, it is considered empty.
252
+ * Empty lines are discarded.
253
+ */
254
+ function $getCodeLines(selection) {
255
+ const nodes = selection.getNodes();
256
+ const lines = [];
257
+ if (nodes.length === 1 && $isCodeNode(nodes[0])) {
258
+ return lines;
259
+ }
260
+ let lastLine = [];
261
+ for (let i = 0; i < nodes.length; i++) {
262
+ const node = nodes[i];
263
+ invariant($isCodeHighlightNode(node) || $isTabNode(node) || $isLineBreakNode(node), "Expected selection to be inside CodeBlock and consisting of CodeHighlightNode, TabNode and LineBreakNode");
264
+ if ($isLineBreakNode(node)) {
265
+ if (lastLine.length > 0) {
266
+ lines.push(lastLine);
267
+ lastLine = [];
268
+ }
269
+ }
270
+ else {
271
+ lastLine.push(node);
272
+ }
273
+ }
274
+ if (lastLine.length > 0) {
275
+ const selectionEnd = selection.isBackward()
276
+ ? selection.anchor
277
+ : selection.focus;
278
+ // Discard the last line if the selection ends exactly at the
279
+ // start of the line (no real selection)
280
+ const lastPoint = $createPoint(lastLine[0].getKey(), 0, "text");
281
+ if (!selectionEnd.is(lastPoint)) {
282
+ lines.push(lastLine);
283
+ }
284
+ }
285
+ return lines;
286
+ }
287
+ function $handleTab(shiftKey) {
288
+ const selection = $getSelection();
289
+ if (!$isRangeSelection(selection) || !$isSelectionInCode(selection)) {
290
+ return null;
291
+ }
292
+ const indentOrOutdent = !shiftKey
293
+ ? INDENT_CONTENT_COMMAND
294
+ : OUTDENT_CONTENT_COMMAND;
295
+ const tabOrOutdent = !shiftKey ? INSERT_TAB_COMMAND : OUTDENT_CONTENT_COMMAND;
296
+ const anchor = selection.anchor;
297
+ const focus = selection.focus;
298
+ // 1. early decision when there is no real selection
299
+ if (anchor.is(focus)) {
300
+ return tabOrOutdent;
301
+ }
302
+ // 2. If only empty lines or multiple non-empty lines are selected: indent/outdent
303
+ const codeLines = $getCodeLines(selection);
304
+ if (codeLines.length !== 1) {
305
+ return indentOrOutdent;
306
+ }
307
+ const codeLine = codeLines[0];
308
+ const codeLineLength = codeLine.length;
309
+ invariant(codeLineLength !== 0, "$getCodeLines only extracts non-empty lines");
310
+ // Take into account the direction of the selection
311
+ let selectionFirst;
312
+ let selectionLast;
313
+ if (selection.isBackward()) {
314
+ selectionFirst = focus;
315
+ selectionLast = anchor;
316
+ }
317
+ else {
318
+ selectionFirst = anchor;
319
+ selectionLast = focus;
320
+ }
321
+ // find boundary elements of the line
322
+ // since codeLine only contains TabNode | CodeHighlightNode
323
+ // the result of these functions should is of Type TabNode | CodeHighlightNode
324
+ const firstOfLine = $getFirstCodeNodeOfLine(codeLine[0]);
325
+ const lastOfLine = $getLastCodeNodeOfLine(codeLine[0]);
326
+ const anchorOfLine = $createPoint(firstOfLine.getKey(), 0, "text");
327
+ const focusOfLine = $createPoint(lastOfLine.getKey(), lastOfLine.getTextContentSize(), "text");
328
+ // 3. multiline because selection started strictly before the line
329
+ if (selectionFirst.isBefore(anchorOfLine)) {
330
+ return indentOrOutdent;
331
+ }
332
+ // 4. multiline because the selection stops strictly after the line
333
+ if (focusOfLine.isBefore(selectionLast)) {
334
+ return indentOrOutdent;
335
+ }
336
+ // The selection if within the line.
337
+ // 4. If it does not touch both borders, it needs a tab
338
+ if (anchorOfLine.isBefore(selectionFirst) ||
339
+ selectionLast.isBefore(focusOfLine)) {
340
+ return tabOrOutdent;
341
+ }
342
+ // 5. Selection is matching a full line on non-empty code
343
+ return indentOrOutdent;
344
+ }
345
+ function $handleMultilineIndent(type) {
346
+ const selection = $getSelection();
347
+ if (!$isRangeSelection(selection) || !$isSelectionInCode(selection)) {
348
+ return false;
349
+ }
350
+ const codeLines = $getCodeLines(selection);
351
+ const codeLinesLength = codeLines.length;
352
+ // Special Indent case
353
+ // Selection is collapsed at the beginning of a line
354
+ if (codeLinesLength === 0 && selection.isCollapsed()) {
355
+ if (type === INDENT_CONTENT_COMMAND) {
356
+ selection.insertNodes([$createTabNode()]);
357
+ }
358
+ return true;
359
+ }
360
+ // Special Indent case
361
+ // Selection is matching only one LineBreak
362
+ if (codeLinesLength === 0 &&
363
+ type === INDENT_CONTENT_COMMAND &&
364
+ selection.getTextContent() === "\n") {
365
+ const tabNode = $createTabNode();
366
+ const lineBreakNode = $createLineBreakNode();
367
+ const direction = selection.isBackward() ? "previous" : "next";
368
+ selection.insertNodes([tabNode, lineBreakNode]);
369
+ $setSelectionFromCaretRange($getCaretRangeInDirection($getCaretRange($getTextPointCaret(tabNode, "next", 0), $normalizeCaret($getSiblingCaret(lineBreakNode, "next"))), direction));
370
+ return true;
371
+ }
372
+ // Indent Non Empty Lines
373
+ for (let i = 0; i < codeLinesLength; i++) {
374
+ const line = codeLines[i];
375
+ // a line here is never empty
376
+ if (line.length > 0) {
377
+ let firstOfLine = line[0];
378
+ // make sure to consider the first node on the first line
379
+ // because the line might not be fully selected
380
+ if (i === 0) {
381
+ firstOfLine = $getFirstCodeNodeOfLine(firstOfLine);
382
+ }
383
+ if (type === INDENT_CONTENT_COMMAND) {
384
+ const tabNode = $createTabNode();
385
+ firstOfLine.insertBefore(tabNode);
386
+ // First real code line may need selection adjustment
387
+ // when firstOfLine is at the selection boundary
388
+ if (i === 0) {
389
+ const anchorKey = selection.isBackward() ? "focus" : "anchor";
390
+ const anchorLine = $createPoint(firstOfLine.getKey(), 0, "text");
391
+ if (selection[anchorKey].is(anchorLine)) {
392
+ selection[anchorKey].set(tabNode.getKey(), 0, "text");
393
+ }
394
+ }
395
+ }
396
+ else if ($isTabNode(firstOfLine)) {
397
+ firstOfLine.remove();
398
+ }
399
+ }
400
+ }
401
+ return true;
402
+ }
403
+ function $handleShiftLines(type, event) {
404
+ // We only care about the alt+arrow keys
405
+ const selection = $getSelection();
406
+ if (!$isRangeSelection(selection)) {
407
+ return false;
408
+ }
409
+ // I'm not quite sure why, but it seems like calling anchor.getNode() collapses the selection here
410
+ // So first, get the anchor and the focus, then get their nodes
411
+ const { anchor, focus } = selection;
412
+ const anchorOffset = anchor.offset;
413
+ const focusOffset = focus.offset;
414
+ const anchorNode = anchor.getNode();
415
+ const focusNode = focus.getNode();
416
+ const arrowIsUp = type === KEY_ARROW_UP_COMMAND;
417
+ // Ensure the selection is within the codeblock
418
+ if (!$isSelectionInCode(selection) ||
419
+ !($isCodeHighlightNode(anchorNode) || $isTabNode(anchorNode)) ||
420
+ !($isCodeHighlightNode(focusNode) || $isTabNode(focusNode))) {
421
+ return false;
422
+ }
423
+ if (!event.altKey) {
424
+ // Handle moving selection out of the code block, given there are no
425
+ // siblings that can natively take the selection.
426
+ if (selection.isCollapsed()) {
427
+ const codeNode = anchorNode.getParentOrThrow();
428
+ if (arrowIsUp &&
429
+ anchorOffset === 0 &&
430
+ anchorNode.getPreviousSibling() === null) {
431
+ const codeNodeSibling = codeNode.getPreviousSibling();
432
+ if (codeNodeSibling === null) {
433
+ codeNode.selectPrevious();
434
+ event.preventDefault();
435
+ return true;
436
+ }
437
+ }
438
+ else if (!arrowIsUp &&
439
+ anchorOffset === anchorNode.getTextContentSize() &&
440
+ anchorNode.getNextSibling() === null) {
441
+ const codeNodeSibling = codeNode.getNextSibling();
442
+ if (codeNodeSibling === null) {
443
+ codeNode.selectNext();
444
+ event.preventDefault();
445
+ return true;
446
+ }
447
+ }
448
+ }
449
+ return false;
450
+ }
451
+ let start;
452
+ let end;
453
+ if (anchorNode.isBefore(focusNode)) {
454
+ start = $getFirstCodeNodeOfLine(anchorNode);
455
+ end = $getLastCodeNodeOfLine(focusNode);
456
+ }
457
+ else {
458
+ start = $getFirstCodeNodeOfLine(focusNode);
459
+ end = $getLastCodeNodeOfLine(anchorNode);
460
+ }
461
+ if (start == null || end == null) {
462
+ return false;
463
+ }
464
+ const range = start.getNodesBetween(end);
465
+ for (let i = 0; i < range.length; i++) {
466
+ const node = range[i];
467
+ if (!$isCodeHighlightNode(node) &&
468
+ !$isTabNode(node) &&
469
+ !$isLineBreakNode(node)) {
470
+ return false;
471
+ }
472
+ }
473
+ // After this point, we know the selection is within the codeblock. We may not be able to
474
+ // actually move the lines around, but we want to return true either way to prevent
475
+ // the event's default behavior
476
+ event.preventDefault();
477
+ event.stopPropagation(); // required to stop cursor movement under Firefox
478
+ const linebreak = arrowIsUp
479
+ ? start.getPreviousSibling()
480
+ : end.getNextSibling();
481
+ if (!$isLineBreakNode(linebreak)) {
482
+ return true;
483
+ }
484
+ const sibling = arrowIsUp
485
+ ? linebreak.getPreviousSibling()
486
+ : linebreak.getNextSibling();
487
+ if (sibling == null) {
488
+ return true;
489
+ }
490
+ const maybeInsertionPoint = $isCodeHighlightNode(sibling) ||
491
+ $isTabNode(sibling) ||
492
+ $isLineBreakNode(sibling)
493
+ ? arrowIsUp
494
+ ? $getFirstCodeNodeOfLine(sibling)
495
+ : $getLastCodeNodeOfLine(sibling)
496
+ : null;
497
+ let insertionPoint = maybeInsertionPoint != null ? maybeInsertionPoint : sibling;
498
+ linebreak.remove();
499
+ range.forEach((node) => node.remove());
500
+ if (type === KEY_ARROW_UP_COMMAND) {
501
+ range.forEach((node) => insertionPoint.insertBefore(node));
502
+ insertionPoint.insertBefore(linebreak);
503
+ }
504
+ else {
505
+ insertionPoint.insertAfter(linebreak);
506
+ insertionPoint = linebreak;
507
+ range.forEach((node) => {
508
+ insertionPoint.insertAfter(node);
509
+ insertionPoint = node;
510
+ });
511
+ }
512
+ selection.setTextNodeRange(anchorNode, anchorOffset, focusNode, focusOffset);
513
+ return true;
514
+ }
515
+ function $handleMoveTo(type, event) {
516
+ const selection = $getSelection();
517
+ if (!$isRangeSelection(selection)) {
518
+ return false;
519
+ }
520
+ const { anchor, focus } = selection;
521
+ const anchorNode = anchor.getNode();
522
+ const focusNode = focus.getNode();
523
+ const isMoveToStart = type === MOVE_TO_START;
524
+ // Ensure the selection is within the codeblock
525
+ if (!$isSelectionInCode(selection) ||
526
+ !($isCodeHighlightNode(anchorNode) || $isTabNode(anchorNode)) ||
527
+ !($isCodeHighlightNode(focusNode) || $isTabNode(focusNode))) {
528
+ return false;
529
+ }
530
+ const focusLineNode = focusNode;
531
+ const direction = $getCodeLineDirection(focusLineNode);
532
+ const moveToStart = direction === "rtl" ? !isMoveToStart : isMoveToStart;
533
+ if (moveToStart) {
534
+ const start = $getStartOfCodeInLine(focusLineNode, focus.offset);
535
+ if (start !== null) {
536
+ const { node, offset } = start;
537
+ if ($isLineBreakNode(node)) {
538
+ node.selectNext(0, 0);
539
+ }
540
+ else {
541
+ selection.setTextNodeRange(node, offset, node, offset);
542
+ }
543
+ }
544
+ else {
545
+ focusLineNode.getParentOrThrow().selectStart();
546
+ }
547
+ }
548
+ else {
549
+ const node = $getEndOfCodeInLine(focusLineNode);
550
+ node.select();
551
+ }
552
+ event.preventDefault();
553
+ event.stopPropagation();
554
+ return true;
555
+ }
556
+ export function registerCodeHighlighting(editor, tokenizer) {
557
+ if (!editor.hasNodes([CodeNode, CodeHighlightNode])) {
558
+ throw new Error("CodeHighlightPlugin: CodeNode or CodeHighlightNode not registered on editor");
559
+ }
560
+ if (tokenizer == null) {
561
+ tokenizer = ShikiTokenizer;
562
+ }
563
+ const registrations = [];
564
+ // Only register the mutation listener if not in headless mode
565
+ if (editor._headless !== true) {
566
+ registrations.push(editor.registerMutationListener(CodeNode, (mutations) => {
567
+ editor.getEditorState().read(() => {
568
+ for (const [key, type] of mutations) {
569
+ if (type !== "destroyed") {
570
+ const node = $getNodeByKey(key);
571
+ if (node !== null) {
572
+ updateCodeGutter(node, editor);
573
+ }
574
+ }
575
+ }
576
+ });
577
+ }, { skipInitialization: false }));
578
+ }
579
+ // Add the rest of the registrations
580
+ registrations.push(editor.registerNodeTransform(CodeNode, (node) => codeNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(TextNode, (node) => $textNodeTransform(node, editor, tokenizer)), editor.registerNodeTransform(CodeHighlightNode, (node) => $textNodeTransform(node, editor, tokenizer)), editor.registerCommand(KEY_TAB_COMMAND, (event) => {
581
+ const command = $handleTab(event.shiftKey);
582
+ if (command === null) {
583
+ return false;
584
+ }
585
+ event.preventDefault();
586
+ editor.dispatchCommand(command, undefined);
587
+ return true;
588
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(INSERT_TAB_COMMAND, () => {
589
+ const selection = $getSelection();
590
+ if (!$isSelectionInCode(selection)) {
591
+ return false;
592
+ }
593
+ $insertNodes([$createTabNode()]);
594
+ return true;
595
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(INDENT_CONTENT_COMMAND, (payload) => $handleMultilineIndent(INDENT_CONTENT_COMMAND), COMMAND_PRIORITY_LOW), editor.registerCommand(OUTDENT_CONTENT_COMMAND, (payload) => $handleMultilineIndent(OUTDENT_CONTENT_COMMAND), COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ARROW_UP_COMMAND, (event) => {
596
+ const selection = $getSelection();
597
+ if (!$isRangeSelection(selection)) {
598
+ return false;
599
+ }
600
+ const { anchor } = selection;
601
+ const anchorNode = anchor.getNode();
602
+ if (!$isSelectionInCode(selection)) {
603
+ return false;
604
+ }
605
+ // If at the start of a code block, prevent selection from moving out
606
+ if (selection.isCollapsed() &&
607
+ anchor.offset === 0 &&
608
+ anchorNode.getPreviousSibling() === null &&
609
+ $isCodeNode(anchorNode.getParentOrThrow())) {
610
+ event.preventDefault();
611
+ return true;
612
+ }
613
+ return $handleShiftLines(KEY_ARROW_UP_COMMAND, event);
614
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ARROW_DOWN_COMMAND, (event) => {
615
+ const selection = $getSelection();
616
+ if (!$isRangeSelection(selection)) {
617
+ return false;
618
+ }
619
+ const { anchor } = selection;
620
+ const anchorNode = anchor.getNode();
621
+ if (!$isSelectionInCode(selection)) {
622
+ return false;
623
+ }
624
+ // If at the end of a code block, prevent selection from moving out
625
+ if (selection.isCollapsed() &&
626
+ anchor.offset === anchorNode.getTextContentSize() &&
627
+ anchorNode.getNextSibling() === null &&
628
+ $isCodeNode(anchorNode.getParentOrThrow())) {
629
+ event.preventDefault();
630
+ return true;
631
+ }
632
+ return $handleShiftLines(KEY_ARROW_DOWN_COMMAND, event);
633
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(MOVE_TO_START, (event) => $handleMoveTo(MOVE_TO_START, event), COMMAND_PRIORITY_LOW), editor.registerCommand(MOVE_TO_END, (event) => $handleMoveTo(MOVE_TO_END, event), COMMAND_PRIORITY_LOW));
634
+ return mergeRegister(...registrations);
635
+ }
636
+ /**
637
+ * Add code highlighting support for code blocks with Shiki
638
+ */
639
+ export const CodeHighlighterShikiExtension = defineExtension({
640
+ config: safeCast(ShikiTokenizer),
641
+ dependencies: [CodeExtension],
642
+ name: "@lexical/code-shiki",
643
+ register: (editor, config) => registerCodeHighlighting(editor, config),
644
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import type { CodeHighlightNode } from "./CodeHighlightNode";
9
+ import type { DOMConversionMap, DOMExportOutput, EditorConfig, LexicalEditor, LexicalNode, LexicalUpdateJSON, NodeKey, ParagraphNode, RangeSelection, SerializedElementNode, Spread, TabNode } from "lexical";
10
+ import { ElementNode } from "lexical";
11
+ export type SerializedCodeNode = Spread<{
12
+ language: string | null | undefined;
13
+ theme?: string | undefined;
14
+ }, SerializedElementNode>;
15
+ export declare const DEFAULT_CODE_LANGUAGE = "javascript";
16
+ export declare const getDefaultCodeLanguage: () => string;
17
+ /** @noInheritDoc */
18
+ export declare class CodeNode extends ElementNode {
19
+ /** @internal */
20
+ __language: string | null | undefined;
21
+ /** @internal */
22
+ __theme: string | undefined;
23
+ /** @internal */
24
+ __isSyntaxHighlightSupported: boolean;
25
+ static getType(): string;
26
+ static clone(node: CodeNode): CodeNode;
27
+ constructor(language?: string | null | undefined, key?: NodeKey);
28
+ afterCloneFrom(prevNode: this): void;
29
+ createDOM(config: EditorConfig): HTMLElement;
30
+ updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean;
31
+ exportDOM(editor: LexicalEditor): DOMExportOutput;
32
+ static importDOM(): DOMConversionMap | null;
33
+ static importJSON(serializedNode: SerializedCodeNode): CodeNode;
34
+ updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedCodeNode>): this;
35
+ exportJSON(): SerializedCodeNode;
36
+ insertNewAfter(selection: RangeSelection, restoreSelection?: boolean): null | ParagraphNode | CodeHighlightNode | TabNode;
37
+ canIndent(): false;
38
+ collapseAtStart(): boolean;
39
+ setLanguage(language: string | null | undefined): this;
40
+ getLanguage(): string | null | undefined;
41
+ setIsSyntaxHighlightSupported(isSupported: boolean): this;
42
+ getIsSyntaxHighlightSupported(): boolean;
43
+ setTheme(theme: string | null | undefined): this;
44
+ getTheme(): string | undefined;
45
+ }
46
+ export declare function $createCodeNode(language?: string | null | undefined, theme?: string | null | undefined): CodeNode;
47
+ export declare function $isCodeNode(node: LexicalNode | null | undefined): node is CodeNode;
48
+ //# sourceMappingURL=CodeNode.d.ts.map