@cyberyozh/text-editor 0.1.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 (209) hide show
  1. package/README.md +102 -0
  2. package/dist/editor.css +2069 -0
  3. package/dist/editor.css.map +1 -0
  4. package/dist/editor.d.mts +45 -0
  5. package/dist/editor.d.ts +45 -0
  6. package/dist/editor.js +6155 -0
  7. package/dist/editor.js.map +1 -0
  8. package/dist/editor.mjs +6118 -0
  9. package/dist/editor.mjs.map +1 -0
  10. package/dist/render/client.d.mts +24 -0
  11. package/dist/render/client.d.ts +24 -0
  12. package/dist/render/client.js +98 -0
  13. package/dist/render/client.js.map +1 -0
  14. package/dist/render/client.mjs +74 -0
  15. package/dist/render/client.mjs.map +1 -0
  16. package/dist/render.d.mts +58 -0
  17. package/dist/render.d.ts +58 -0
  18. package/dist/render.js +2521 -0
  19. package/dist/render.js.map +1 -0
  20. package/dist/render.mjs +2484 -0
  21. package/dist/render.mjs.map +1 -0
  22. package/dist/styles/index.css +2068 -0
  23. package/package.json +92 -0
  24. package/src/editor/commands/items.ts +374 -0
  25. package/src/editor/commands/suggestion.tsx +146 -0
  26. package/src/editor/components/button/button.css +56 -0
  27. package/src/editor/components/button/button.tsx +35 -0
  28. package/src/editor/components/button/index.ts +1 -0
  29. package/src/editor/components/common-modal/common-modal.css +85 -0
  30. package/src/editor/components/common-modal/common-modal.tsx +58 -0
  31. package/src/editor/components/common-modal/index.ts +1 -0
  32. package/src/editor/components/index.ts +3 -0
  33. package/src/editor/components/input/index.ts +1 -0
  34. package/src/editor/components/input/input.css +43 -0
  35. package/src/editor/components/input/input.tsx +22 -0
  36. package/src/editor/context/dialog-command.tsx +47 -0
  37. package/src/editor/context/index.ts +2 -0
  38. package/src/editor/context/translations-context.tsx +28 -0
  39. package/src/editor/controls/bubble-menu-content.tsx +394 -0
  40. package/src/editor/controls/callout-menu.tsx +169 -0
  41. package/src/editor/controls/character-count.tsx +36 -0
  42. package/src/editor/controls/commands-list.tsx +117 -0
  43. package/src/editor/controls/drag-handle.tsx +98 -0
  44. package/src/editor/controls/emoji-picker.tsx +62 -0
  45. package/src/editor/controls/index.ts +5 -0
  46. package/src/editor/controls/table-menu.tsx +322 -0
  47. package/src/editor/dialogs/add-katex-dialog/add-katex-dialog.css +115 -0
  48. package/src/editor/dialogs/add-katex-dialog/add-katex-dialog.tsx +116 -0
  49. package/src/editor/dialogs/add-katex-dialog/index.ts +1 -0
  50. package/src/editor/dialogs/add-link-dialog/add-link-dialog.css +105 -0
  51. package/src/editor/dialogs/add-link-dialog/add-link-dialog.tsx +177 -0
  52. package/src/editor/dialogs/add-link-dialog/index.ts +1 -0
  53. package/src/editor/dialogs/add-video-dialog/add-video-dialog.css +146 -0
  54. package/src/editor/dialogs/add-video-dialog/add-video-dialog.tsx +157 -0
  55. package/src/editor/dialogs/add-video-dialog/index.ts +1 -0
  56. package/src/editor/dialogs/image-dialog/image-dialog.css +101 -0
  57. package/src/editor/dialogs/image-dialog/image-dialog.tsx +276 -0
  58. package/src/editor/dialogs/image-dialog/index.ts +1 -0
  59. package/src/editor/dialogs/index.ts +4 -0
  60. package/src/editor/editor.tsx +247 -0
  61. package/src/editor/handlers/create-image-upload-handler.ts +24 -0
  62. package/src/editor/handlers/dialog-handlers.ts +143 -0
  63. package/src/editor/handlers/index.ts +8 -0
  64. package/src/editor/index.ts +3 -0
  65. package/src/extensions/base/callout.ts +138 -0
  66. package/src/extensions/base/code-block.ts +24 -0
  67. package/src/extensions/base/compatibility.ts +493 -0
  68. package/src/extensions/base/copyable-text.ts +56 -0
  69. package/src/extensions/base/custom-quote.ts +174 -0
  70. package/src/extensions/base/figure.ts +141 -0
  71. package/src/extensions/base/index.ts +19 -0
  72. package/src/extensions/base/link.ts +18 -0
  73. package/src/extensions/base/myth-reality.ts +45 -0
  74. package/src/extensions/base/prompt.ts +109 -0
  75. package/src/extensions/base/video.ts +29 -0
  76. package/src/extensions/editor/callout.ts +43 -0
  77. package/src/extensions/editor/code-block.ts +9 -0
  78. package/src/extensions/editor/commands.ts +43 -0
  79. package/src/extensions/editor/copyable-text.ts +16 -0
  80. package/src/extensions/editor/custom-quote.ts +54 -0
  81. package/src/extensions/editor/figure.ts +20 -0
  82. package/src/extensions/editor/get-editor-extensions.ts +113 -0
  83. package/src/extensions/editor/index.ts +25 -0
  84. package/src/extensions/editor/prompt.ts +43 -0
  85. package/src/extensions/editor/video.ts +23 -0
  86. package/src/extensions/render/get-render-extensions.ts +74 -0
  87. package/src/extensions/render/index.ts +6 -0
  88. package/src/extensions/views/components/callout.tsx +70 -0
  89. package/src/extensions/views/components/code-block.tsx +73 -0
  90. package/src/extensions/views/components/copy-button.tsx +52 -0
  91. package/src/extensions/views/components/copyable-text.tsx +11 -0
  92. package/src/extensions/views/components/custom-quote.tsx +64 -0
  93. package/src/extensions/views/components/figure.tsx +63 -0
  94. package/src/extensions/views/components/index.ts +7 -0
  95. package/src/extensions/views/components/prompt.tsx +43 -0
  96. package/src/extensions/views/components/video.tsx +40 -0
  97. package/src/extensions/views/node-views/callout.tsx +51 -0
  98. package/src/extensions/views/node-views/code-block.tsx +30 -0
  99. package/src/extensions/views/node-views/copyable-text.tsx +10 -0
  100. package/src/extensions/views/node-views/custom-quote.tsx +66 -0
  101. package/src/extensions/views/node-views/figure.tsx +38 -0
  102. package/src/extensions/views/node-views/index.ts +7 -0
  103. package/src/extensions/views/node-views/prompt.tsx +35 -0
  104. package/src/extensions/views/node-views/video.tsx +19 -0
  105. package/src/icons/Check.tsx +12 -0
  106. package/src/icons/Copy.tsx +15 -0
  107. package/src/icons/DragIcon.tsx +10 -0
  108. package/src/icons/Edit.tsx +12 -0
  109. package/src/icons/Quote.tsx +10 -0
  110. package/src/icons/X.tsx +13 -0
  111. package/src/icons/color/TiptapCalloutError.tsx +25 -0
  112. package/src/icons/color/TiptapCalloutInfo.tsx +18 -0
  113. package/src/icons/color/TiptapCalloutSuccess.tsx +49 -0
  114. package/src/icons/color/TiptapCalloutWarning.tsx +28 -0
  115. package/src/icons/color/index.ts +4 -0
  116. package/src/icons/index.ts +60 -0
  117. package/src/icons/menu/AddImage.tsx +10 -0
  118. package/src/icons/menu/AlignCenter.tsx +10 -0
  119. package/src/icons/menu/AlignLeft.tsx +10 -0
  120. package/src/icons/menu/AlignRight.tsx +10 -0
  121. package/src/icons/menu/ArrowDown.tsx +13 -0
  122. package/src/icons/menu/ArrowLeft.tsx +13 -0
  123. package/src/icons/menu/ArrowRight.tsx +13 -0
  124. package/src/icons/menu/ArrowUp.tsx +13 -0
  125. package/src/icons/menu/Blockquote.tsx +7 -0
  126. package/src/icons/menu/Bold.tsx +10 -0
  127. package/src/icons/menu/BulletList.tsx +10 -0
  128. package/src/icons/menu/CalloutError.tsx +10 -0
  129. package/src/icons/menu/CalloutInfo.tsx +12 -0
  130. package/src/icons/menu/CalloutSuccess.tsx +10 -0
  131. package/src/icons/menu/CalloutWarning.tsx +12 -0
  132. package/src/icons/menu/ClearFormatting.tsx +10 -0
  133. package/src/icons/menu/Code.tsx +10 -0
  134. package/src/icons/menu/CodeBlock.tsx +10 -0
  135. package/src/icons/menu/Copyable.tsx +10 -0
  136. package/src/icons/menu/CustomQuote.tsx +17 -0
  137. package/src/icons/menu/DeleteColumn.tsx +17 -0
  138. package/src/icons/menu/DeleteRow.tsx +17 -0
  139. package/src/icons/menu/Details.tsx +10 -0
  140. package/src/icons/menu/H2.tsx +10 -0
  141. package/src/icons/menu/H3.tsx +10 -0
  142. package/src/icons/menu/H4.tsx +10 -0
  143. package/src/icons/menu/H5.tsx +10 -0
  144. package/src/icons/menu/H6.tsx +10 -0
  145. package/src/icons/menu/Highlight.tsx +13 -0
  146. package/src/icons/menu/HorizontalRule.tsx +7 -0
  147. package/src/icons/menu/Italic.tsx +10 -0
  148. package/src/icons/menu/Link.tsx +10 -0
  149. package/src/icons/menu/LinkOff.tsx +10 -0
  150. package/src/icons/menu/Math.tsx +10 -0
  151. package/src/icons/menu/MergeCells.tsx +10 -0
  152. package/src/icons/menu/MythReality.tsx +10 -0
  153. package/src/icons/menu/OrderedList.tsx +10 -0
  154. package/src/icons/menu/Prompt.tsx +18 -0
  155. package/src/icons/menu/Redo.tsx +14 -0
  156. package/src/icons/menu/SplitCells.tsx +7 -0
  157. package/src/icons/menu/Strikethrough.tsx +10 -0
  158. package/src/icons/menu/Subscript.tsx +10 -0
  159. package/src/icons/menu/Superscript.tsx +10 -0
  160. package/src/icons/menu/Table.tsx +14 -0
  161. package/src/icons/menu/TableColumnHeading.tsx +7 -0
  162. package/src/icons/menu/TableRowHeading.tsx +10 -0
  163. package/src/icons/menu/TextColor.tsx +13 -0
  164. package/src/icons/menu/Underline.tsx +10 -0
  165. package/src/icons/menu/Undo.tsx +14 -0
  166. package/src/icons/menu/Video.tsx +14 -0
  167. package/src/icons/menu/index.ts +49 -0
  168. package/src/render/index.ts +22 -0
  169. package/src/render/static-renderer-config.tsx +206 -0
  170. package/src/render/tiptap-interactivity-provider.tsx +78 -0
  171. package/src/render/tiptap-render.tsx +102 -0
  172. package/src/styles/components.css +10 -0
  173. package/src/styles/editor/base.css +39 -0
  174. package/src/styles/editor/callout-menu.css +81 -0
  175. package/src/styles/editor/controls.css +57 -0
  176. package/src/styles/editor/emoji-picker.css +113 -0
  177. package/src/styles/editor/index.css +9 -0
  178. package/src/styles/editor/menus.css +16 -0
  179. package/src/styles/editor/states.css +43 -0
  180. package/src/styles/editor/typography.css +165 -0
  181. package/src/styles/editor/utilities.css +71 -0
  182. package/src/styles/editor/variables.css +70 -0
  183. package/src/styles/extensions/callout.css +155 -0
  184. package/src/styles/extensions/code-block.css +109 -0
  185. package/src/styles/extensions/commands-list.css +83 -0
  186. package/src/styles/extensions/custom-quote.css +103 -0
  187. package/src/styles/extensions/details.css +87 -0
  188. package/src/styles/extensions/figure.css +66 -0
  189. package/src/styles/extensions/index.css +11 -0
  190. package/src/styles/extensions/math.css +32 -0
  191. package/src/styles/extensions/myth-reality.css +59 -0
  192. package/src/styles/extensions/prompt.css +75 -0
  193. package/src/styles/extensions/table.css +253 -0
  194. package/src/styles/extensions/video.css +53 -0
  195. package/src/styles/styles.css +3 -0
  196. package/src/translations/en.json +158 -0
  197. package/src/translations/ru.json +158 -0
  198. package/src/types/image-handler.ts +33 -0
  199. package/src/types/index.ts +1 -0
  200. package/src/utils/copy-to-clipboard.ts +23 -0
  201. package/src/utils/custom-emoji.ts +174 -0
  202. package/src/utils/detect-video-hosting.ts +106 -0
  203. package/src/utils/get-shared-extensions.ts +45 -0
  204. package/src/utils/get-translations.ts +25 -0
  205. package/src/utils/handle-exit-node.ts +61 -0
  206. package/src/utils/image-src-resolver.ts +74 -0
  207. package/src/utils/index.ts +2 -0
  208. package/src/utils/migrate-legacy-callouts.ts +59 -0
  209. package/src/utils/pluralize.ts +38 -0
@@ -0,0 +1,20 @@
1
+ import { ReactNodeViewRenderer } from "@tiptap/react";
2
+ import { BaseFigure } from "../base";
3
+ import { FigureView } from "../views/node-views";
4
+ import { BaseLegacyFigure } from "../base/compatibility";
5
+
6
+ export const Figure = BaseFigure.extend({
7
+ addNodeView() {
8
+ return ReactNodeViewRenderer(FigureView);
9
+ },
10
+ });
11
+
12
+ /**
13
+ * Legacy Figure extension for backward compatibility with old Tiptap content.
14
+ * @deprecated Use {@link Figure} extension instead.
15
+ */
16
+ export const LegacyFigure = BaseLegacyFigure.extend({
17
+ addNodeView() {
18
+ return ReactNodeViewRenderer(FigureView);
19
+ },
20
+ });
@@ -0,0 +1,113 @@
1
+ import { Mathematics } from "@tiptap/extension-mathematics";
2
+ import { TableKit } from "@tiptap/extension-table";
3
+
4
+ import { Callout, LegacyBookAlert, LegacyBookTip } from "./callout";
5
+ import { CodeBlock } from "./code-block";
6
+ import {
7
+ CustomQuote,
8
+ CustomQuoteText,
9
+ CustomQuoteAuthor,
10
+ CustomQuoteSign,
11
+ LegacySEQuote,
12
+ } from "./custom-quote";
13
+ import { Video, LegacyYouTube } from "./video";
14
+ import { Commands } from "./commands";
15
+ import { getSharedExtensions } from "@/utils/get-shared-extensions";
16
+ import { CopyableText } from "./copyable-text";
17
+ import { BasePrompt } from "../base";
18
+ import { LegacyPromptSEContent, LegacyPromptSEHeader, PromptContent, PromptHeader } from "./prompt";
19
+ import { BaseLegacyPromptSE, BaseLegacyCustomBlockquote } from "../base/compatibility";
20
+ import { Figure, LegacyFigure } from "./figure";
21
+
22
+ import type { TiptapTranslations } from "@/utils/get-translations";
23
+ import { CharacterCount, Placeholder } from "@tiptap/extensions";
24
+
25
+ interface GetExtensionsOptions {
26
+ translations: TiptapTranslations;
27
+ suggestion?: any;
28
+ isEditable?: boolean;
29
+ getImageById?: (fileId: string) => string | null;
30
+ onKatexClick?: (latex: string, pos?: number) => void;
31
+ onFigureClick?: (attrs: any, pos: number) => void;
32
+ }
33
+
34
+ /**
35
+ * Get all Tiptap extensions for Editor instance
36
+ *
37
+ * This extensions can be used for static render (server-side)
38
+ */
39
+ export function getEditorExtensions(options: GetExtensionsOptions) {
40
+ const {
41
+ suggestion,
42
+ translations,
43
+ isEditable = false,
44
+ getImageById,
45
+ onKatexClick,
46
+ onFigureClick,
47
+ } = options;
48
+ const sharedExtensions = getSharedExtensions();
49
+
50
+ return [
51
+ ...sharedExtensions,
52
+ Callout,
53
+ CopyableText,
54
+ CodeBlock,
55
+ CustomQuote,
56
+ CustomQuoteText,
57
+ CustomQuoteAuthor,
58
+ CustomQuoteSign,
59
+ BasePrompt,
60
+ PromptHeader,
61
+ PromptContent,
62
+ Video,
63
+
64
+ // Configure with optional getImageById for URL resolution and onFigureClick callback
65
+ Figure.configure({ getImageById, onFigureClick }),
66
+ Mathematics.configure({
67
+ katexOptions: {
68
+ throwOnError: false,
69
+ },
70
+ inlineOptions: {
71
+ onClick: (node, pos) => {
72
+ onKatexClick?.(node.attrs.latex, pos);
73
+ },
74
+ },
75
+ }),
76
+ Placeholder.configure({
77
+ includeChildren: true,
78
+ placeholder: ({ node }) => {
79
+ if (!translations) return "";
80
+
81
+ if (node.type.name === "detailsSummary") {
82
+ return translations.editor?.detailsSummaryPlaceholder || "";
83
+ }
84
+
85
+ if (node.type.name === "tableCell") {
86
+ return "";
87
+ }
88
+
89
+ return translations.editor?.commandMenuPlaceholder || "";
90
+ },
91
+ }),
92
+ TableKit.configure({
93
+ table: { resizable: isEditable },
94
+ }),
95
+ Commands.configure({
96
+ suggestion,
97
+ }),
98
+ CharacterCount,
99
+
100
+ // ========================================================================
101
+ // Legacy Extensions (Deprecated - for backward compatibility only)
102
+ // ========================================================================
103
+ LegacyBookAlert,
104
+ LegacyBookTip,
105
+ LegacySEQuote,
106
+ BaseLegacyPromptSE,
107
+ LegacyPromptSEHeader,
108
+ LegacyPromptSEContent,
109
+ BaseLegacyCustomBlockquote,
110
+ LegacyYouTube,
111
+ LegacyFigure.configure({ getImageById, onFigureClick }),
112
+ ];
113
+ }
@@ -0,0 +1,25 @@
1
+ // export { Callout, BookAlert, BookTip } from "./callout";
2
+ // export { CodeBlock } from "./code-block";
3
+ // export { Commands } from "./commands";
4
+ // export { CopyableText } from "./copyable-text";
5
+ // export {
6
+ // CustomQuote,
7
+ // CustomQuoteText,
8
+ // CustomQuoteAuthor,
9
+ // CustomQuoteSign,
10
+ // CustomBlockquote,
11
+ // CustomQuoteSE,
12
+ // } from "./custom-quote";
13
+ // export { Figure, LegacyFigure, type FigureAttrs } from "./figure";
14
+ // export { InlineLatexSE } from "./inline-latex";
15
+ // export {
16
+ // Prompt,
17
+ // PromptHeader,
18
+ // PromptContent,
19
+ // PromptSE,
20
+ // PromptSEHeader,
21
+ // PromptSEContent,
22
+ // } from "./prompt";
23
+ // export { Video, YouTube } from "./video";
24
+
25
+ export { getEditorExtensions } from "./get-editor-extensions";
@@ -0,0 +1,43 @@
1
+ import { ReactNodeViewRenderer } from "@tiptap/react";
2
+
3
+ import { PromptHeaderView, PromptContentView } from "../views/node-views";
4
+ import { BasePromptContent, BasePromptHeader } from "../base";
5
+ import { BaseLegacyPromptSEContent, BaseLegacyPromptSEHeader } from "../base/compatibility";
6
+
7
+ export const PromptHeader = BasePromptHeader.extend({
8
+ addNodeView() {
9
+ return ReactNodeViewRenderer(PromptHeaderView);
10
+ },
11
+ });
12
+
13
+ export const PromptContent = BasePromptContent.extend({
14
+ addNodeView() {
15
+ return ReactNodeViewRenderer(PromptContentView);
16
+ },
17
+ });
18
+
19
+ // ============================================================================
20
+ // Legacy Prompt V2 Compatibility Extensions
21
+ // ============================================================================
22
+
23
+ /**
24
+ * Legacy PromptV2Header extension for backward compatibility with old Tiptap copy editor content.
25
+ * @deprecated Use {@link PromptHeader} instead.
26
+ * This extension is kept only for rendering old content that uses the `promptV2Header` node type.
27
+ */
28
+ export const LegacyPromptSEHeader = BaseLegacyPromptSEHeader.extend({
29
+ addNodeView() {
30
+ return ReactNodeViewRenderer(PromptHeaderView);
31
+ },
32
+ });
33
+
34
+ /**
35
+ * Legacy PromptV2Content extension for backward compatibility with old Tiptap copy editor content.
36
+ * @deprecated Use {@link PromptContent} instead.
37
+ * This extension is kept only for rendering old content that uses the `promptV2Content` node type.
38
+ */
39
+ export const LegacyPromptSEContent = BaseLegacyPromptSEContent.extend({
40
+ addNodeView() {
41
+ return ReactNodeViewRenderer(PromptContentView);
42
+ },
43
+ });
@@ -0,0 +1,23 @@
1
+ import { ReactNodeViewRenderer } from "@tiptap/react";
2
+
3
+ import { BaseVideo } from "../base/video";
4
+ import { VideoView } from "../views/node-views";
5
+ import { BaseLegacyYouTube } from "../base/compatibility";
6
+
7
+ export const Video = BaseVideo.extend({
8
+ addNodeView() {
9
+ return ReactNodeViewRenderer(VideoView);
10
+ },
11
+ });
12
+
13
+ /**
14
+ * Legacy YouTube extension for backward compatibility with old Tiptap content.
15
+ * @deprecated Use {@link Video} extension instead.
16
+ * This extension is kept only for rendering old content that uses the `youtube` node type.
17
+ * Renders using the same VideoView component.
18
+ */
19
+ export const LegacyYouTube = BaseLegacyYouTube.extend({
20
+ addNodeView() {
21
+ return ReactNodeViewRenderer(VideoView);
22
+ },
23
+ });
@@ -0,0 +1,74 @@
1
+ import { Mathematics } from "@tiptap/extension-mathematics";
2
+ import { TableKit } from "@tiptap/extension-table";
3
+
4
+ import {
5
+ BasePrompt,
6
+ BasePromptContent,
7
+ BasePromptHeader,
8
+ BaseCallout,
9
+ BaseCodeBlock,
10
+ CopyableText,
11
+ BaseCustomQuote,
12
+ BaseCustomQuoteAuthor,
13
+ BaseCustomQuoteSign,
14
+ BaseCustomQuoteText,
15
+ BaseVideo,
16
+ BaseFigure,
17
+ } from "../base";
18
+ import { getSharedExtensions } from "@/utils/get-shared-extensions";
19
+ import {
20
+ BaseLegacyCustomBlockquote,
21
+ BaseLegacyPromptSE,
22
+ BaseLegacyPromptSEContent,
23
+ BaseLegacyPromptSEHeader,
24
+ BaseLegacyBookAlert,
25
+ BaseLegacyBookTip,
26
+ BaseLegacySEQuote,
27
+ BaseLegacyYouTube,
28
+ BaseLegacyFigure,
29
+ } from "../base/compatibility";
30
+
31
+ export function getRenderExtensions() {
32
+ const sharedExtensions = getSharedExtensions();
33
+
34
+ return [
35
+ ...sharedExtensions,
36
+ CopyableText,
37
+ BaseCallout,
38
+ BaseCodeBlock,
39
+ BaseCustomQuote,
40
+ BaseCustomQuoteText,
41
+ BaseCustomQuoteAuthor,
42
+ BaseCustomQuoteSign,
43
+ BasePrompt,
44
+ BasePromptHeader,
45
+ BasePromptContent,
46
+ BaseVideo,
47
+ BaseFigure,
48
+
49
+ // Need to update
50
+ TableKit.configure({
51
+ table: { resizable: false },
52
+ }),
53
+
54
+ Mathematics.configure({
55
+ katexOptions: {
56
+ throwOnError: false,
57
+ },
58
+ }),
59
+
60
+ // ========================================================================
61
+ // Legacy Extensions (Deprecated - for backward compatibility only)
62
+ // ========================================================================
63
+ BaseLegacyBookAlert,
64
+ BaseLegacyBookTip,
65
+ BaseLegacySEQuote,
66
+ BaseLegacyPromptSE,
67
+ BaseLegacyPromptSEHeader,
68
+ BaseLegacyPromptSEContent,
69
+ BaseLegacyCustomBlockquote,
70
+ BaseLegacyYouTube,
71
+ BaseLegacyFigure,
72
+ // Update
73
+ ];
74
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Server/Render extensions - extensions configured for server-side static rendering
3
+ * Used with @tiptap/static-renderer for parsing and rendering Tiptap JSON
4
+ */
5
+
6
+ export { getRenderExtensions } from "./get-render-extensions";
@@ -0,0 +1,70 @@
1
+ import type { CalloutType } from "../../base";
2
+ import {
3
+ TiptapCalloutError,
4
+ TiptapCalloutInfo,
5
+ TiptapCalloutSuccess,
6
+ TiptapCalloutWarning,
7
+ } from "../../../icons/color";
8
+ import { ReactNode } from "react";
9
+ import { calloutIconComponents } from "../../../utils/custom-emoji";
10
+
11
+ const calloutIcons: Record<CalloutType, React.ReactNode> = {
12
+ info: <TiptapCalloutInfo />,
13
+ warning: <TiptapCalloutWarning />,
14
+ success: <TiptapCalloutSuccess />,
15
+ error: <TiptapCalloutError />,
16
+ };
17
+
18
+ const legacyTypeMap: Record<string, CalloutType> = {
19
+ question: "info",
20
+ idea: "warning",
21
+ info: "success",
22
+ error: "error",
23
+ };
24
+
25
+ interface Props {
26
+ type: CalloutType;
27
+ bgColor?: string | null;
28
+ emoji?: string | null;
29
+ children: ReactNode;
30
+ calloutType?: CalloutType;
31
+ iconWrapper?: (icon: ReactNode) => ReactNode;
32
+ }
33
+
34
+ export const Callout = ({ type, bgColor, emoji, children, iconWrapper, calloutType }: Props) => {
35
+ const isLegacySECallout = !!calloutType;
36
+ const finalType = isLegacySECallout ? legacyTypeMap[calloutType] : type;
37
+
38
+ const hasCustomColor = !!bgColor;
39
+ const className = hasCustomColor ? "callout-node" : `callout-node callout-${finalType}`;
40
+ const style = hasCustomColor ? { backgroundColor: bgColor } : undefined;
41
+
42
+ let icon: ReactNode;
43
+ if (emoji) {
44
+ if (emoji in calloutIconComponents) {
45
+ const IconComponent = calloutIconComponents[emoji as keyof typeof calloutIconComponents];
46
+ icon = <IconComponent />;
47
+ } else {
48
+ icon = emoji;
49
+ }
50
+ } else {
51
+ icon = calloutIcons[finalType];
52
+ }
53
+
54
+ const iconContent = iconWrapper ? iconWrapper(icon) : <div className="callout-icon">{icon}</div>;
55
+
56
+ return (
57
+ <div
58
+ className={className}
59
+ data-callout-type={hasCustomColor ? undefined : type}
60
+ data-bg-color={bgColor || undefined}
61
+ data-emoji={emoji || undefined}
62
+ style={style}
63
+ >
64
+ {iconContent}
65
+ <div className="callout-content-wrapper">
66
+ <div className="callout-content">{children}</div>
67
+ </div>
68
+ </div>
69
+ );
70
+ };
@@ -0,0 +1,73 @@
1
+ import { ChangeEvent, ReactNode, useMemo } from "react";
2
+ import html from "highlight.js/lib/languages/xml";
3
+ import { common, createLowlight } from "lowlight";
4
+
5
+ import type { TiptapTranslations } from "../../../utils/get-translations";
6
+ import { CopyButton } from "./copy-button";
7
+
8
+ interface CodeBlockProps {
9
+ language: string;
10
+ isEditable: boolean;
11
+ onLanguageChange?: (language: string) => void;
12
+ children: ReactNode;
13
+ translations?: TiptapTranslations;
14
+ }
15
+
16
+ export const CodeBlock = ({
17
+ language,
18
+ isEditable,
19
+ onLanguageChange,
20
+ children,
21
+ translations,
22
+ }: CodeBlockProps) => {
23
+ const languagesList = useMemo(() => {
24
+ const lowlight = createLowlight(common);
25
+ lowlight.register("html", html);
26
+ const list = lowlight.listLanguages();
27
+ return list.sort();
28
+ }, []);
29
+
30
+ const handleChange = (e: ChangeEvent<HTMLSelectElement>) => {
31
+ onLanguageChange?.(e.target.value);
32
+ };
33
+
34
+ return (
35
+ <div className="tiptap-code-block-wrapper">
36
+ <div className="tiptap-code-block-header">
37
+ {isEditable ? (
38
+ <select
39
+ className="tiptap-code-block-language-select"
40
+ value={language}
41
+ onChange={handleChange}
42
+ >
43
+ <option value="">{translations?.codeBlock.selectLanguage}</option>
44
+ {languagesList.map((lang) => (
45
+ <option
46
+ key={lang}
47
+ value={lang}
48
+ >
49
+ {lang}
50
+ </option>
51
+ ))}
52
+ </select>
53
+ ) : (
54
+ <span className="tiptap-code-block-language-text">
55
+ {language || translations?.codeBlock.selectLanguage}
56
+ </span>
57
+ )}
58
+ <CopyButton
59
+ iconSize={20}
60
+ color="white"
61
+ />
62
+ </div>
63
+ <pre className="tiptap-code-block">
64
+ <code
65
+ className="tiptap-code-block-content"
66
+ data-copy-content
67
+ >
68
+ {children}
69
+ </code>
70
+ </pre>
71
+ </div>
72
+ );
73
+ };
@@ -0,0 +1,52 @@
1
+ import { TiptapCopy, TiptapCheck } from "../../../icons";
2
+
3
+ interface CopyButtonProps {
4
+ iconSize?: number;
5
+ color?: "white" | "black" | "prompt";
6
+ }
7
+
8
+ /**
9
+ * Reusable copy button component for server-rendered content
10
+ * Works with a client-side interactivity provider that:
11
+ * - Handles click events via data-copy-action attribute
12
+ * - Copies content from nearest element marked with data-copy-content
13
+ * - Shows TiptapCopy icon by default
14
+ * - Switches to TiptapCheck icon for 1500ms after successful copy
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <div>
19
+ * <div data-copy-content>Text to copy</div>
20
+ * <CopyButton iconSize={16} />
21
+ * </div>
22
+ * ```
23
+ */
24
+ export const CopyButton = ({ iconSize = 16, color = "black" }: CopyButtonProps) => {
25
+ return (
26
+ <button
27
+ className={`copy-button copy-icon-${color}`}
28
+ data-copy-action="copy"
29
+ type="button"
30
+ >
31
+ <span
32
+ className="copy-icon"
33
+ data-copy-icon="default"
34
+ >
35
+ <TiptapCopy
36
+ width={iconSize}
37
+ height={iconSize}
38
+ />
39
+ </span>
40
+ <span
41
+ className="copy-icon-success"
42
+ data-copy-icon="success"
43
+ style={{ display: "none" }}
44
+ >
45
+ <TiptapCheck
46
+ width={iconSize}
47
+ height={iconSize}
48
+ />
49
+ </span>
50
+ </button>
51
+ );
52
+ };
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from "react";
2
+ import { CopyButton } from "./copy-button";
3
+
4
+ export const CopyableText = ({ children }: { children: ReactNode }) => {
5
+ return (
6
+ <span className="copyable">
7
+ <span data-copy-content>{children}</span>
8
+ <CopyButton iconSize={16} />
9
+ </span>
10
+ );
11
+ };
@@ -0,0 +1,64 @@
1
+ import { ReactNode } from "react";
2
+ import { TiptapQuote } from "../../../icons";
3
+
4
+ interface CustomQuoteProps {
5
+ children: ReactNode;
6
+ }
7
+
8
+ export const CustomQuote = ({ children }: CustomQuoteProps) => (
9
+ <div data-custom-quote="">
10
+ <div className="custom-quote-divider" />
11
+ <div className="custom-quote-svg-wrapper">
12
+ <TiptapQuote />
13
+ </div>
14
+ {children}
15
+ </div>
16
+ );
17
+
18
+ interface CustomQuoteTextProps {
19
+ children: ReactNode;
20
+ isEmpty?: boolean;
21
+ placeholder?: string;
22
+ }
23
+
24
+ export const CustomQuoteText = ({ children, isEmpty, placeholder }: CustomQuoteTextProps) => (
25
+ <div
26
+ data-custom-quote-text
27
+ className={isEmpty ? "is-empty" : ""}
28
+ data-placeholder={placeholder}
29
+ >
30
+ {children}
31
+ </div>
32
+ );
33
+
34
+ interface CustomQuoteAuthorProps {
35
+ children: ReactNode;
36
+ isEmpty?: boolean;
37
+ placeholder?: string;
38
+ }
39
+
40
+ export const CustomQuoteAuthor = ({ children, isEmpty, placeholder }: CustomQuoteAuthorProps) => (
41
+ <div
42
+ data-custom-quote-author=""
43
+ className={isEmpty ? "is-empty" : ""}
44
+ data-placeholder={placeholder}
45
+ >
46
+ {children}
47
+ </div>
48
+ );
49
+
50
+ interface CustomQuoteSignProps {
51
+ children: ReactNode;
52
+ isEmpty?: boolean;
53
+ placeholder?: string;
54
+ }
55
+
56
+ export const CustomQuoteSign = ({ children, isEmpty, placeholder }: CustomQuoteSignProps) => (
57
+ <div
58
+ data-custom-quote-sign=""
59
+ className={isEmpty ? "is-empty" : ""}
60
+ data-placeholder={placeholder}
61
+ >
62
+ {children}
63
+ </div>
64
+ );
@@ -0,0 +1,63 @@
1
+ import { ReactNode } from "react";
2
+
3
+ import { TiptapEdit } from "../../../icons";
4
+ import { resolveImageSrc } from "../../../utils/image-src-resolver";
5
+
6
+ interface FigureProps {
7
+ src?: string;
8
+ alt?: string;
9
+ title?: string;
10
+ caption?: string;
11
+ width?: number | null;
12
+ height?: number | null;
13
+ isEditable?: boolean;
14
+ onEditClick?: () => void;
15
+ children?: ReactNode;
16
+ fileId?: string | null;
17
+ getImageById?: (fileId: string) => string | null;
18
+ }
19
+
20
+ export const Figure = ({
21
+ src,
22
+ alt,
23
+ title,
24
+ caption,
25
+ width,
26
+ height,
27
+ isEditable,
28
+ onEditClick,
29
+ children,
30
+ fileId,
31
+ getImageById,
32
+ }: FigureProps) => {
33
+ const resolvedSrc = resolveImageSrc({ fileId, src }, { getImageById });
34
+
35
+ return (
36
+ <figure>
37
+ {resolvedSrc && (
38
+ <div className="figure-image-container">
39
+ <img
40
+ src={resolvedSrc}
41
+ alt={alt || ""}
42
+ title={title}
43
+ width={width || undefined}
44
+ height={height || undefined}
45
+ />
46
+ {isEditable && onEditClick && (
47
+ <button
48
+ type="button"
49
+ className="figure-edit-button"
50
+ onClick={onEditClick}
51
+ contentEditable={false}
52
+ aria-label="Редактировать изображение"
53
+ >
54
+ <TiptapEdit />
55
+ </button>
56
+ )}
57
+ </div>
58
+ )}
59
+ {caption && <figcaption>{caption}</figcaption>}
60
+ {children}
61
+ </figure>
62
+ );
63
+ };
@@ -0,0 +1,7 @@
1
+ export { Callout } from "./callout";
2
+ export { CodeBlock } from "./code-block";
3
+ export { CopyableText } from "./copyable-text";
4
+ export { CustomQuote, CustomQuoteText, CustomQuoteAuthor, CustomQuoteSign } from "./custom-quote";
5
+ export { Figure } from "./figure";
6
+ export { PromptHeader, PromptContent } from "./prompt";
7
+ export { Video } from "./video";