5htp-core 0.4.8 → 0.4.9-1

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 (188) 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 +2 -6
  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/client/components/inputv3/index.tsx +1 -1
  164. package/src/common/data/rte/nodes.ts +60 -9
  165. package/src/common/validation/index.ts +21 -2
  166. package/src/common/validation/schema.ts +27 -10
  167. package/src/common/validation/validator.ts +12 -4
  168. package/src/common/validation/validators.ts +112 -63
  169. package/src/server/services/router/http/multipart.ts +0 -1
  170. package/src/server/services/schema/index.ts +26 -4
  171. package/src/server/services/schema/request.ts +3 -2
  172. package/src/server/services/schema/rte.ts +110 -0
  173. package/src/{common/data/rte/index.ts → server/utils/rte.ts} +27 -16
  174. package/src/client/components/inputv3/Rte/ExampleTheme.tsx +0 -42
  175. package/src/client/components/inputv3/Rte/ToolbarPlugin.tsx +0 -167
  176. package/src/client/components/inputv3/Rte/icons/LICENSE.md +0 -5
  177. package/src/client/components/inputv3/Rte/icons/arrow-clockwise.svg +0 -4
  178. package/src/client/components/inputv3/Rte/icons/arrow-counterclockwise.svg +0 -4
  179. package/src/client/components/inputv3/Rte/icons/journal-text.svg +0 -5
  180. package/src/client/components/inputv3/Rte/icons/justify.svg +0 -3
  181. package/src/client/components/inputv3/Rte/icons/text-center.svg +0 -3
  182. package/src/client/components/inputv3/Rte/icons/text-left.svg +0 -3
  183. package/src/client/components/inputv3/Rte/icons/text-paragraph.svg +0 -3
  184. package/src/client/components/inputv3/Rte/icons/text-right.svg +0 -3
  185. package/src/client/components/inputv3/Rte/icons/type-bold.svg +0 -3
  186. package/src/client/components/inputv3/Rte/icons/type-italic.svg +0 -3
  187. package/src/client/components/inputv3/Rte/icons/type-strikethrough.svg +0 -3
  188. package/src/client/components/inputv3/Rte/icons/type-underline.svg +0 -3
@@ -0,0 +1,324 @@
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 {
10
+ $convertFromMarkdownString,
11
+ $convertToMarkdownString,
12
+ CHECK_LIST,
13
+ ELEMENT_TRANSFORMERS,
14
+ ElementTransformer,
15
+ MULTILINE_ELEMENT_TRANSFORMERS,
16
+ TEXT_FORMAT_TRANSFORMERS,
17
+ TEXT_MATCH_TRANSFORMERS,
18
+ TextMatchTransformer,
19
+ Transformer,
20
+ } from '@lexical/markdown';
21
+ import {
22
+ $createHorizontalRuleNode,
23
+ $isHorizontalRuleNode,
24
+ HorizontalRuleNode,
25
+ } from '@lexical/react/LexicalHorizontalRuleNode';
26
+ import {
27
+ $createTableCellNode,
28
+ $createTableNode,
29
+ $createTableRowNode,
30
+ $isTableCellNode,
31
+ $isTableNode,
32
+ $isTableRowNode,
33
+ TableCellHeaderStates,
34
+ TableCellNode,
35
+ TableNode,
36
+ TableRowNode,
37
+ } from '@lexical/table';
38
+ import {
39
+ $createTextNode,
40
+ $isParagraphNode,
41
+ $isTextNode,
42
+ LexicalNode,
43
+ } from 'lexical';
44
+
45
+ /*import {
46
+ $createEquationNode,
47
+ $isEquationNode,
48
+ EquationNode,
49
+ } from '../../nodes/EquationNode';*/
50
+
51
+ import { $createImageNode, $isImageNode, ImageNode } from '../../nodes/ImageNode';
52
+ import { $createTweetNode, $isTweetNode, TweetNode } from '../../nodes/TweetNode';
53
+ import emojiList from '../../utils/emoji-list';
54
+
55
+ export const HR: ElementTransformer = {
56
+ dependencies: [HorizontalRuleNode],
57
+ export: (node: LexicalNode) => {
58
+ return $isHorizontalRuleNode(node) ? '***' : null;
59
+ },
60
+ regExp: /^(---|\*\*\*|___)\s?$/,
61
+ replace: (parentNode, _1, _2, isImport) => {
62
+ const line = $createHorizontalRuleNode();
63
+
64
+ // TODO: Get rid of isImport flag
65
+ if (isImport || parentNode.getNextSibling() != null) {
66
+ parentNode.replace(line);
67
+ } else {
68
+ parentNode.insertBefore(line);
69
+ }
70
+
71
+ line.selectNext();
72
+ },
73
+ type: 'element',
74
+ };
75
+
76
+ export const IMAGE: TextMatchTransformer = {
77
+ dependencies: [ImageNode],
78
+ export: (node) => {
79
+ if (!$isImageNode(node)) {
80
+ return null;
81
+ }
82
+
83
+ return `![${node.getAltText()}](${node.getSrc()})`;
84
+ },
85
+ importRegExp: /!(?:\[([^[]*)\])(?:\(([^(]+)\))/,
86
+ regExp: /!(?:\[([^[]*)\])(?:\(([^(]+)\))$/,
87
+ replace: (textNode, match) => {
88
+ const [, altText, src] = match;
89
+ const imageNode = $createImageNode({
90
+ altText,
91
+ maxWidth: 800,
92
+ src,
93
+ });
94
+ textNode.replace(imageNode);
95
+ },
96
+ trigger: ')',
97
+ type: 'text-match',
98
+ };
99
+
100
+ export const EMOJI: TextMatchTransformer = {
101
+ dependencies: [],
102
+ export: () => null,
103
+ importRegExp: /:([a-z0-9_]+):/,
104
+ regExp: /:([a-z0-9_]+):$/,
105
+ replace: (textNode, [, name]) => {
106
+ const emoji = emojiList.find((e) => e.aliases.includes(name))?.emoji;
107
+ if (emoji) {
108
+ textNode.replace($createTextNode(emoji));
109
+ }
110
+ },
111
+ trigger: ':',
112
+ type: 'text-match',
113
+ };
114
+
115
+ /*export const EQUATION: TextMatchTransformer = {
116
+ dependencies: [EquationNode],
117
+ export: (node) => {
118
+ if (!$isEquationNode(node)) {
119
+ return null;
120
+ }
121
+
122
+ return `$${node.getEquation()}$`;
123
+ },
124
+ importRegExp: /\$([^$]+?)\$/,
125
+ regExp: /\$([^$]+?)\$$/,
126
+ replace: (textNode, match) => {
127
+ const [, equation] = match;
128
+ const equationNode = $createEquationNode(equation, true);
129
+ textNode.replace(equationNode);
130
+ },
131
+ trigger: '$',
132
+ type: 'text-match',
133
+ };*/
134
+
135
+ export const TWEET: ElementTransformer = {
136
+ dependencies: [TweetNode],
137
+ export: (node) => {
138
+ if (!$isTweetNode(node)) {
139
+ return null;
140
+ }
141
+
142
+ return `<tweet id="${node.getId()}" />`;
143
+ },
144
+ regExp: /<tweet id="([^"]+?)"\s?\/>\s?$/,
145
+ replace: (textNode, _1, match) => {
146
+ const [, id] = match;
147
+ const tweetNode = $createTweetNode(id);
148
+ textNode.replace(tweetNode);
149
+ },
150
+ type: 'element',
151
+ };
152
+
153
+ // Very primitive table setup
154
+ const TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/;
155
+ const TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/;
156
+
157
+ export const TABLE: ElementTransformer = {
158
+ dependencies: [TableNode, TableRowNode, TableCellNode],
159
+ export: (node: LexicalNode) => {
160
+ if (!$isTableNode(node)) {
161
+ return null;
162
+ }
163
+
164
+ const output: string[] = [];
165
+
166
+ for (const row of node.getChildren()) {
167
+ const rowOutput = [];
168
+ if (!$isTableRowNode(row)) {
169
+ continue;
170
+ }
171
+
172
+ let isHeaderRow = false;
173
+ for (const cell of row.getChildren()) {
174
+ // It's TableCellNode so it's just to make flow happy
175
+ if ($isTableCellNode(cell)) {
176
+ rowOutput.push(
177
+ $convertToMarkdownString(PLAYGROUND_TRANSFORMERS, cell).replace(
178
+ /\n/g,
179
+ '\\n',
180
+ ),
181
+ );
182
+ if (cell.__headerState === TableCellHeaderStates.ROW) {
183
+ isHeaderRow = true;
184
+ }
185
+ }
186
+ }
187
+
188
+ output.push(`| ${rowOutput.join(' | ')} |`);
189
+ if (isHeaderRow) {
190
+ output.push(`| ${rowOutput.map((_) => '---').join(' | ')} |`);
191
+ }
192
+ }
193
+
194
+ return output.join('\n');
195
+ },
196
+ regExp: TABLE_ROW_REG_EXP,
197
+ replace: (parentNode, _1, match) => {
198
+ // Header row
199
+ if (TABLE_ROW_DIVIDER_REG_EXP.test(match[0])) {
200
+ const table = parentNode.getPreviousSibling();
201
+ if (!table || !$isTableNode(table)) {
202
+ return;
203
+ }
204
+
205
+ const rows = table.getChildren();
206
+ const lastRow = rows[rows.length - 1];
207
+ if (!lastRow || !$isTableRowNode(lastRow)) {
208
+ return;
209
+ }
210
+
211
+ // Add header state to row cells
212
+ lastRow.getChildren().forEach((cell) => {
213
+ if (!$isTableCellNode(cell)) {
214
+ return;
215
+ }
216
+ cell.setHeaderStyles(
217
+ TableCellHeaderStates.ROW,
218
+ TableCellHeaderStates.ROW,
219
+ );
220
+ });
221
+
222
+ // Remove line
223
+ parentNode.remove();
224
+ return;
225
+ }
226
+
227
+ const matchCells = mapToTableCells(match[0]);
228
+
229
+ if (matchCells == null) {
230
+ return;
231
+ }
232
+
233
+ const rows = [matchCells];
234
+ let sibling = parentNode.getPreviousSibling();
235
+ let maxCells = matchCells.length;
236
+
237
+ while (sibling) {
238
+ if (!$isParagraphNode(sibling)) {
239
+ break;
240
+ }
241
+
242
+ if (sibling.getChildrenSize() !== 1) {
243
+ break;
244
+ }
245
+
246
+ const firstChild = sibling.getFirstChild();
247
+
248
+ if (!$isTextNode(firstChild)) {
249
+ break;
250
+ }
251
+
252
+ const cells = mapToTableCells(firstChild.getTextContent());
253
+
254
+ if (cells == null) {
255
+ break;
256
+ }
257
+
258
+ maxCells = Math.max(maxCells, cells.length);
259
+ rows.unshift(cells);
260
+ const previousSibling = sibling.getPreviousSibling();
261
+ sibling.remove();
262
+ sibling = previousSibling;
263
+ }
264
+
265
+ const table = $createTableNode();
266
+
267
+ for (const cells of rows) {
268
+ const tableRow = $createTableRowNode();
269
+ table.append(tableRow);
270
+
271
+ for (let i = 0; i < maxCells; i++) {
272
+ tableRow.append(i < cells.length ? cells[i] : $createTableCell(''));
273
+ }
274
+ }
275
+
276
+ const previousSibling = parentNode.getPreviousSibling();
277
+ if (
278
+ $isTableNode(previousSibling) &&
279
+ getTableColumnsSize(previousSibling) === maxCells
280
+ ) {
281
+ previousSibling.append(...table.getChildren());
282
+ parentNode.remove();
283
+ } else {
284
+ parentNode.replace(table);
285
+ }
286
+
287
+ table.selectEnd();
288
+ },
289
+ type: 'element',
290
+ };
291
+
292
+ function getTableColumnsSize(table: TableNode) {
293
+ const row = table.getFirstChild();
294
+ return $isTableRowNode(row) ? row.getChildrenSize() : 0;
295
+ }
296
+
297
+ const $createTableCell = (textContent: string): TableCellNode => {
298
+ textContent = textContent.replace(/\\n/g, '\n');
299
+ const cell = $createTableCellNode(TableCellHeaderStates.NO_STATUS);
300
+ $convertFromMarkdownString(textContent, PLAYGROUND_TRANSFORMERS, cell);
301
+ return cell;
302
+ };
303
+
304
+ const mapToTableCells = (textContent: string): Array<TableCellNode> | null => {
305
+ const match = textContent.match(TABLE_ROW_REG_EXP);
306
+ if (!match || !match[1]) {
307
+ return null;
308
+ }
309
+ return match[1].split('|').map((text) => $createTableCell(text));
310
+ };
311
+
312
+ export const PLAYGROUND_TRANSFORMERS: Array<Transformer> = [
313
+ TABLE,
314
+ HR,
315
+ IMAGE,
316
+ EMOJI,
317
+ //EQUATION,
318
+ TWEET,
319
+ CHECK_LIST,
320
+ ...ELEMENT_TRANSFORMERS,
321
+ ...MULTILINE_ELEMENT_TRANSFORMERS,
322
+ ...TEXT_FORMAT_TRANSFORMERS,
323
+ ...TEXT_MATCH_TRANSFORMERS,
324
+ ];
@@ -0,0 +1,53 @@
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 {$trimTextContentFromAnchor} from '@lexical/selection';
11
+ import {$restoreEditorState} from '@lexical/utils';
12
+ import {$getSelection, $isRangeSelection, EditorState, RootNode} from 'lexical';
13
+ import {useEffect} from 'react';
14
+
15
+ export function MaxLengthPlugin({maxLength}: {maxLength: number}): null {
16
+ const [editor] = useLexicalComposerContext();
17
+
18
+ useEffect(() => {
19
+ let lastRestoredEditorState: EditorState | null = null;
20
+
21
+ return editor.registerNodeTransform(RootNode, (rootNode: RootNode) => {
22
+ const selection = $getSelection();
23
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
24
+ return;
25
+ }
26
+ const prevEditorState = editor.getEditorState();
27
+ const prevTextContentSize = prevEditorState.read(() =>
28
+ rootNode.getTextContentSize(),
29
+ );
30
+ const textContentSize = rootNode.getTextContentSize();
31
+ if (prevTextContentSize !== textContentSize) {
32
+ const delCount = textContentSize - maxLength;
33
+ const anchor = selection.anchor;
34
+
35
+ if (delCount > 0) {
36
+ // Restore the old editor state instead if the last
37
+ // text content was already at the limit.
38
+ if (
39
+ prevTextContentSize === maxLength &&
40
+ lastRestoredEditorState !== prevEditorState
41
+ ) {
42
+ lastRestoredEditorState = prevEditorState;
43
+ $restoreEditorState(editor, prevEditorState);
44
+ } else {
45
+ $trimTextContentFromAnchor(editor, anchor, delCount);
46
+ }
47
+ }
48
+ }
49
+ });
50
+ }, [editor, maxLength]);
51
+
52
+ return null;
53
+ }