@blue-patterns/richtext 0.0.0-stage → 0.7.18

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 (201) hide show
  1. package/CHANGELOG.md +275 -0
  2. package/LICENSE +22 -0
  3. package/README.md +88 -2
  4. package/astryx.integration.mjs +11 -0
  5. package/blocks/RichTextEditorShowcase.template.mjs +13 -0
  6. package/blocks/RichTextEditorShowcase.tsx +19 -0
  7. package/dist/RichTextEditor.d.ts +282 -0
  8. package/dist/RichTextEditor.d.ts.map +1 -0
  9. package/dist/RichTextEditor.js +657 -0
  10. package/dist/RichTextEditorAutoLinkPlugin.d.ts +83 -0
  11. package/dist/RichTextEditorAutoLinkPlugin.d.ts.map +1 -0
  12. package/dist/RichTextEditorAutoLinkPlugin.js +99 -0
  13. package/dist/RichTextEditorToolbar.d.ts +186 -0
  14. package/dist/RichTextEditorToolbar.d.ts.map +1 -0
  15. package/dist/RichTextEditorToolbar.js +688 -0
  16. package/dist/RichTextView.d.ts +92 -0
  17. package/dist/RichTextView.d.ts.map +1 -0
  18. package/dist/RichTextView.js +267 -0
  19. package/dist/codeLanguages.d.ts +14 -0
  20. package/dist/codeLanguages.d.ts.map +1 -0
  21. package/dist/codeLanguages.js +34 -0
  22. package/dist/codeLineTokens.d.ts +53 -0
  23. package/dist/codeLineTokens.d.ts.map +1 -0
  24. package/dist/codeLineTokens.js +188 -0
  25. package/dist/editorNodes.d.ts +8 -0
  26. package/dist/editorNodes.d.ts.map +1 -0
  27. package/dist/editorNodes.js +30 -0
  28. package/dist/editorTheme.d.ts +7 -0
  29. package/dist/editorTheme.d.ts.map +1 -0
  30. package/dist/editorTheme.js +328 -0
  31. package/dist/index.d.ts +31 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +28 -0
  34. package/dist/internal/CodeBackspacePlugin.d.ts +2 -0
  35. package/dist/internal/CodeBackspacePlugin.d.ts.map +1 -0
  36. package/dist/internal/CodeBackspacePlugin.js +70 -0
  37. package/dist/internal/CodeBlockHeaderPlugin.d.ts +11 -0
  38. package/dist/internal/CodeBlockHeaderPlugin.d.ts.map +1 -0
  39. package/dist/internal/CodeBlockHeaderPlugin.js +204 -0
  40. package/dist/internal/CodePastePlugin.d.ts +5 -0
  41. package/dist/internal/CodePastePlugin.d.ts.map +1 -0
  42. package/dist/internal/CodePastePlugin.js +104 -0
  43. package/dist/internal/CodeSyntaxPlugin.d.ts +8 -0
  44. package/dist/internal/CodeSyntaxPlugin.d.ts.map +1 -0
  45. package/dist/internal/CodeSyntaxPlugin.js +397 -0
  46. package/dist/internal/CodeTabPlugin.d.ts +2 -0
  47. package/dist/internal/CodeTabPlugin.d.ts.map +1 -0
  48. package/dist/internal/CodeTabPlugin.js +256 -0
  49. package/dist/internal/DisabledLinkGuardPlugin.d.ts +4 -0
  50. package/dist/internal/DisabledLinkGuardPlugin.d.ts.map +1 -0
  51. package/dist/internal/DisabledLinkGuardPlugin.js +93 -0
  52. package/dist/internal/ImageSourceCaretPlugin.d.ts +3 -0
  53. package/dist/internal/ImageSourceCaretPlugin.d.ts.map +1 -0
  54. package/dist/internal/ImageSourceCaretPlugin.js +105 -0
  55. package/dist/internal/ListItemShortcutsPlugin.d.ts +6 -0
  56. package/dist/internal/ListItemShortcutsPlugin.d.ts.map +1 -0
  57. package/dist/internal/ListItemShortcutsPlugin.js +314 -0
  58. package/dist/internal/MarkdownExtensionsPlugin.d.ts +17 -0
  59. package/dist/internal/MarkdownExtensionsPlugin.d.ts.map +1 -0
  60. package/dist/internal/MarkdownExtensionsPlugin.js +185 -0
  61. package/dist/internal/SelectAllScopePlugin.d.ts +2 -0
  62. package/dist/internal/SelectAllScopePlugin.d.ts.map +1 -0
  63. package/dist/internal/SelectAllScopePlugin.js +67 -0
  64. package/dist/internal/TableColumnFloorPlugin.d.ts +12 -0
  65. package/dist/internal/TableColumnFloorPlugin.d.ts.map +1 -0
  66. package/dist/internal/TableColumnFloorPlugin.js +84 -0
  67. package/dist/internal/TablePastePlugin.d.ts +9 -0
  68. package/dist/internal/TablePastePlugin.d.ts.map +1 -0
  69. package/dist/internal/TablePastePlugin.js +183 -0
  70. package/dist/internal/TableScrollRegionPlugin.d.ts +9 -0
  71. package/dist/internal/TableScrollRegionPlugin.d.ts.map +1 -0
  72. package/dist/internal/TableScrollRegionPlugin.js +95 -0
  73. package/dist/internal/TaskCheckboxPlugin.d.ts +7 -0
  74. package/dist/internal/TaskCheckboxPlugin.d.ts.map +1 -0
  75. package/dist/internal/TaskCheckboxPlugin.js +193 -0
  76. package/dist/internal/ToolbarLinkPopover.d.ts +74 -0
  77. package/dist/internal/ToolbarLinkPopover.d.ts.map +1 -0
  78. package/dist/internal/ToolbarLinkPopover.js +292 -0
  79. package/dist/linkEditing.d.ts +6 -0
  80. package/dist/linkEditing.d.ts.map +1 -0
  81. package/dist/linkEditing.js +20 -0
  82. package/dist/linkForm.d.ts +28 -0
  83. package/dist/linkForm.d.ts.map +1 -0
  84. package/dist/linkForm.js +137 -0
  85. package/dist/linkUtils.d.ts +27 -0
  86. package/dist/linkUtils.d.ts.map +1 -0
  87. package/dist/linkUtils.js +101 -0
  88. package/dist/markdown.d.ts +17 -0
  89. package/dist/markdown.d.ts.map +1 -0
  90. package/dist/markdown.js +17 -0
  91. package/dist/markdownCharacterReferences.d.ts +135 -0
  92. package/dist/markdownCharacterReferences.d.ts.map +1 -0
  93. package/dist/markdownCharacterReferences.js +1127 -0
  94. package/dist/markdownCodeFence.d.ts +4 -0
  95. package/dist/markdownCodeFence.d.ts.map +1 -0
  96. package/dist/markdownCodeFence.js +167 -0
  97. package/dist/markdownExtensionNode.d.ts +88 -0
  98. package/dist/markdownExtensionNode.d.ts.map +1 -0
  99. package/dist/markdownExtensionNode.js +248 -0
  100. package/dist/markdownExtensions.d.ts +115 -0
  101. package/dist/markdownExtensions.d.ts.map +1 -0
  102. package/dist/markdownExtensions.js +392 -0
  103. package/dist/markdownHardLineBreak.d.ts +25 -0
  104. package/dist/markdownHardLineBreak.d.ts.map +1 -0
  105. package/dist/markdownHardLineBreak.js +59 -0
  106. package/dist/markdownHeading.d.ts +20 -0
  107. package/dist/markdownHeading.d.ts.map +1 -0
  108. package/dist/markdownHeading.js +30 -0
  109. package/dist/markdownLink.d.ts +5 -0
  110. package/dist/markdownLink.d.ts.map +1 -0
  111. package/dist/markdownLink.js +80 -0
  112. package/dist/markdownListExport.d.ts +3 -0
  113. package/dist/markdownListExport.d.ts.map +1 -0
  114. package/dist/markdownListExport.js +68 -0
  115. package/dist/markdownListIndentation.d.ts +8 -0
  116. package/dist/markdownListIndentation.d.ts.map +1 -0
  117. package/dist/markdownListIndentation.js +101 -0
  118. package/dist/markdownOrderedList.d.ts +3 -0
  119. package/dist/markdownOrderedList.d.ts.map +1 -0
  120. package/dist/markdownOrderedList.js +51 -0
  121. package/dist/markdownQuote.d.ts +22 -0
  122. package/dist/markdownQuote.d.ts.map +1 -0
  123. package/dist/markdownQuote.js +32 -0
  124. package/dist/markdownSerializers.d.ts +49 -0
  125. package/dist/markdownSerializers.d.ts.map +1 -0
  126. package/dist/markdownSerializers.js +83 -0
  127. package/dist/markdownSource.d.ts +71 -0
  128. package/dist/markdownSource.d.ts.map +1 -0
  129. package/dist/markdownSource.js +804 -0
  130. package/dist/markdownSpaceRuns.d.ts +24 -0
  131. package/dist/markdownSpaceRuns.d.ts.map +1 -0
  132. package/dist/markdownSpaceRuns.js +147 -0
  133. package/dist/markdownTable.d.ts +35 -0
  134. package/dist/markdownTable.d.ts.map +1 -0
  135. package/dist/markdownTable.js +227 -0
  136. package/dist/markdownTaskList.d.ts +48 -0
  137. package/dist/markdownTaskList.d.ts.map +1 -0
  138. package/dist/markdownTaskList.js +166 -0
  139. package/dist/markdownThematicBreak.d.ts +3 -0
  140. package/dist/markdownThematicBreak.d.ts.map +1 -0
  141. package/dist/markdownThematicBreak.js +55 -0
  142. package/dist/privateAttributes/layerPortalBoundary.stylex.d.ts +12 -0
  143. package/dist/privateAttributes/layerPortalBoundary.stylex.d.ts.map +1 -0
  144. package/dist/privateAttributes/layerPortalBoundary.stylex.js +16 -0
  145. package/dist/richtext.css +213 -0
  146. package/dist/textSemantics.d.ts +3 -0
  147. package/dist/textSemantics.d.ts.map +1 -0
  148. package/dist/textSemantics.js +87 -0
  149. package/package.json +158 -3
  150. package/src/RichTextEditor.doc.mjs +308 -0
  151. package/src/RichTextEditor.tsx +1109 -0
  152. package/src/RichTextEditorAutoLinkPlugin.doc.mjs +43 -0
  153. package/src/RichTextEditorAutoLinkPlugin.tsx +126 -0
  154. package/src/RichTextEditorToolbar.doc.mjs +92 -0
  155. package/src/RichTextEditorToolbar.tsx +871 -0
  156. package/src/RichTextView.doc.mjs +101 -0
  157. package/src/RichTextView.tsx +351 -0
  158. package/src/codeLanguages.ts +42 -0
  159. package/src/codeLineTokens.ts +241 -0
  160. package/src/doc-mjs.d.ts +23 -0
  161. package/src/editorNodes.ts +44 -0
  162. package/src/editorTheme.ts +550 -0
  163. package/src/index.ts +59 -0
  164. package/src/internal/CodeBackspacePlugin.tsx +96 -0
  165. package/src/internal/CodeBlockHeaderPlugin.tsx +282 -0
  166. package/src/internal/CodePastePlugin.tsx +144 -0
  167. package/src/internal/CodeSyntaxPlugin.tsx +493 -0
  168. package/src/internal/CodeTabPlugin.tsx +298 -0
  169. package/src/internal/DisabledLinkGuardPlugin.tsx +93 -0
  170. package/src/internal/ImageSourceCaretPlugin.tsx +159 -0
  171. package/src/internal/ListItemShortcutsPlugin.tsx +404 -0
  172. package/src/internal/MarkdownExtensionsPlugin.tsx +289 -0
  173. package/src/internal/SelectAllScopePlugin.tsx +86 -0
  174. package/src/internal/TableColumnFloorPlugin.tsx +99 -0
  175. package/src/internal/TablePastePlugin.tsx +223 -0
  176. package/src/internal/TableScrollRegionPlugin.tsx +107 -0
  177. package/src/internal/TaskCheckboxPlugin.tsx +246 -0
  178. package/src/internal/ToolbarLinkPopover.tsx +392 -0
  179. package/src/linkEditing.ts +20 -0
  180. package/src/linkForm.tsx +156 -0
  181. package/src/linkUtils.ts +106 -0
  182. package/src/markdown.ts +25 -0
  183. package/src/markdownCharacterReferences.ts +1137 -0
  184. package/src/markdownCodeFence.ts +216 -0
  185. package/src/markdownExtensionNode.ts +339 -0
  186. package/src/markdownExtensions.ts +496 -0
  187. package/src/markdownHardLineBreak.ts +73 -0
  188. package/src/markdownHeading.ts +33 -0
  189. package/src/markdownLink.ts +86 -0
  190. package/src/markdownListExport.ts +85 -0
  191. package/src/markdownListIndentation.ts +105 -0
  192. package/src/markdownOrderedList.ts +60 -0
  193. package/src/markdownQuote.ts +35 -0
  194. package/src/markdownSerializers.ts +108 -0
  195. package/src/markdownSource.ts +1045 -0
  196. package/src/markdownSpaceRuns.ts +164 -0
  197. package/src/markdownTable.ts +309 -0
  198. package/src/markdownTaskList.ts +222 -0
  199. package/src/markdownThematicBreak.ts +66 -0
  200. package/src/privateAttributes/layerPortalBoundary.stylex.ts +18 -0
  201. package/src/textSemantics.ts +104 -0
@@ -0,0 +1,204 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file CodeBlockHeaderPlugin.tsx
7
+ * @input Uses @lexical/react (composer context), @lexical/code (CodeNode),
8
+ * lexical, and core IconButton, Icon, useClipboard, and useTranslator.
9
+ * @output Exports CodeBlockHeaderPlugin, which draws core CodeBlock's header
10
+ * over every fenced code block: the language label and a copy button, or
11
+ * just the copy button in the corner when the block names no language.
12
+ * @position Rendered by RichTextEditor and RichTextView inside the positioned
13
+ * element that holds the content editable. The headers are siblings of the
14
+ * editable text, never inside it, so they are not part of the document and
15
+ * cannot be edited (spec:AST-061 FR8, DEC-4). The code block's theme class
16
+ * reserves the header's height, so the code sits where core Markdown's does.
17
+ */
18
+ import * as stylex from '@stylexjs/stylex';
19
+ import { useEffect, useState } from 'react';
20
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
21
+ import { $isCodeNode } from '@lexical/code';
22
+ import { $getNodeByKey, $getRoot } from 'lexical';
23
+ import { Icon } from '@blue-patterns/core/Icon';
24
+ import { IconButton } from '@blue-patterns/core/IconButton';
25
+ import { useClipboard } from '@blue-patterns/core/hooks';
26
+ import { useTranslator } from '@blue-patterns/core/i18n';
27
+ import { listedLanguage } from "../codeLanguages.js";
28
+ import '@blue-patterns/core/theme/tokens.stylex';
29
+ import { fontWeightVars, spacingVars, typeScaleVars, typographyVars } from '@blue-patterns/core/theme/tokens.stylex';
30
+
31
+ /** Where one code block's header goes, in the container's coordinates. */
32
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
33
+ const styles = {
34
+ header: {
35
+ kVAEAm: "x10l6tqk",
36
+ k1xSpc: "x78zum5",
37
+ kGNEyG: "x6s0dn4",
38
+ kjj79g: "x1qughib",
39
+ k8WAf4: "xce4md1",
40
+ kg3NbH: "x1pzlopt",
41
+ kB7OPa: "x9f619",
42
+ $$css: true
43
+ },
44
+ corner: {
45
+ kVAEAm: "x10l6tqk",
46
+ k1xSpc: "x78zum5",
47
+ kjj79g: "x13a6bvl",
48
+ kmVPX3: "xlsj2fj",
49
+ kB7OPa: "x9f619",
50
+ kfzvcC: "x47corl",
51
+ $$css: true
52
+ },
53
+ cornerButton: {
54
+ kfzvcC: "x67bb7w",
55
+ $$css: true
56
+ },
57
+ copyButton: {
58
+ kMwMTN: "x1mjzq1q",
59
+ $$css: true
60
+ },
61
+ placement: (top, left, width) => [{
62
+ k87sOh: top != null ? "xjbys53" : top,
63
+ kbCHJM: left != null ? "xgq9j65" : left,
64
+ kzqmXN: width != null ? "x5lhr3w" : width,
65
+ $$css: true
66
+ }, {
67
+ "--x-top": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(top),
68
+ "--x-left": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(left),
69
+ "--x-width": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(width)
70
+ }]
71
+ };
72
+
73
+ /**
74
+ * The language a header names, as core CodeBlock decides it: none for a fence
75
+ * without one, and none for exactly `plaintext`, which core Markdown gives a
76
+ * fence with no info string.
77
+ */
78
+ function displayLanguageOf(language) {
79
+ return language == null || language === '' || language === PLAIN_TEXT ? null : language;
80
+ }
81
+ const PLAIN_TEXT = 'plaintext';
82
+ function samePlacements(a, b) {
83
+ return a.length === b.length && a.every((placement, index) => placement.key === b[index].key && placement.language === b[index].language && placement.top === b[index].top && placement.left === b[index].left && placement.width === b[index].width);
84
+ }
85
+ function CodeBlockHeader({
86
+ placement,
87
+ label
88
+ }) {
89
+ const [editor] = useLexicalComposerContext();
90
+ const t = useTranslator();
91
+ const {
92
+ copy,
93
+ isCopied
94
+ } = useClipboard({
95
+ announce: t('@astryx.codeBlock.copied')
96
+ });
97
+ const copyButton = /*#__PURE__*/_jsx(IconButton, {
98
+ variant: "ghost",
99
+ size: "sm",
100
+ icon: /*#__PURE__*/_jsx(Icon, {
101
+ icon: isCopied ? 'check' : 'copy',
102
+ size: "sm",
103
+ color: "inherit"
104
+ }),
105
+ tooltip: t('@astryx.codeBlock.copyCode'),
106
+ label: isCopied ? t('@astryx.codeBlock.copied') : t('@astryx.codeBlock.copyCode'),
107
+ onClick: () => {
108
+ const code = editor.getEditorState().read(() => $getNodeByKey(placement.key)?.getTextContent() ?? '');
109
+ void copy(code);
110
+ },
111
+ xstyle: [styles.copyButton, placement.language == null && styles.cornerButton]
112
+ });
113
+ const position = styles.placement(placement.top, placement.left, placement.width);
114
+ if (placement.language == null) {
115
+ return /*#__PURE__*/_jsx("div", {
116
+ "data-richtext-code-header": "",
117
+ ...stylex.props(styles.corner, position),
118
+ children: copyButton
119
+ });
120
+ }
121
+ return /*#__PURE__*/_jsxs("div", {
122
+ "data-richtext-code-header": "",
123
+ ...stylex.props(styles.header, position),
124
+ children: [/*#__PURE__*/_jsx("span", {
125
+ ...{
126
+ className: "x141an7d x9m5x89 x1e4wzip x1ltkj2j x1mjzq1q xeuugli xb3r6kr xlyipyv xuxw1ft"
127
+ },
128
+ children: label ?? placement.language
129
+ }), copyButton]
130
+ });
131
+ }
132
+
133
+ /**
134
+ * Draws a header over each top-level code block and keeps it there as the
135
+ * document, the editor's size, or the window changes.
136
+ */
137
+ export function CodeBlockHeaderPlugin({
138
+ codeLanguages
139
+ } = {}) {
140
+ const [editor] = useLexicalComposerContext();
141
+ const [placements, setPlacements] = useState([]);
142
+ useEffect(() => {
143
+ let frame = 0;
144
+ const measure = () => {
145
+ frame = 0;
146
+ const root = editor.getRootElement();
147
+ const container = root?.parentElement;
148
+ if (root == null || container == null) {
149
+ setPlacements(current => current.length === 0 ? current : []);
150
+ return;
151
+ }
152
+ const origin = container.getBoundingClientRect();
153
+ const next = editor.getEditorState().read(() => $getRoot().getChildren().filter($isCodeNode).flatMap(node => {
154
+ const element = editor.getElementByKey(node.getKey());
155
+ if (element == null) {
156
+ return [];
157
+ }
158
+ const box = element.getBoundingClientRect();
159
+ // Inside the block's border, so the header lines up with the
160
+ // padding the theme reserves for it.
161
+ return [{
162
+ key: node.getKey(),
163
+ language: displayLanguageOf(node.getLanguage()),
164
+ top: box.top - origin.top + element.clientTop,
165
+ left: box.left - origin.left + element.clientLeft,
166
+ width: element.clientWidth
167
+ }];
168
+ }));
169
+ setPlacements(current => samePlacements(current, next) ? current : next);
170
+ };
171
+ const schedule = () => {
172
+ if (frame === 0) {
173
+ frame = requestAnimationFrame(measure);
174
+ }
175
+ };
176
+ const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
177
+ const unregisterRoot = editor.registerRootListener(root => {
178
+ observer?.disconnect();
179
+ if (root != null) {
180
+ observer?.observe(root);
181
+ }
182
+ schedule();
183
+ });
184
+ const unregisterUpdate = editor.registerUpdateListener(schedule);
185
+ window.addEventListener('resize', schedule);
186
+ schedule();
187
+ return () => {
188
+ cancelAnimationFrame(frame);
189
+ observer?.disconnect();
190
+ unregisterRoot();
191
+ unregisterUpdate();
192
+ window.removeEventListener('resize', schedule);
193
+ };
194
+ }, [editor]);
195
+ return /*#__PURE__*/_jsx(_Fragment, {
196
+ children: placements.map(placement => /*#__PURE__*/_jsx(CodeBlockHeader, {
197
+ placement: placement
198
+ // A fence matched in `codeLanguages` shows the value's name, as
199
+ // Markdown does (spec:AST-061).
200
+ ,
201
+ label: placement.language == null ? undefined : listedLanguage(codeLanguages, placement.language)?.name
202
+ }, placement.key))
203
+ });
204
+ }
@@ -0,0 +1,5 @@
1
+ import { type BaseSelection, type RangeSelection } from 'lexical';
2
+ /** Whether content inserted at the selection lands in a code block. */
3
+ export declare function $startsInCodeBlock(selection: BaseSelection | null): selection is RangeSelection;
4
+ export declare function CodePastePlugin(): null;
5
+ //# sourceMappingURL=CodePastePlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodePastePlugin.d.ts","sourceRoot":"","sources":["../../src/internal/CodePastePlugin.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAaL,KAAK,aAAa,EAElB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAKjB,uEAAuE;AACvE,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,aAAa,GAAG,IAAI,GAC9B,SAAS,IAAI,cAAc,CAQ7B;AAqCD,wBAAgB,eAAe,IAAI,IAAI,CAuDtC"}
@@ -0,0 +1,104 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file CodePastePlugin.tsx
7
+ * @input Uses @lexical/react (composer context), @lexical/code (CodeNode), and
8
+ * lexical.
9
+ * @output Exports CodePastePlugin, which makes rich content pasted or dropped
10
+ * into a code block go in as plain lines of code, and $startsInCodeBlock,
11
+ * which TablePastePlugin uses to leave such a paste to it.
12
+ * @position Rendered by RichTextEditor; always on; not exported. A paste
13
+ * whose selection starts in a code block goes in as plain text: the
14
+ * clipboard's plain text, or else one line per pasted block.
15
+ */
16
+ import { useEffect } from 'react';
17
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
18
+ import { $isCodeNode } from '@lexical/code';
19
+ import { $addUpdateTag, $findMatchingParent, $getSelection, $isElementNode, $isRangeSelection, $isSelectionCapturedInDecoratorInput, COMMAND_PRIORITY_LOW, isDOMNode, mergeRegister, PASTE_COMMAND, PASTE_TAG, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND } from 'lexical';
20
+
21
+ /** Clipboard types that carry more than plain text. */
22
+ const RICH_TYPES = ['text/html', 'application/x-lexical-editor'];
23
+
24
+ /** Whether content inserted at the selection lands in a code block. */
25
+ export function $startsInCodeBlock(selection) {
26
+ if (!$isRangeSelection(selection)) {
27
+ return false;
28
+ }
29
+ const start = selection.isBackward() ? selection.focus : selection.anchor;
30
+ const node = start.getNode();
31
+ // A link (an autolinked URL) can sit between the text and its code block.
32
+ return $findMatchingParent(node, $isCodeNode) !== null;
33
+ }
34
+
35
+ /**
36
+ * Clipboard nodes as plain lines: each block's text on a line of its own (a
37
+ * paragraph, a heading, a list item, a table cell), and inline content
38
+ * between blocks on one line.
39
+ */
40
+ function $plainLinesOf(nodes) {
41
+ const lines = [];
42
+ let inline = null;
43
+ const endInline = () => {
44
+ if (inline != null) {
45
+ lines.push(inline);
46
+ inline = null;
47
+ }
48
+ };
49
+ const visit = node => {
50
+ if (node.isInline()) {
51
+ inline = (inline ?? '') + node.getTextContent();
52
+ return;
53
+ }
54
+ endInline();
55
+ if ($isElementNode(node) && node.getChildren().some(child => !child.isInline())) {
56
+ node.getChildren().forEach(visit);
57
+ endInline();
58
+ } else {
59
+ lines.push(node.getTextContent());
60
+ }
61
+ };
62
+ nodes.forEach(visit);
63
+ endInline();
64
+ return lines.join('\n');
65
+ }
66
+ export function CodePastePlugin() {
67
+ const [editor] = useLexicalComposerContext();
68
+ useEffect(() => mergeRegister(
69
+ // Ahead of the rich-text paste, which inserts the clipboard's rich
70
+ // content when there is any.
71
+ editor.registerCommand(PASTE_COMMAND, event => {
72
+ // A paste into an input a decorator node renders is that input's.
73
+ if (isDOMNode(event.target) && $isSelectionCapturedInDecoratorInput(event.target)) {
74
+ return false;
75
+ }
76
+ const data = 'clipboardData' in event ? event.clipboardData : null;
77
+ if (!editor.isEditable() || data == null || !RICH_TYPES.some(type => data.types.includes(type))) {
78
+ return false;
79
+ }
80
+ const text = data.getData('text/plain');
81
+ const selection = $getSelection();
82
+ if (text === '' || !$startsInCodeBlock(selection)) {
83
+ return false;
84
+ }
85
+ event.preventDefault();
86
+ // Its own undo step, as every paste is.
87
+ $addUpdateTag(PASTE_TAG);
88
+ selection.insertRawText(text);
89
+ return true;
90
+ }, COMMAND_PRIORITY_LOW),
91
+ // Every insertion of clipboard nodes, a paste with no plain text or a
92
+ // drop, comes through here; ahead of the table's own handler.
93
+ editor.registerCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, ({
94
+ nodes,
95
+ selection
96
+ }) => {
97
+ if (!$startsInCodeBlock(selection)) {
98
+ return false;
99
+ }
100
+ selection.insertRawText($plainLinesOf(nodes));
101
+ return true;
102
+ }, COMMAND_PRIORITY_LOW)), [editor]);
103
+ return null;
104
+ }
@@ -0,0 +1,8 @@
1
+ import { type CodeLanguage } from '@blue-patterns/core/CodeBlock';
2
+ /** The class the theme adds to every code block (editorTheme.ts). */
3
+ export declare const CODE_SYNTAX_CLASS = "astryx-richtext-code";
4
+ export declare function CodeSyntaxPlugin({ codeLanguages, }?: {
5
+ /** Language values a fence may name (component:Markdown FR30). */
6
+ codeLanguages?: ReadonlyArray<CodeLanguage>;
7
+ }): null;
8
+ //# sourceMappingURL=CodeSyntaxPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeSyntaxPlugin.d.ts","sourceRoot":"","sources":["../../src/internal/CodeSyntaxPlugin.tsx"],"names":[],"mappings":"AAqCA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AAIvC,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,yBAAyB,CAAC;AAgMxD,wBAAgB,gBAAgB,CAAC,EAC/B,aAAa,GACd,GAAE;IACD,kEAAkE;IAClE,aAAa,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;CACxC,GAAG,IAAI,CAyPZ"}