5htp-core 0.4.8 → 0.4.9

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 (187) hide show
  1. package/package.json +5 -1
  2. package/src/client/assets/css/components/table.less +2 -0
  3. package/src/client/components/Form.ts +1 -1
  4. package/src/client/components/button.tsx +2 -1
  5. package/src/client/components/containers/Popover/index.tsx +2 -2
  6. package/src/client/components/dropdown/index.tsx +16 -6
  7. package/src/client/components/input/Slider/index.tsx +0 -2
  8. package/src/client/components/inputv3/Rte/Editor.tsx +271 -0
  9. package/src/client/components/inputv3/Rte/ToolbarPlugin/BlockFormat.tsx +220 -0
  10. package/src/client/components/inputv3/Rte/ToolbarPlugin/ElementFormat.tsx +107 -0
  11. package/src/client/components/inputv3/Rte/ToolbarPlugin/index.tsx +768 -0
  12. package/src/client/components/inputv3/Rte/appSettings.ts +36 -0
  13. package/src/client/components/inputv3/Rte/context/FlashMessageContext.tsx +68 -0
  14. package/src/client/components/inputv3/Rte/context/SettingsContext.tsx +71 -0
  15. package/src/client/components/inputv3/Rte/context/SharedAutocompleteContext.tsx +71 -0
  16. package/src/client/components/inputv3/Rte/context/SharedHistoryContext.tsx +35 -0
  17. package/src/client/components/inputv3/Rte/currentEditor.ts +42 -0
  18. package/src/client/components/inputv3/Rte/hooks/useFlashMessage.tsx +16 -0
  19. package/src/client/components/inputv3/Rte/hooks/useReport.ts +67 -0
  20. package/src/client/components/inputv3/Rte/images/emoji/1F600.png +0 -0
  21. package/src/client/components/inputv3/Rte/images/emoji/1F641.png +0 -0
  22. package/src/client/components/inputv3/Rte/images/emoji/1F642.png +0 -0
  23. package/src/client/components/inputv3/Rte/images/emoji/2764.png +0 -0
  24. package/src/client/components/inputv3/Rte/images/emoji/LICENSE.md +5 -0
  25. package/src/client/components/inputv3/Rte/images/icons/draggable-block-menu.svg +1 -0
  26. package/src/client/components/inputv3/Rte/images/icons/prettier-error.svg +1 -0
  27. package/src/client/components/inputv3/Rte/images/icons/prettier.svg +1 -0
  28. package/src/client/components/inputv3/Rte/images/image/LICENSE.md +5 -0
  29. package/src/client/components/inputv3/Rte/images/image-broken.svg +4 -0
  30. package/src/client/components/inputv3/Rte/images/logo.svg +1 -0
  31. package/src/client/components/inputv3/Rte/index.tsx +63 -79
  32. package/src/client/components/inputv3/Rte/nodes/AutocompleteNode.tsx +119 -0
  33. package/src/client/components/inputv3/Rte/nodes/EmojiNode.tsx +102 -0
  34. package/src/client/components/inputv3/Rte/nodes/EquationComponent.tsx +141 -0
  35. package/src/client/components/inputv3/Rte/nodes/EquationNode.tsx +174 -0
  36. package/src/client/components/inputv3/Rte/nodes/FigmaNode.tsx +135 -0
  37. package/src/client/components/inputv3/Rte/nodes/ImageComponent.tsx +468 -0
  38. package/src/client/components/inputv3/Rte/nodes/ImageNode.css +43 -0
  39. package/src/client/components/inputv3/Rte/nodes/ImageNode.tsx +266 -0
  40. package/src/client/components/inputv3/Rte/nodes/InlineImageNode/InlineImageComponent.tsx +402 -0
  41. package/src/client/components/inputv3/Rte/nodes/InlineImageNode/InlineImageNode.css +94 -0
  42. package/src/client/components/inputv3/Rte/nodes/InlineImageNode/InlineImageNode.tsx +294 -0
  43. package/src/client/components/inputv3/Rte/nodes/KeywordNode.ts +67 -0
  44. package/src/client/components/inputv3/Rte/nodes/LayoutContainerNode.ts +137 -0
  45. package/src/client/components/inputv3/Rte/nodes/LayoutItemNode.ts +71 -0
  46. package/src/client/components/inputv3/Rte/nodes/MentionNode.ts +130 -0
  47. package/src/client/components/inputv3/Rte/nodes/PageBreakNode/index.css +62 -0
  48. package/src/client/components/inputv3/Rte/nodes/PageBreakNode/index.tsx +170 -0
  49. package/src/client/components/inputv3/Rte/nodes/PlaygroundNodes.ts +76 -0
  50. package/src/client/components/inputv3/Rte/nodes/PollComponent.tsx +249 -0
  51. package/src/client/components/inputv3/Rte/nodes/PollNode.css +187 -0
  52. package/src/client/components/inputv3/Rte/nodes/PollNode.tsx +209 -0
  53. package/src/client/components/inputv3/Rte/nodes/StickyComponent.tsx +261 -0
  54. package/src/client/components/inputv3/Rte/nodes/StickyNode.css +37 -0
  55. package/src/client/components/inputv3/Rte/nodes/StickyNode.tsx +150 -0
  56. package/src/client/components/inputv3/Rte/nodes/TweetNode.tsx +223 -0
  57. package/src/client/components/inputv3/Rte/nodes/YouTubeNode.tsx +184 -0
  58. package/src/client/components/inputv3/Rte/plugins/ActionsPlugin/index.tsx +334 -0
  59. package/src/client/components/inputv3/Rte/plugins/AutoEmbedPlugin/index.tsx +352 -0
  60. package/src/client/components/inputv3/Rte/plugins/AutoLinkPlugin/index.tsx +32 -0
  61. package/src/client/components/inputv3/Rte/plugins/AutocompletePlugin/index.tsx +2529 -0
  62. package/src/client/components/inputv3/Rte/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +70 -0
  63. package/src/client/components/inputv3/Rte/plugins/CodeActionMenuPlugin/components/PrettierButton/index.css +14 -0
  64. package/src/client/components/inputv3/Rte/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +156 -0
  65. package/src/client/components/inputv3/Rte/plugins/CodeActionMenuPlugin/index.css +54 -0
  66. package/src/client/components/inputv3/Rte/plugins/CodeActionMenuPlugin/index.tsx +190 -0
  67. package/src/client/components/inputv3/Rte/plugins/CodeActionMenuPlugin/utils.ts +33 -0
  68. package/src/client/components/inputv3/Rte/plugins/CodeHighlightPlugin/index.ts +21 -0
  69. package/src/client/components/inputv3/Rte/plugins/CollapsiblePlugin/Collapsible.css +57 -0
  70. package/src/client/components/inputv3/Rte/plugins/CollapsiblePlugin/CollapsibleContainerNode.ts +168 -0
  71. package/src/client/components/inputv3/Rte/plugins/CollapsiblePlugin/CollapsibleContentNode.ts +127 -0
  72. package/src/client/components/inputv3/Rte/plugins/CollapsiblePlugin/CollapsibleTitleNode.ts +152 -0
  73. package/src/client/components/inputv3/Rte/plugins/CollapsiblePlugin/CollapsibleUtils.ts +17 -0
  74. package/src/client/components/inputv3/Rte/plugins/CollapsiblePlugin/index.ts +284 -0
  75. package/src/client/components/inputv3/Rte/plugins/ComponentPickerPlugin/index.tsx +370 -0
  76. package/src/client/components/inputv3/Rte/plugins/ContextMenuPlugin/index.tsx +270 -0
  77. package/src/client/components/inputv3/Rte/plugins/DocsPlugin/index.tsx +20 -0
  78. package/src/client/components/inputv3/Rte/plugins/DragDropPastePlugin/index.ts +51 -0
  79. package/src/client/components/inputv3/Rte/plugins/DraggableBlockPlugin/index.css +36 -0
  80. package/src/client/components/inputv3/Rte/plugins/DraggableBlockPlugin/index.tsx +43 -0
  81. package/src/client/components/inputv3/Rte/plugins/EmojiPickerPlugin/index.tsx +198 -0
  82. package/src/client/components/inputv3/Rte/plugins/EmojisPlugin/index.ts +75 -0
  83. package/src/client/components/inputv3/Rte/plugins/EquationsPlugin/index.tsx +82 -0
  84. package/src/client/components/inputv3/Rte/plugins/FigmaPlugin/index.tsx +40 -0
  85. package/src/client/components/inputv3/Rte/plugins/FloatingLinkEditorPlugin/index.css +41 -0
  86. package/src/client/components/inputv3/Rte/plugins/FloatingLinkEditorPlugin/index.tsx +393 -0
  87. package/src/client/components/inputv3/Rte/plugins/FloatingTextFormatToolbarPlugin/index.css +141 -0
  88. package/src/client/components/inputv3/Rte/plugins/FloatingTextFormatToolbarPlugin/index.tsx +388 -0
  89. package/src/client/components/inputv3/Rte/plugins/ImagesPlugin/index.tsx +350 -0
  90. package/src/client/components/inputv3/Rte/plugins/InlineImagePlugin/index.tsx +336 -0
  91. package/src/client/components/inputv3/Rte/plugins/KeywordsPlugin/index.ts +56 -0
  92. package/src/client/components/inputv3/Rte/plugins/LayoutPlugin/InsertLayoutDialog.tsx +58 -0
  93. package/src/client/components/inputv3/Rte/plugins/LayoutPlugin/LayoutPlugin.tsx +219 -0
  94. package/src/client/components/inputv3/Rte/plugins/LinkPlugin/index.tsx +34 -0
  95. package/src/client/components/inputv3/Rte/plugins/ListMaxIndentLevelPlugin/index.ts +85 -0
  96. package/src/client/components/inputv3/Rte/plugins/MarkdownShortcutPlugin/index.tsx +16 -0
  97. package/src/client/components/inputv3/Rte/plugins/MarkdownTransformers/index.ts +324 -0
  98. package/src/client/components/inputv3/Rte/plugins/MaxLengthPlugin/index.tsx +53 -0
  99. package/src/client/components/inputv3/Rte/plugins/MentionsPlugin/index.tsx +696 -0
  100. package/src/client/components/inputv3/Rte/plugins/PageBreakPlugin/index.tsx +57 -0
  101. package/src/client/components/inputv3/Rte/plugins/PasteLogPlugin/index.tsx +54 -0
  102. package/src/client/components/inputv3/Rte/plugins/PollPlugin/index.tsx +86 -0
  103. package/src/client/components/inputv3/Rte/plugins/SpeechToTextPlugin/index.ts +125 -0
  104. package/src/client/components/inputv3/Rte/plugins/StickyPlugin/index.ts +22 -0
  105. package/src/client/components/inputv3/Rte/plugins/TabFocusPlugin/index.tsx +65 -0
  106. package/src/client/components/inputv3/Rte/plugins/TableActionMenuPlugin/index.tsx +773 -0
  107. package/src/client/components/inputv3/Rte/plugins/TableCellResizer/index.css +12 -0
  108. package/src/client/components/inputv3/Rte/plugins/TableCellResizer/index.tsx +436 -0
  109. package/src/client/components/inputv3/Rte/plugins/TableHoverActionsPlugin/index.tsx +287 -0
  110. package/src/client/components/inputv3/Rte/plugins/TableOfContentsPlugin/index.css +95 -0
  111. package/src/client/components/inputv3/Rte/plugins/TableOfContentsPlugin/index.tsx +197 -0
  112. package/src/client/components/inputv3/Rte/plugins/TablePlugin.tsx +178 -0
  113. package/src/client/components/inputv3/Rte/plugins/TestRecorderPlugin/index.tsx +468 -0
  114. package/src/client/components/inputv3/Rte/plugins/TreeViewPlugin/index.tsx +26 -0
  115. package/src/client/components/inputv3/Rte/plugins/TwitterPlugin/index.ts +41 -0
  116. package/src/client/components/inputv3/Rte/plugins/TypingPerfPlugin/index.ts +117 -0
  117. package/src/client/components/inputv3/Rte/plugins/YouTubePlugin/index.ts +41 -0
  118. package/src/client/components/inputv3/Rte/shared/canUseDOM.ts +4 -0
  119. package/src/client/components/inputv3/Rte/shared/caretFromPoint.ts +40 -0
  120. package/src/client/components/inputv3/Rte/shared/environment.ts +56 -0
  121. package/src/client/components/inputv3/Rte/shared/invariant.ts +26 -0
  122. package/src/client/components/inputv3/Rte/shared/normalizeClassNames.ts +21 -0
  123. package/src/client/components/inputv3/Rte/shared/react-test-utils.ts +18 -0
  124. package/src/client/components/inputv3/Rte/shared/reactPatches.ts +22 -0
  125. package/src/client/components/inputv3/Rte/shared/simpleDiffWithCursor.ts +49 -0
  126. package/src/client/components/inputv3/Rte/shared/useLayoutEffect.ts +19 -0
  127. package/src/client/components/inputv3/Rte/shared/warnOnlyOnce.ts +20 -0
  128. package/src/client/components/inputv3/Rte/style.less +30 -60
  129. package/src/client/components/inputv3/Rte/themes/CommentEditorTheme.css +13 -0
  130. package/src/client/components/inputv3/Rte/themes/CommentEditorTheme.ts +20 -0
  131. package/src/client/components/inputv3/Rte/themes/PlaygroundEditorTheme.css +447 -0
  132. package/src/client/components/inputv3/Rte/themes/PlaygroundEditorTheme.ts +120 -0
  133. package/src/client/components/inputv3/Rte/themes/StickyEditorTheme.css +13 -0
  134. package/src/client/components/inputv3/Rte/themes/StickyEditorTheme.ts +20 -0
  135. package/src/client/components/inputv3/Rte/ui/ColorPicker.css +88 -0
  136. package/src/client/components/inputv3/Rte/ui/ColorPicker.tsx +365 -0
  137. package/src/client/components/inputv3/Rte/ui/ContentEditable.css +44 -0
  138. package/src/client/components/inputv3/Rte/ui/ContentEditable.tsx +36 -0
  139. package/src/client/components/inputv3/Rte/ui/DropDown.tsx +259 -0
  140. package/src/client/components/inputv3/Rte/ui/DropdownColorPicker.tsx +41 -0
  141. package/src/client/components/inputv3/Rte/ui/EquationEditor.css +38 -0
  142. package/src/client/components/inputv3/Rte/ui/EquationEditor.tsx +56 -0
  143. package/src/client/components/inputv3/Rte/ui/FileInput.tsx +38 -0
  144. package/src/client/components/inputv3/Rte/ui/FlashMessage.css +28 -0
  145. package/src/client/components/inputv3/Rte/ui/FlashMessage.tsx +29 -0
  146. package/src/client/components/inputv3/Rte/ui/ImageResizer.tsx +316 -0
  147. package/src/client/components/inputv3/Rte/ui/Input.css +32 -0
  148. package/src/client/components/inputv3/Rte/ui/KatexRenderer.tsx +54 -0
  149. package/src/client/components/inputv3/Rte/ui/Switch.tsx +36 -0
  150. package/src/client/components/inputv3/Rte/utils/docSerialization.ts +77 -0
  151. package/src/client/components/inputv3/Rte/utils/emoji-list.ts +16615 -0
  152. package/src/client/components/inputv3/Rte/utils/getDOMRangeRect.ts +27 -0
  153. package/src/client/components/inputv3/Rte/utils/getSelectedNode.ts +27 -0
  154. package/src/client/components/inputv3/Rte/utils/guard.ts +10 -0
  155. package/src/client/components/inputv3/Rte/utils/isMobileWidth.ts +7 -0
  156. package/src/client/components/inputv3/Rte/utils/joinClasses.ts +13 -0
  157. package/src/client/components/inputv3/Rte/utils/setFloatingElemPosition.ts +51 -0
  158. package/src/client/components/inputv3/Rte/utils/setFloatingElemPositionForLinkEditor.ts +46 -0
  159. package/src/client/components/inputv3/Rte/utils/swipe.ts +127 -0
  160. package/src/client/components/inputv3/Rte/utils/url.ts +38 -0
  161. package/src/client/components/inputv3/base.tsx +8 -5
  162. package/src/client/components/inputv3/file/index.tsx +11 -5
  163. package/src/common/data/rte/nodes.ts +60 -9
  164. package/src/common/validation/index.ts +21 -2
  165. package/src/common/validation/schema.ts +42 -10
  166. package/src/common/validation/validator.ts +12 -4
  167. package/src/common/validation/validators.ts +82 -53
  168. package/src/server/services/router/http/multipart.ts +0 -1
  169. package/src/server/services/schema/index.ts +24 -2
  170. package/src/server/services/schema/request.ts +3 -2
  171. package/src/server/services/schema/rte.ts +110 -0
  172. package/src/{common/data/rte/index.ts → server/utils/rte.ts} +27 -16
  173. package/src/client/components/inputv3/Rte/ExampleTheme.tsx +0 -42
  174. package/src/client/components/inputv3/Rte/ToolbarPlugin.tsx +0 -167
  175. package/src/client/components/inputv3/Rte/icons/LICENSE.md +0 -5
  176. package/src/client/components/inputv3/Rte/icons/arrow-clockwise.svg +0 -4
  177. package/src/client/components/inputv3/Rte/icons/arrow-counterclockwise.svg +0 -4
  178. package/src/client/components/inputv3/Rte/icons/journal-text.svg +0 -5
  179. package/src/client/components/inputv3/Rte/icons/justify.svg +0 -3
  180. package/src/client/components/inputv3/Rte/icons/text-center.svg +0 -3
  181. package/src/client/components/inputv3/Rte/icons/text-left.svg +0 -3
  182. package/src/client/components/inputv3/Rte/icons/text-paragraph.svg +0 -3
  183. package/src/client/components/inputv3/Rte/icons/text-right.svg +0 -3
  184. package/src/client/components/inputv3/Rte/icons/type-bold.svg +0 -3
  185. package/src/client/components/inputv3/Rte/icons/type-italic.svg +0 -3
  186. package/src/client/components/inputv3/Rte/icons/type-strikethrough.svg +0 -3
  187. package/src/client/components/inputv3/Rte/icons/type-underline.svg +0 -3
@@ -0,0 +1,57 @@
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 {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
9
+ import {$insertNodeToNearestRoot, mergeRegister} from '@lexical/utils';
10
+ import {
11
+ $getSelection,
12
+ $isRangeSelection,
13
+ COMMAND_PRIORITY_EDITOR,
14
+ createCommand,
15
+ LexicalCommand,
16
+ } from 'lexical';
17
+ import {useEffect} from 'react';
18
+
19
+ import {$createPageBreakNode, PageBreakNode} from '../../nodes/PageBreakNode';
20
+
21
+ export const INSERT_PAGE_BREAK: LexicalCommand<undefined> = createCommand();
22
+
23
+ export default function PageBreakPlugin(): JSX.Element | null {
24
+ const [editor] = useLexicalComposerContext();
25
+
26
+ useEffect(() => {
27
+ if (!editor.hasNodes([PageBreakNode])) {
28
+ throw new Error(
29
+ 'PageBreakPlugin: PageBreakNode is not registered on editor',
30
+ );
31
+ }
32
+
33
+ return mergeRegister(
34
+ editor.registerCommand(
35
+ INSERT_PAGE_BREAK,
36
+ () => {
37
+ const selection = $getSelection();
38
+
39
+ if (!$isRangeSelection(selection)) {
40
+ return false;
41
+ }
42
+
43
+ const focusNode = selection.focus.getNode();
44
+ if (focusNode !== null) {
45
+ const pgBreak = $createPageBreakNode();
46
+ $insertNodeToNearestRoot(pgBreak);
47
+ }
48
+
49
+ return true;
50
+ },
51
+ COMMAND_PRIORITY_EDITOR,
52
+ ),
53
+ );
54
+ }, [editor]);
55
+
56
+ return null;
57
+ }
@@ -0,0 +1,54 @@
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
+
9
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
10
+ import {COMMAND_PRIORITY_NORMAL, PASTE_COMMAND} from 'lexical';
11
+ import * as React from 'react';
12
+ import {useEffect, useState} from 'react';
13
+
14
+ export default function PasteLogPlugin(): JSX.Element {
15
+ const [editor] = useLexicalComposerContext();
16
+ const [isActive, setIsActive] = useState(false);
17
+ const [lastClipboardData, setLastClipboardData] = useState<string | null>(
18
+ null,
19
+ );
20
+ useEffect(() => {
21
+ if (isActive) {
22
+ return editor.registerCommand(
23
+ PASTE_COMMAND,
24
+ (e: ClipboardEvent) => {
25
+ const {clipboardData} = e;
26
+ const allData: string[] = [];
27
+ if (clipboardData && clipboardData.types) {
28
+ clipboardData.types.forEach((type) => {
29
+ allData.push(type.toUpperCase(), clipboardData.getData(type));
30
+ });
31
+ }
32
+ setLastClipboardData(allData.join('\n\n'));
33
+ return false;
34
+ },
35
+ COMMAND_PRIORITY_NORMAL,
36
+ );
37
+ }
38
+ }, [editor, isActive]);
39
+ return (
40
+ <>
41
+ <button
42
+ id="paste-log-button"
43
+ className={`editor-dev-button ${isActive ? 'active' : ''}`}
44
+ onClick={() => {
45
+ setIsActive(!isActive);
46
+ }}
47
+ title={isActive ? 'Disable paste log' : 'Enable paste log'}
48
+ />
49
+ {isActive && lastClipboardData !== null ? (
50
+ <pre>{lastClipboardData}</pre>
51
+ ) : null}
52
+ </>
53
+ );
54
+ }
@@ -0,0 +1,86 @@
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
+ // Core
9
+ import Button from '@client/components/button';
10
+ import Input from '@client/components/inputv3';
11
+
12
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
13
+ import { $wrapNodeInElement } from '@lexical/utils';
14
+ import {
15
+ $createParagraphNode,
16
+ $insertNodes,
17
+ $isRootOrShadowRoot,
18
+ COMMAND_PRIORITY_EDITOR,
19
+ createCommand,
20
+ LexicalCommand,
21
+ LexicalEditor,
22
+ } from 'lexical';
23
+ import { useEffect, useState } from 'react';
24
+ import * as React from 'react';
25
+
26
+ import {
27
+ $createPollNode,
28
+ createPollOption,
29
+ PollNode,
30
+ } from '../../nodes/PollNode';
31
+
32
+ export const INSERT_POLL_COMMAND: LexicalCommand<string> = createCommand(
33
+ 'INSERT_POLL_COMMAND',
34
+ );
35
+
36
+ export function InsertPollDialog({
37
+ editor,
38
+ close,
39
+ }: {
40
+ editor: LexicalEditor;
41
+ close: () => void;
42
+ }): React.JSX.Element {
43
+ const [question, setQuestion] = useState('');
44
+
45
+ const onClick = () => {
46
+ editor.dispatchCommand(INSERT_POLL_COMMAND, question);
47
+ close();
48
+ };
49
+
50
+ return (
51
+ <>
52
+ <Input title="Question" onChange={setQuestion} value={question} />
53
+
54
+ <Button type="primary" disabled={question.trim() === ''} onClick={onClick}>
55
+ Confirm
56
+ </Button>
57
+ </>
58
+ );
59
+ }
60
+
61
+ export default function PollPlugin(): React.JSX.Element | null {
62
+ const [editor] = useLexicalComposerContext();
63
+ useEffect(() => {
64
+ if (!editor.hasNodes([PollNode])) {
65
+ throw new Error('PollPlugin: PollNode not registered on editor');
66
+ }
67
+
68
+ return editor.registerCommand<string>(
69
+ INSERT_POLL_COMMAND,
70
+ (payload) => {
71
+ const pollNode = $createPollNode(payload, [
72
+ createPollOption(),
73
+ createPollOption(),
74
+ ]);
75
+ $insertNodes([pollNode]);
76
+ if ($isRootOrShadowRoot(pollNode.getParentOrThrow())) {
77
+ $wrapNodeInElement(pollNode, $createParagraphNode).selectEnd();
78
+ }
79
+
80
+ return true;
81
+ },
82
+ COMMAND_PRIORITY_EDITOR,
83
+ );
84
+ }, [editor]);
85
+ return null;
86
+ }
@@ -0,0 +1,125 @@
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
+
9
+ import type {LexicalCommand, LexicalEditor, RangeSelection} from 'lexical';
10
+
11
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
12
+ import {
13
+ $getSelection,
14
+ $isRangeSelection,
15
+ COMMAND_PRIORITY_EDITOR,
16
+ createCommand,
17
+ REDO_COMMAND,
18
+ UNDO_COMMAND,
19
+ } from 'lexical';
20
+ import {useEffect, useRef, useState} from 'react';
21
+
22
+ import useReport from '../../hooks/useReport';
23
+
24
+ export const SPEECH_TO_TEXT_COMMAND: LexicalCommand<boolean> = createCommand(
25
+ 'SPEECH_TO_TEXT_COMMAND',
26
+ );
27
+
28
+ const VOICE_COMMANDS: Readonly<
29
+ Record<
30
+ string,
31
+ (arg0: {editor: LexicalEditor; selection: RangeSelection}) => void
32
+ >
33
+ > = {
34
+ '\n': ({selection}) => {
35
+ selection.insertParagraph();
36
+ },
37
+ redo: ({editor}) => {
38
+ editor.dispatchCommand(REDO_COMMAND, undefined);
39
+ },
40
+ undo: ({editor}) => {
41
+ editor.dispatchCommand(UNDO_COMMAND, undefined);
42
+ },
43
+ };
44
+
45
+ export const SUPPORT_SPEECH_RECOGNITION: boolean =
46
+ 'SpeechRecognition' in window || 'webkitSpeechRecognition' in window;
47
+
48
+ function SpeechToTextPlugin(): null {
49
+ const [editor] = useLexicalComposerContext();
50
+ const [isEnabled, setIsEnabled] = useState<boolean>(false);
51
+ const SpeechRecognition =
52
+ // @ts-expect-error missing type
53
+ window.SpeechRecognition || window.webkitSpeechRecognition;
54
+ const recognition = useRef<typeof SpeechRecognition | null>(null);
55
+ const report = useReport();
56
+
57
+ useEffect(() => {
58
+ if (isEnabled && recognition.current === null) {
59
+ recognition.current = new SpeechRecognition();
60
+ recognition.current.continuous = true;
61
+ recognition.current.interimResults = true;
62
+ recognition.current.addEventListener(
63
+ 'result',
64
+ (event: typeof SpeechRecognition) => {
65
+ const resultItem = event.results.item(event.resultIndex);
66
+ const {transcript} = resultItem.item(0);
67
+ report(transcript);
68
+
69
+ if (!resultItem.isFinal) {
70
+ return;
71
+ }
72
+
73
+ editor.update(() => {
74
+ const selection = $getSelection();
75
+
76
+ if ($isRangeSelection(selection)) {
77
+ const command = VOICE_COMMANDS[transcript.toLowerCase().trim()];
78
+
79
+ if (command) {
80
+ command({
81
+ editor,
82
+ selection,
83
+ });
84
+ } else if (transcript.match(/\s*\n\s*/)) {
85
+ selection.insertParagraph();
86
+ } else {
87
+ selection.insertText(transcript);
88
+ }
89
+ }
90
+ });
91
+ },
92
+ );
93
+ }
94
+
95
+ if (recognition.current) {
96
+ if (isEnabled) {
97
+ recognition.current.start();
98
+ } else {
99
+ recognition.current.stop();
100
+ }
101
+ }
102
+
103
+ return () => {
104
+ if (recognition.current !== null) {
105
+ recognition.current.stop();
106
+ }
107
+ };
108
+ }, [SpeechRecognition, editor, isEnabled, report]);
109
+ useEffect(() => {
110
+ return editor.registerCommand(
111
+ SPEECH_TO_TEXT_COMMAND,
112
+ (_isEnabled: boolean) => {
113
+ setIsEnabled(_isEnabled);
114
+ return true;
115
+ },
116
+ COMMAND_PRIORITY_EDITOR,
117
+ );
118
+ }, [editor]);
119
+
120
+ return null;
121
+ }
122
+
123
+ export default (SUPPORT_SPEECH_RECOGNITION
124
+ ? SpeechToTextPlugin
125
+ : () => null) as () => null;
@@ -0,0 +1,22 @@
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
+
9
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
10
+ import {useEffect} from 'react';
11
+
12
+ import {StickyNode} from '../../nodes/StickyNode';
13
+
14
+ export default function StickyPlugin(): JSX.Element | null {
15
+ const [editor] = useLexicalComposerContext();
16
+ useEffect(() => {
17
+ if (!editor.hasNodes([StickyNode])) {
18
+ throw new Error('StickyPlugin: StickyNode not registered on editor');
19
+ }
20
+ }, [editor]);
21
+ return null;
22
+ }
@@ -0,0 +1,65 @@
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
+
9
+ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
10
+ import {
11
+ $getSelection,
12
+ $isRangeSelection,
13
+ $setSelection,
14
+ FOCUS_COMMAND,
15
+ } from 'lexical';
16
+ import {useEffect} from 'react';
17
+
18
+ const COMMAND_PRIORITY_LOW = 1;
19
+ const TAB_TO_FOCUS_INTERVAL = 100;
20
+
21
+ let lastTabKeyDownTimestamp = 0;
22
+ let hasRegisteredKeyDownListener = false;
23
+
24
+ function registerKeyTimeStampTracker() {
25
+ window.addEventListener(
26
+ 'keydown',
27
+ (event: KeyboardEvent) => {
28
+ // Tab
29
+ if (event.key === 'Tab') {
30
+ lastTabKeyDownTimestamp = event.timeStamp;
31
+ }
32
+ },
33
+ true,
34
+ );
35
+ }
36
+
37
+ export default function TabFocusPlugin(): null {
38
+ const [editor] = useLexicalComposerContext();
39
+
40
+ useEffect(() => {
41
+ if (!hasRegisteredKeyDownListener) {
42
+ registerKeyTimeStampTracker();
43
+ hasRegisteredKeyDownListener = true;
44
+ }
45
+
46
+ return editor.registerCommand(
47
+ FOCUS_COMMAND,
48
+ (event: FocusEvent) => {
49
+ const selection = $getSelection();
50
+ if ($isRangeSelection(selection)) {
51
+ if (
52
+ lastTabKeyDownTimestamp + TAB_TO_FOCUS_INTERVAL >
53
+ event.timeStamp
54
+ ) {
55
+ $setSelection(selection.clone());
56
+ }
57
+ }
58
+ return false;
59
+ },
60
+ COMMAND_PRIORITY_LOW,
61
+ );
62
+ }, [editor]);
63
+
64
+ return null;
65
+ }