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,41 @@
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 * as React from 'react';
10
+
11
+ import ColorPicker from './ColorPicker';
12
+ import DropDown from './DropDown';
13
+
14
+ type Props = {
15
+ disabled?: boolean;
16
+ buttonAriaLabel?: string;
17
+ buttonClassName: string;
18
+ buttonIconClassName?: string;
19
+ buttonLabel?: string;
20
+ title?: string;
21
+ stopCloseOnClickSelf?: boolean;
22
+ color: string;
23
+ onChange?: (color: string, skipHistoryStack: boolean) => void;
24
+ };
25
+
26
+ export default function DropdownColorPicker({
27
+ disabled = false,
28
+ stopCloseOnClickSelf = true,
29
+ color,
30
+ onChange,
31
+ ...rest
32
+ }: Props) {
33
+ return (
34
+ <DropDown
35
+ {...rest}
36
+ disabled={disabled}
37
+ stopCloseOnClickSelf={stopCloseOnClickSelf}>
38
+ <ColorPicker color={color} onChange={onChange} />
39
+ </DropDown>
40
+ );
41
+ }
@@ -0,0 +1,38 @@
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
+
10
+ .EquationEditor_inlineEditor {
11
+ padding: 0;
12
+ margin: 0;
13
+ border: 0;
14
+ outline: 0;
15
+ color: #8421a2;
16
+ background-color: inherit;
17
+ resize: none;
18
+ }
19
+
20
+ .EquationEditor_blockEditor {
21
+ padding: 0;
22
+ margin: 0;
23
+ border: 0;
24
+ outline: 0;
25
+ color: #8421a2;
26
+ background-color: inherit;
27
+ resize: none;
28
+ width: 100%;
29
+ }
30
+
31
+ .EquationEditor_inputBackground {
32
+ background-color: #eee;
33
+ }
34
+
35
+ .EquationEditor_dollarSign {
36
+ text-align: left;
37
+ color: #b0b0b0;
38
+ }
@@ -0,0 +1,56 @@
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 {Ref, RefObject} from 'react';
10
+
11
+ import './EquationEditor.css';
12
+
13
+ import * as React from 'react';
14
+ import {ChangeEvent, forwardRef} from 'react';
15
+
16
+ type BaseEquationEditorProps = {
17
+ equation: string;
18
+ inline: boolean;
19
+ setEquation: (equation: string) => void;
20
+ };
21
+
22
+ function EquationEditor(
23
+ {equation, setEquation, inline}: BaseEquationEditorProps,
24
+ forwardedRef: Ref<HTMLInputElement | HTMLTextAreaElement>,
25
+ ): JSX.Element {
26
+ const onChange = (event: ChangeEvent) => {
27
+ setEquation((event.target as HTMLInputElement).value);
28
+ };
29
+
30
+ return inline && forwardedRef instanceof HTMLInputElement ? (
31
+ <span className="EquationEditor_inputBackground">
32
+ <span className="EquationEditor_dollarSign">$</span>
33
+ <input
34
+ className="EquationEditor_inlineEditor"
35
+ value={equation}
36
+ onChange={onChange}
37
+ autoFocus={true}
38
+ ref={forwardedRef as RefObject<HTMLInputElement>}
39
+ />
40
+ <span className="EquationEditor_dollarSign">$</span>
41
+ </span>
42
+ ) : (
43
+ <div className="EquationEditor_inputBackground">
44
+ <span className="EquationEditor_dollarSign">{'$$\n'}</span>
45
+ <textarea
46
+ className="EquationEditor_blockEditor"
47
+ value={equation}
48
+ onChange={onChange}
49
+ ref={forwardedRef as RefObject<HTMLTextAreaElement>}
50
+ />
51
+ <span className="EquationEditor_dollarSign">{'\n$$'}</span>
52
+ </div>
53
+ );
54
+ }
55
+
56
+ export default forwardRef(EquationEditor);
@@ -0,0 +1,38 @@
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 './Input.css';
10
+
11
+ import * as React from 'react';
12
+
13
+ type Props = Readonly<{
14
+ 'data-test-id'?: string;
15
+ accept?: string;
16
+ label: string;
17
+ onChange: (files: FileList | null) => void;
18
+ }>;
19
+
20
+ export default function FileInput({
21
+ accept,
22
+ label,
23
+ onChange,
24
+ 'data-test-id': dataTestId,
25
+ }: Props): JSX.Element {
26
+ return (
27
+ <div className="Input__wrapper">
28
+ <label className="Input__label">{label}</label>
29
+ <input
30
+ type="file"
31
+ accept={accept}
32
+ className="Input__input"
33
+ onChange={(e) => onChange(e.target.files)}
34
+ data-test-id={dataTestId}
35
+ />
36
+ </div>
37
+ );
38
+ }
@@ -0,0 +1,28 @@
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
+
10
+ .FlashMessage__overlay {
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ position: fixed;
15
+ pointer-events: none;
16
+ top: 0px;
17
+ bottom: 0px;
18
+ left: 0px;
19
+ right: 0px;
20
+ }
21
+ .FlashMessage__alert {
22
+ background-color: rgba(0, 0, 0, 0.8);
23
+ color: white;
24
+ padding: 20px;
25
+ font-size: 1.5rem;
26
+ border-radius: 1em;
27
+ padding: 0.5em 1.5em;
28
+ }
@@ -0,0 +1,29 @@
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 './FlashMessage.css';
10
+
11
+ import {ReactNode} from 'react';
12
+ import {createPortal} from 'react-dom';
13
+
14
+ export interface FlashMessageProps {
15
+ children: ReactNode;
16
+ }
17
+
18
+ export default function FlashMessage({
19
+ children,
20
+ }: FlashMessageProps): JSX.Element {
21
+ return createPortal(
22
+ <div className="FlashMessage__overlay" role="dialog">
23
+ <p className="FlashMessage__alert" role="alert">
24
+ {children}
25
+ </p>
26
+ </div>,
27
+ document.body,
28
+ );
29
+ }
@@ -0,0 +1,316 @@
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 {LexicalEditor} from 'lexical';
10
+
11
+ import {calculateZoomLevel} from '@lexical/utils';
12
+ import * as React from 'react';
13
+ import {useRef} from 'react';
14
+
15
+ function clamp(value: number, min: number, max: number) {
16
+ return Math.min(Math.max(value, min), max);
17
+ }
18
+
19
+ const Direction = {
20
+ east: 1 << 0,
21
+ north: 1 << 3,
22
+ south: 1 << 1,
23
+ west: 1 << 2,
24
+ };
25
+
26
+ export default function ImageResizer({
27
+ onResizeStart,
28
+ onResizeEnd,
29
+ buttonRef,
30
+ imageRef,
31
+ maxWidth,
32
+ editor,
33
+ showCaption,
34
+ setShowCaption,
35
+ captionsEnabled,
36
+ }: {
37
+ editor: LexicalEditor;
38
+ buttonRef: {current: null | HTMLButtonElement};
39
+ imageRef: {current: null | HTMLElement};
40
+ maxWidth?: number;
41
+ onResizeEnd: (width: 'inherit' | number, height: 'inherit' | number) => void;
42
+ onResizeStart: () => void;
43
+ setShowCaption: (show: boolean) => void;
44
+ showCaption: boolean;
45
+ captionsEnabled: boolean;
46
+ }): JSX.Element {
47
+ const controlWrapperRef = useRef<HTMLDivElement>(null);
48
+ const userSelect = useRef({
49
+ priority: '',
50
+ value: 'default',
51
+ });
52
+ const positioningRef = useRef<{
53
+ currentHeight: 'inherit' | number;
54
+ currentWidth: 'inherit' | number;
55
+ direction: number;
56
+ isResizing: boolean;
57
+ ratio: number;
58
+ startHeight: number;
59
+ startWidth: number;
60
+ startX: number;
61
+ startY: number;
62
+ }>({
63
+ currentHeight: 0,
64
+ currentWidth: 0,
65
+ direction: 0,
66
+ isResizing: false,
67
+ ratio: 0,
68
+ startHeight: 0,
69
+ startWidth: 0,
70
+ startX: 0,
71
+ startY: 0,
72
+ });
73
+ const editorRootElement = editor.getRootElement();
74
+ // Find max width, accounting for editor padding.
75
+ const maxWidthContainer = maxWidth
76
+ ? maxWidth
77
+ : editorRootElement !== null
78
+ ? editorRootElement.getBoundingClientRect().width - 20
79
+ : 100;
80
+ const maxHeightContainer =
81
+ editorRootElement !== null
82
+ ? editorRootElement.getBoundingClientRect().height - 20
83
+ : 100;
84
+
85
+ const minWidth = 100;
86
+ const minHeight = 100;
87
+
88
+ const setStartCursor = (direction: number) => {
89
+ const ew = direction === Direction.east || direction === Direction.west;
90
+ const ns = direction === Direction.north || direction === Direction.south;
91
+ const nwse =
92
+ (direction & Direction.north && direction & Direction.west) ||
93
+ (direction & Direction.south && direction & Direction.east);
94
+
95
+ const cursorDir = ew ? 'ew' : ns ? 'ns' : nwse ? 'nwse' : 'nesw';
96
+
97
+ if (editorRootElement !== null) {
98
+ editorRootElement.style.setProperty(
99
+ 'cursor',
100
+ `${cursorDir}-resize`,
101
+ 'important',
102
+ );
103
+ }
104
+ if (document.body !== null) {
105
+ document.body.style.setProperty(
106
+ 'cursor',
107
+ `${cursorDir}-resize`,
108
+ 'important',
109
+ );
110
+ userSelect.current.value = document.body.style.getPropertyValue(
111
+ '-webkit-user-select',
112
+ );
113
+ userSelect.current.priority = document.body.style.getPropertyPriority(
114
+ '-webkit-user-select',
115
+ );
116
+ document.body.style.setProperty(
117
+ '-webkit-user-select',
118
+ `none`,
119
+ 'important',
120
+ );
121
+ }
122
+ };
123
+
124
+ const setEndCursor = () => {
125
+ if (editorRootElement !== null) {
126
+ editorRootElement.style.setProperty('cursor', 'text');
127
+ }
128
+ if (document.body !== null) {
129
+ document.body.style.setProperty('cursor', 'default');
130
+ document.body.style.setProperty(
131
+ '-webkit-user-select',
132
+ userSelect.current.value,
133
+ userSelect.current.priority,
134
+ );
135
+ }
136
+ };
137
+
138
+ const handlePointerDown = (
139
+ event: React.PointerEvent<HTMLDivElement>,
140
+ direction: number,
141
+ ) => {
142
+ if (!editor.isEditable()) {
143
+ return;
144
+ }
145
+
146
+ const image = imageRef.current;
147
+ const controlWrapper = controlWrapperRef.current;
148
+
149
+ if (image !== null && controlWrapper !== null) {
150
+ event.preventDefault();
151
+ const {width, height} = image.getBoundingClientRect();
152
+ const zoom = calculateZoomLevel(image);
153
+ const positioning = positioningRef.current;
154
+ positioning.startWidth = width;
155
+ positioning.startHeight = height;
156
+ positioning.ratio = width / height;
157
+ positioning.currentWidth = width;
158
+ positioning.currentHeight = height;
159
+ positioning.startX = event.clientX / zoom;
160
+ positioning.startY = event.clientY / zoom;
161
+ positioning.isResizing = true;
162
+ positioning.direction = direction;
163
+
164
+ setStartCursor(direction);
165
+ onResizeStart();
166
+
167
+ controlWrapper.classList.add('image-control-wrapper--resizing');
168
+ image.style.height = `${height}px`;
169
+ image.style.width = `${width}px`;
170
+
171
+ document.addEventListener('pointermove', handlePointerMove);
172
+ document.addEventListener('pointerup', handlePointerUp);
173
+ }
174
+ };
175
+ const handlePointerMove = (event: PointerEvent) => {
176
+ const image = imageRef.current;
177
+ const positioning = positioningRef.current;
178
+
179
+ const isHorizontal =
180
+ positioning.direction & (Direction.east | Direction.west);
181
+ const isVertical =
182
+ positioning.direction & (Direction.south | Direction.north);
183
+
184
+ if (image !== null && positioning.isResizing) {
185
+ const zoom = calculateZoomLevel(image);
186
+ // Corner cursor
187
+ if (isHorizontal && isVertical) {
188
+ let diff = Math.floor(positioning.startX - event.clientX / zoom);
189
+ diff = positioning.direction & Direction.east ? -diff : diff;
190
+
191
+ const width = clamp(
192
+ positioning.startWidth + diff,
193
+ minWidth,
194
+ maxWidthContainer,
195
+ );
196
+
197
+ const height = width / positioning.ratio;
198
+ image.style.width = `${width}px`;
199
+ image.style.height = `${height}px`;
200
+ positioning.currentHeight = height;
201
+ positioning.currentWidth = width;
202
+ } else if (isVertical) {
203
+ let diff = Math.floor(positioning.startY - event.clientY / zoom);
204
+ diff = positioning.direction & Direction.south ? -diff : diff;
205
+
206
+ const height = clamp(
207
+ positioning.startHeight + diff,
208
+ minHeight,
209
+ maxHeightContainer,
210
+ );
211
+
212
+ image.style.height = `${height}px`;
213
+ positioning.currentHeight = height;
214
+ } else {
215
+ let diff = Math.floor(positioning.startX - event.clientX / zoom);
216
+ diff = positioning.direction & Direction.east ? -diff : diff;
217
+
218
+ const width = clamp(
219
+ positioning.startWidth + diff,
220
+ minWidth,
221
+ maxWidthContainer,
222
+ );
223
+
224
+ image.style.width = `${width}px`;
225
+ positioning.currentWidth = width;
226
+ }
227
+ }
228
+ };
229
+ const handlePointerUp = () => {
230
+ const image = imageRef.current;
231
+ const positioning = positioningRef.current;
232
+ const controlWrapper = controlWrapperRef.current;
233
+ if (image !== null && controlWrapper !== null && positioning.isResizing) {
234
+ const width = positioning.currentWidth;
235
+ const height = positioning.currentHeight;
236
+ positioning.startWidth = 0;
237
+ positioning.startHeight = 0;
238
+ positioning.ratio = 0;
239
+ positioning.startX = 0;
240
+ positioning.startY = 0;
241
+ positioning.currentWidth = 0;
242
+ positioning.currentHeight = 0;
243
+ positioning.isResizing = false;
244
+
245
+ controlWrapper.classList.remove('image-control-wrapper--resizing');
246
+
247
+ setEndCursor();
248
+ onResizeEnd(width, height);
249
+
250
+ document.removeEventListener('pointermove', handlePointerMove);
251
+ document.removeEventListener('pointerup', handlePointerUp);
252
+ }
253
+ };
254
+ return (
255
+ <div ref={controlWrapperRef}>
256
+ {!showCaption && captionsEnabled && (
257
+ <button
258
+ className="image-caption-button"
259
+ ref={buttonRef}
260
+ onClick={() => {
261
+ setShowCaption(!showCaption);
262
+ }}>
263
+ Add Caption
264
+ </button>
265
+ )}
266
+ <div
267
+ className="image-resizer image-resizer-n"
268
+ onPointerDown={(event) => {
269
+ handlePointerDown(event, Direction.north);
270
+ }}
271
+ />
272
+ <div
273
+ className="image-resizer image-resizer-ne"
274
+ onPointerDown={(event) => {
275
+ handlePointerDown(event, Direction.north | Direction.east);
276
+ }}
277
+ />
278
+ <div
279
+ className="image-resizer image-resizer-e"
280
+ onPointerDown={(event) => {
281
+ handlePointerDown(event, Direction.east);
282
+ }}
283
+ />
284
+ <div
285
+ className="image-resizer image-resizer-se"
286
+ onPointerDown={(event) => {
287
+ handlePointerDown(event, Direction.south | Direction.east);
288
+ }}
289
+ />
290
+ <div
291
+ className="image-resizer image-resizer-s"
292
+ onPointerDown={(event) => {
293
+ handlePointerDown(event, Direction.south);
294
+ }}
295
+ />
296
+ <div
297
+ className="image-resizer image-resizer-sw"
298
+ onPointerDown={(event) => {
299
+ handlePointerDown(event, Direction.south | Direction.west);
300
+ }}
301
+ />
302
+ <div
303
+ className="image-resizer image-resizer-w"
304
+ onPointerDown={(event) => {
305
+ handlePointerDown(event, Direction.west);
306
+ }}
307
+ />
308
+ <div
309
+ className="image-resizer image-resizer-nw"
310
+ onPointerDown={(event) => {
311
+ handlePointerDown(event, Direction.north | Direction.west);
312
+ }}
313
+ />
314
+ </div>
315
+ );
316
+ }
@@ -0,0 +1,32 @@
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
+
10
+ .Input__wrapper {
11
+ display: flex;
12
+ flex-direction: row;
13
+ align-items: center;
14
+ margin-bottom: 10px;
15
+ }
16
+ .Input__label {
17
+ display: flex;
18
+ flex: 1;
19
+ color: #666;
20
+ }
21
+ .Input__input {
22
+ display: flex;
23
+ flex: 2;
24
+ border: 1px solid #999;
25
+ padding-top: 7px;
26
+ padding-bottom: 7px;
27
+ padding-left: 10px;
28
+ padding-right: 10px;
29
+ font-size: 16px;
30
+ border-radius: 5px;
31
+ min-width: 0;
32
+ }
@@ -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 katex from 'katex';
10
+ import * as React from 'react';
11
+ import {useEffect, useRef} from 'react';
12
+
13
+ export default function KatexRenderer({
14
+ equation,
15
+ inline,
16
+ onDoubleClick,
17
+ }: Readonly<{
18
+ equation: string;
19
+ inline: boolean;
20
+ onDoubleClick: () => void;
21
+ }>): JSX.Element {
22
+ const katexElementRef = useRef(null);
23
+
24
+ useEffect(() => {
25
+ const katexElement = katexElementRef.current;
26
+
27
+ if (katexElement !== null) {
28
+ katex.render(equation, katexElement, {
29
+ displayMode: !inline, // true === block display //
30
+ errorColor: '#cc0000',
31
+ output: 'html',
32
+ strict: 'warn',
33
+ throwOnError: false,
34
+ trust: false,
35
+ });
36
+ }
37
+ }, [equation, inline]);
38
+
39
+ return (
40
+ // We use an empty image tag either side to ensure Android doesn't try and compose from the
41
+ // inner text from Katex. There didn't seem to be any other way of making this work,
42
+ // without having a physical space.
43
+ <>
44
+ <img src="#" alt="" />
45
+ <span
46
+ role="button"
47
+ tabIndex={-1}
48
+ onDoubleClick={onDoubleClick}
49
+ ref={katexElementRef}
50
+ />
51
+ <img src="#" alt="" />
52
+ </>
53
+ );
54
+ }
@@ -0,0 +1,36 @@
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 * as React from 'react';
10
+ import {useMemo} from 'react';
11
+
12
+ export default function Switch({
13
+ checked,
14
+ onClick,
15
+ text,
16
+ id,
17
+ }: Readonly<{
18
+ checked: boolean;
19
+ id?: string;
20
+ onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
21
+ text: string;
22
+ }>): JSX.Element {
23
+ const buttonId = useMemo(() => 'id_' + Math.floor(Math.random() * 10000), []);
24
+ return (
25
+ <div className="switch" id={id}>
26
+ <label htmlFor={buttonId}>{text}</label>
27
+ <button
28
+ role="switch"
29
+ aria-checked={checked}
30
+ id={buttonId}
31
+ onClick={onClick}>
32
+ <span />
33
+ </button>
34
+ </div>
35
+ );
36
+ }