tiptap-notion-editor 0.5.0

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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/lib/NotionEditor.d.ts +58 -0
  4. package/lib/components/Draggable/index.d.ts +5 -0
  5. package/lib/components/ToggleButton.d.ts +16 -0
  6. package/lib/components/TooltipWrapper.d.ts +9 -0
  7. package/lib/components/blocks/attachment.d.ts +2 -0
  8. package/lib/components/blocks/code.d.ts +2 -0
  9. package/lib/components/blocks/emoji.d.ts +2 -0
  10. package/lib/components/blocks/image.d.ts +2 -0
  11. package/lib/components/blocks/list.d.ts +4 -0
  12. package/lib/components/blocks/separator.d.ts +2 -0
  13. package/lib/components/blocks/table.d.ts +2 -0
  14. package/lib/components/blocks/tableOfContents.d.ts +2 -0
  15. package/lib/components/blocks/types.d.ts +26 -0
  16. package/lib/components/blocks/typography.d.ts +8 -0
  17. package/lib/components/bubble/BubbleMoreOption.d.ts +5 -0
  18. package/lib/components/bubble/ImageBubbleMenu.d.ts +7 -0
  19. package/lib/components/bubble/IndentButtons.d.ts +5 -0
  20. package/lib/components/bubble/MyBubbleMenu.d.ts +5 -0
  21. package/lib/components/bubble/PickLink.d.ts +6 -0
  22. package/lib/components/bubble/TextTurnInto.d.ts +5 -0
  23. package/lib/components/bubble/icon.d.ts +4 -0
  24. package/lib/components/color/ColorDropdown.d.ts +5 -0
  25. package/lib/components/color/ColorItem.d.ts +5 -0
  26. package/lib/components/color/ColorSubMenu.d.ts +7 -0
  27. package/lib/components/color/HighlightButton.d.ts +15 -0
  28. package/lib/components/color/TextButton.d.ts +9 -0
  29. package/lib/components/color/constant.d.ts +12 -0
  30. package/lib/components/color/icon.d.ts +2 -0
  31. package/lib/components/color/type.d.ts +9 -0
  32. package/lib/components/color/utils.d.ts +5 -0
  33. package/lib/components/extensions/Indent.d.ts +16 -0
  34. package/lib/components/extensions/emoji-picker/EmojiList.d.ts +8 -0
  35. package/lib/components/extensions/emoji-picker/EmojiPicker.d.ts +14 -0
  36. package/lib/components/extensions/emoji-picker/emoji-suggestion.d.ts +3 -0
  37. package/lib/components/extensions/file-handle.d.ts +19 -0
  38. package/lib/components/extensions/global-block-background.d.ts +2 -0
  39. package/lib/components/extensions/index.d.ts +51 -0
  40. package/lib/components/extensions/mention/MentionList.d.ts +11 -0
  41. package/lib/components/extensions/mention/mentionSuggestion.d.ts +11 -0
  42. package/lib/components/extensions/mention/types.d.ts +12 -0
  43. package/lib/components/extensions/slash-command/MenuListGroup.d.ts +9 -0
  44. package/lib/components/extensions/slash-command/SlashMenu.d.ts +11 -0
  45. package/lib/components/extensions/slash-command/items.d.ts +3 -0
  46. package/lib/components/extensions/slash-command/slash-command.d.ts +7 -0
  47. package/lib/components/extensions/slash-command/suggestion.d.ts +3 -0
  48. package/lib/components/icons.d.ts +5 -0
  49. package/lib/components/node/attachment/AttachmentNode.d.ts +38 -0
  50. package/lib/components/node/attachment/AttachmentNodeView.d.ts +3 -0
  51. package/lib/components/node/attachment/AttachmentUploadNode.d.ts +37 -0
  52. package/lib/components/node/attachment/AttachmentUploadNodeView.d.ts +3 -0
  53. package/lib/components/node/attachment/context.d.ts +16 -0
  54. package/lib/components/node/attachment/index.d.ts +3 -0
  55. package/lib/components/node/image/CustomImage.d.ts +1 -0
  56. package/lib/components/node/image/ImageNodeView.d.ts +5 -0
  57. package/lib/components/node/image-upload/drop-zone-content.d.ts +4 -0
  58. package/lib/components/node/image-upload/hooks.d.ts +7 -0
  59. package/lib/components/node/image-upload/image-drop-area.d.ts +15 -0
  60. package/lib/components/node/image-upload/image-preview.d.ts +13 -0
  61. package/lib/components/node/image-upload/image-upload-node-extension.d.ts +58 -0
  62. package/lib/components/node/image-upload/image-upload-node-view.d.ts +2 -0
  63. package/lib/components/node/image-upload/index.d.ts +1 -0
  64. package/lib/components/node/image-upload/types.d.ts +66 -0
  65. package/lib/components/node/table-node/AddRowButton.d.ts +5 -0
  66. package/lib/components/node/table-node/CustomTable.d.ts +1 -0
  67. package/lib/components/node/table-node/TableAddRowColumnHandle.d.ts +7 -0
  68. package/lib/components/node/table-node/TableHandle.d.ts +4 -0
  69. package/lib/components/node/table-node/TableMenuHandle.d.ts +7 -0
  70. package/lib/components/node/table-node/TableSelectionOverlay.d.ts +7 -0
  71. package/lib/components/node/table-node/plugins/add-row-plugin.d.ts +9 -0
  72. package/lib/components/node/table-node/plugins/plugin-keys.d.ts +6 -0
  73. package/lib/components/node/table-node/plugins/table-menu-handle-plugin.d.ts +33 -0
  74. package/lib/components/node/table-node/plugins/table-selection-overlay.d.ts +10 -0
  75. package/lib/components/node/table-node/popover/AlignmentContent.d.ts +4 -0
  76. package/lib/components/node/table-node/popover/CellMenuPopover.d.ts +4 -0
  77. package/lib/components/node/table-node/popover/Colors.d.ts +4 -0
  78. package/lib/components/node/table-node/popover/TableMenuItem.d.ts +11 -0
  79. package/lib/components/node/table-node/popover/TableMenuPopover.d.ts +9 -0
  80. package/lib/components/node/table-node/table-kit.d.ts +2 -0
  81. package/lib/components/node/table-node/utils/getActiveTableCellAlignment.d.ts +14 -0
  82. package/lib/components/node/table-node/utils/getTableColumnMeta.d.ts +15 -0
  83. package/lib/components/node/table-node/utils/getTableContext.d.ts +16 -0
  84. package/lib/components/node/table-node/utils/index.d.ts +17 -0
  85. package/lib/components/node/table-node/utils/table.d.ts +51 -0
  86. package/lib/components/node/toc-node/TableOfContentsNode.d.ts +13 -0
  87. package/lib/components/node/toc-node/TocNodeView.d.ts +9 -0
  88. package/lib/components/toc-sidebar/TocPopover.d.ts +6 -0
  89. package/lib/components/toc-sidebar/TocSidebar.d.ts +9 -0
  90. package/lib/components/toc-sidebar/TocSidebarContent.d.ts +6 -0
  91. package/lib/components/toc-sidebar/TocUIList.d.ts +8 -0
  92. package/lib/components/ui/button.d.ts +10 -0
  93. package/lib/components/ui/command.d.ts +18 -0
  94. package/lib/components/ui/dialog.d.ts +17 -0
  95. package/lib/components/ui/dropdown-menu.d.ts +29 -0
  96. package/lib/components/ui/input-group.d.ts +16 -0
  97. package/lib/components/ui/input.d.ts +3 -0
  98. package/lib/components/ui/popover.d.ts +10 -0
  99. package/lib/components/ui/scroll-area.d.ts +5 -0
  100. package/lib/components/ui/separator.d.ts +4 -0
  101. package/lib/components/ui/textarea.d.ts +3 -0
  102. package/lib/components/ui/tooltip.d.ts +7 -0
  103. package/lib/i18n/context.d.ts +15 -0
  104. package/lib/i18n/index.d.ts +2 -0
  105. package/lib/i18n/messages.d.ts +202 -0
  106. package/lib/index.cjs +9 -0
  107. package/lib/index.cjs.map +1 -0
  108. package/lib/index.d.ts +15 -0
  109. package/lib/index.js +5188 -0
  110. package/lib/index.js.map +1 -0
  111. package/lib/lib/aspect-ratio.d.ts +21 -0
  112. package/lib/lib/collect-file-urls.d.ts +10 -0
  113. package/lib/lib/tiptap-utils.d.ts +173 -0
  114. package/lib/lib/use-event.d.ts +1 -0
  115. package/lib/lib/utils.d.ts +25 -0
  116. package/lib/styles/colors.css +88 -0
  117. package/lib/styles/editor.css +268 -0
  118. package/lib/styles/image-upload.css +256 -0
  119. package/lib/styles/image.css +113 -0
  120. package/lib/styles/index.css +18 -0
  121. package/lib/styles/prosemirror.css +271 -0
  122. package/lib/styles/table.css +243 -0
  123. package/lib/styles/tokens.css +66 -0
  124. package/package.json +114 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aicademy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # tiptap-notion-editor
2
+
3
+ Editor rich text kiểu Notion, dựng trên Tiptap 3.
4
+
5
+ Slash command, bubble menu, kéo-thả block, bảng có handle, upload ảnh, công thức
6
+ toán (KaTeX), emoji, `@mention` và mục lục ở lề.
7
+
8
+ ## Cài đặt
9
+
10
+ ```bash
11
+ pnpm add tiptap-notion-editor
12
+ ```
13
+
14
+ Peer dependency phải có sẵn trong app chủ — đây là chủ ý, không phải thiếu sót:
15
+ gói kèm `@tiptap/*` sẽ tạo instance ProseMirror thứ hai và schema từ hai instance
16
+ khác nhau không nhận nhau.
17
+
18
+ ```bash
19
+ pnpm add @tiptap/core @tiptap/pm @tiptap/react react react-dom
20
+ ```
21
+
22
+ ## Dùng
23
+
24
+ ```tsx
25
+ import { NotionEditor } from "tiptap-notion-editor";
26
+ import "tiptap-notion-editor/style.css";
27
+
28
+ export function PageEditor({ page }) {
29
+ return (
30
+ <NotionEditor
31
+ key={page.id}
32
+ content={page.content}
33
+ onChange={(json) => savePage(page.id, json)}
34
+ uploadImage={async (file) => {
35
+ const url = await uploadToStorage(file);
36
+ return url;
37
+ }}
38
+ mentionSource={async (query) => {
39
+ const users = await searchUsers(query);
40
+ return users.map((u) => ({ id: u.id, label: u.fullName }));
41
+ }}
42
+ />
43
+ );
44
+ }
45
+ ```
46
+
47
+ ## Tailwind
48
+
49
+ Component dùng class tiện ích của Tailwind, và các class đó do **app chủ** biên
50
+ dịch chứ không nằm sẵn trong `style.css`. Thêm dòng sau vào file CSS entry của
51
+ app, ngay sau `@import "tailwindcss"`:
52
+
53
+ ```css
54
+ @source "../node_modules/tiptap-notion-editor/lib/*.js";
55
+ ```
56
+
57
+ Không có dòng này editor vẫn chạy nhưng gần như không có style.
58
+
59
+ Editor cũng đọc các biến theme của app (`--color-background`, `--color-border`,
60
+ `--color-primary`…). Thiếu biến nào thì token trong `lib/styles/tokens.css` tự
61
+ rơi về giá trị dự phòng.
62
+
63
+ ## Ngôn ngữ
64
+
65
+ Mặc định là **tiếng Việt**. Đổi bằng prop `locale`:
66
+
67
+ ```tsx
68
+ <NotionEditor locale="en" />
69
+ ```
70
+
71
+ Từ điển gồm hai bản `vi` và `en`, xuất ra ngoài để app chủ ghi đè từng chuỗi
72
+ mà không phải fork package:
73
+
74
+ ```tsx
75
+ import { NotionEditor, getMessages, type Messages } from "tiptap-notion-editor";
76
+
77
+ const t: Messages = getMessages("vi");
78
+ const custom: Messages = {
79
+ ...t,
80
+ slash: { ...t.slash, groups: { ...t.slash.groups, insert: "Thêm vào" } },
81
+ };
82
+ ```
83
+
84
+ Kiểu `Messages` suy ra từ bản tiếng Việt, nên thiếu một khoá ở bản dịch khác là
85
+ lỗi biên dịch chứ không phải chuỗi rỗng lúc chạy.
86
+
87
+ ## Props
88
+
89
+ | Prop | Kiểu | Mặc định | Ý nghĩa |
90
+ | --- | --- | --- | --- |
91
+ | `content` | `JSONContent \| string` | — | Nội dung khởi tạo. **Không kiểm soát** — xem ghi chú bên dưới. |
92
+ | `onChange` | `(json, editor) => void` | — | Gọi mỗi lần document đổi. |
93
+ | `onReady` | `(editor) => void` | — | Gọi một lần khi editor khởi tạo xong. |
94
+ | `editable` | `boolean` | `true` | `false` để chỉ đọc; đổi được lúc chạy. |
95
+ | `uploadImage` | `(file, onProgress?, signal?) => Promise<string>` | — | Đẩy ảnh lên server, trả URL. |
96
+ | `maxImageSize` | `number` | `1048576` | Giới hạn dung lượng ảnh, tính bằng byte. |
97
+ | `uploadAttachment` | `(file, onProgress?, signal?) => Promise<string \| { src?, fileId? }>` | — | Tải tệp đính kèm lên. Trả `src` nếu storage cấp URL cố định, trả `fileId` nếu storage riêng tư chỉ phát URL ngắn hạn. |
98
+ | `maxAttachmentSize` | `number` | `26214400` | Giới hạn dung lượng tệp đính kèm, tính bằng byte. |
99
+ | `onOpenAttachment` | `(attachment) => void` | — | Mở tệp chỉ có `fileId`. Tệp có `src` dùng thẻ `<a>` thật nên không gọi tới. |
100
+ | `mentionSource` | `(query) => MentionItem[] \| Promise<MentionItem[]>` | — | Không truyền thì tắt hẳn `@mention`. |
101
+ | `locale` | `"vi" \| "en"` | `"vi"` | Ngôn ngữ của nhãn trong editor. |
102
+ | `placeholder` | `string \| (({ editor, node }) => string)` | — | Chữ mờ cho document rỗng. Heading rỗng luôn hiện `Heading N`; node rỗng khác không hiện gì. Truyền hàm để tự quyết hoàn toàn. |
103
+ | `showToc` | `boolean` | `true` | Thanh mục lục ở lề phải. |
104
+ | `tocVariant` | `"content" \| "line"` | `"line"` | Kiểu hiển thị mục lục. |
105
+ | `onReplaceImage` | `() => void` | — | Xử lý nút "Replace" trên bubble menu của ảnh. |
106
+ | `extensions` | `AnyExtension[]` | `[]` | Extension Tiptap bổ sung. |
107
+ | `className` / `editorClassName` | `string` | — | Class cho khung ngoài / vùng soạn thảo. |
108
+ | `ref` | `Ref<NotionEditorHandle>` | — | Truy cập `editor`, `getJSON`, `getHTML`, `setContent`, `focus`. |
109
+
110
+ ### Tệp đính kèm
111
+
112
+ Package không biết gì về storage. Nó gọi `uploadAttachment`, lưu lại thứ hàm đó
113
+ trả về, và khi người dùng bấm tải thì hoặc dùng `src` trực tiếp, hoặc gọi
114
+ `onOpenAttachment` để app chủ tự lấy nội dung.
115
+
116
+ ```tsx
117
+ <NotionEditor
118
+ uploadAttachment={async (file) => {
119
+ const { fileId } = await uploadToPrivateStorage(file);
120
+ // Storage riêng tư chỉ phát URL ngắn hạn, nhúng vào nội dung là bảo đảm
121
+ // nó hỏng sau vài phút — nên lưu id và đổi lấy URL lúc cần.
122
+ return { fileId };
123
+ }}
124
+ onOpenAttachment={async ({ fileId, name }) => {
125
+ const blob = await fetchFromPrivateStorage(fileId);
126
+ saveAs(blob, name);
127
+ }}
128
+ />
129
+ ```
130
+
131
+ `collectFileUrls(doc)` trả về mọi URL tệp mà một document đang tham chiếu, đã
132
+ loại ảnh base64 — dùng khi app chủ cần dọn storage sau khi xoá trang.
133
+
134
+ ### `content` không phải prop kiểm soát
135
+
136
+ Đổi giá trị `content` sẽ **không** nạp lại document. Muốn chuyển sang document
137
+ khác thì remount bằng `key` như ví dụ trên — cách này rẻ hơn việc so sánh cây
138
+ node, và tránh con trỏ nhảy về đầu bài mỗi khi state cha render lại giữa lúc
139
+ đang gõ. Nếu cần ghi đè có chủ đích thì dùng `ref.current.setContent(...)`.
140
+
141
+ ### Upload ảnh
142
+
143
+ Không truyền `uploadImage` thì khối upload báo lỗi khi người dùng chọn file, còn
144
+ ảnh kéo-thả rơi về nhúng base64. Base64 làm document phình rất nhanh, nên đừng
145
+ để mặc định này đi vào nội dung lưu xuống backend.
146
+
147
+ ## Phát triển
148
+
149
+ ```bash
150
+ pnpm install
151
+ pnpm build # -> lib/
152
+ pnpm type-check
153
+ ```
154
+
155
+ ### Thử với app chủ trước khi publish
156
+
157
+ Dùng tarball, **không** dùng `link:` hay `pnpm link`:
158
+
159
+ ```bash
160
+ pnpm build && pnpm pack # trong repo này
161
+ pnpm add file:../notion-editor/aicademy-notion-editor-0.1.0.tgz # trong app chủ
162
+ ```
163
+
164
+ `link:` trỏ ra ngoài cây `node_modules` của app, nên package vẫn nạp `react` và
165
+ `prosemirror-*` từ `node_modules` của chính nó. Hai bản ProseMirror giữ hai bộ
166
+ đếm `PluginKey` riêng, cùng sinh ra key `plugin$`, và ProseMirror ném
167
+ `RangeError: Adding different instances of a keyed plugin` ngay lúc dựng editor
168
+ view. `resolve.dedupe` của Vite không cứu được, vì Vitest coi package nằm ngoài
169
+ thư mục gốc là external rồi để Node tự resolve.
170
+
171
+ Cài từ tarball thì pnpm đặt package vào đúng store của app và peer dependency
172
+ resolve về một bản duy nhất — giống hệt lúc cài từ npm.
@@ -0,0 +1,58 @@
1
+ import { Editor, JSONContent } from '@tiptap/core';
2
+ import { NotionEditorExtensionOptions } from './components/extensions';
3
+ import { Locale } from './i18n';
4
+ import { AttachmentAttributes } from './components/node/attachment';
5
+ export type NotionEditorHandle = {
6
+ /** Instance Tiptap, cho các thao tác không nằm trong props. */
7
+ editor: Editor | null;
8
+ /** Nội dung hiện tại dưới dạng JSON. */
9
+ getJSON: () => JSONContent | null;
10
+ /** Nội dung hiện tại dưới dạng HTML. */
11
+ getHTML: () => string;
12
+ /** Ghi đè toàn bộ nội dung mà không phát `onChange`. */
13
+ setContent: (content: JSONContent | string) => void;
14
+ focus: () => void;
15
+ };
16
+ export type NotionEditorProps = NotionEditorExtensionOptions & {
17
+ /**
18
+ * Nội dung khởi tạo. Đây là prop **không kiểm soát**: thay đổi giá trị sẽ
19
+ * không nạp lại document. Khi chuyển sang document khác, hãy remount bằng
20
+ * `key` — cách này rẻ hơn và tránh con trỏ nhảy lung tung khi đang gõ.
21
+ */
22
+ content?: JSONContent | string;
23
+ /** Gọi mỗi lần document đổi. */
24
+ onChange?: (json: JSONContent, editor: Editor) => void;
25
+ /** Gọi một lần khi editor sẵn sàng. */
26
+ onReady?: (editor: Editor) => void;
27
+ /** false để chuyển sang chế độ chỉ đọc. Đổi lúc chạy được. */
28
+ editable?: boolean;
29
+ /** Hiện thanh điều hướng mục lục ở lề phải. */
30
+ showToc?: boolean;
31
+ /** Kiểu hiển thị mục lục. */
32
+ tocVariant?: "content" | "line";
33
+ /**
34
+ * Mở một tệp đính kèm không có URL công khai.
35
+ *
36
+ * Chỉ cần khi `uploadAttachment` trả về `fileId`: lúc đó chỉ app chủ mới
37
+ * đổi được id lấy nội dung. Tệp có `src` dùng thẻ <a> thật, không gọi tới.
38
+ */
39
+ onOpenAttachment?: (attachment: AttachmentAttributes) => void;
40
+ /** Xử lý nút "Replace" trên bubble menu của ảnh. */
41
+ onReplaceImage?: () => void;
42
+ className?: string;
43
+ /** Class gắn vào vùng soạn thảo, nối sau bộ class typography mặc định. */
44
+ editorClassName?: string;
45
+ /** Ngôn ngữ của nhãn trong editor. Mặc định tiếng Việt. */
46
+ locale?: Locale;
47
+ autofocus?: boolean;
48
+ ref?: React.Ref<NotionEditorHandle>;
49
+ };
50
+ /**
51
+ * Editor kiểu Notion: slash command, bubble menu, kéo-thả block, bảng, ảnh,
52
+ * công thức toán và mục lục.
53
+ *
54
+ * Component tự bọc `TooltipProvider` và `EditorContext` nên chỗ dùng chỉ cần
55
+ * render thẻ này. Style phải được import riêng một lần cho cả app:
56
+ * `import "tiptap-notion-editor/style.css"`.
57
+ */
58
+ export declare function NotionEditor({ content, onChange, onReady, editable, showToc, tocVariant, onOpenAttachment, onReplaceImage, className, editorClassName, locale, autofocus, ref, ...extensionOptions }: NotionEditorProps): import("react").JSX.Element | null;
@@ -0,0 +1,5 @@
1
+ import { Editor } from '@tiptap/core';
2
+ declare const Dragable: ({ editor }: {
3
+ editor: Editor | null;
4
+ }) => import("react").JSX.Element | undefined;
5
+ export default Dragable;
@@ -0,0 +1,16 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ import { default as React } from 'react';
3
+ interface ToggleButtonProps {
4
+ onClick: () => void;
5
+ isActive?: boolean;
6
+ icon: LucideIcon | React.JSX.Element;
7
+ className?: string;
8
+ text?: string;
9
+ showTooltip?: boolean;
10
+ tooltip?: string;
11
+ disabled?: boolean;
12
+ size?: "icon" | "default" | "xs" | "sm" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
13
+ [key: string]: any;
14
+ }
15
+ declare const ToggleButton: ({ onClick, isActive, icon, className, text, size, showTooltip, tooltip, disabled, ...props }: ToggleButtonProps) => React.JSX.Element;
16
+ export default ToggleButton;
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ interface PropsType {
3
+ children: React.ReactNode;
4
+ content: string | undefined;
5
+ showTooltip?: boolean;
6
+ className?: string;
7
+ }
8
+ declare const TooltipWrapper: ({ children, content, className, showTooltip, }: PropsType) => React.JSX.Element;
9
+ export default TooltipWrapper;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const attachment: BlockItem;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const htmlCodeBlock: BlockItem;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const emoji: BlockItem;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const uploadImage: BlockItem;
@@ -0,0 +1,4 @@
1
+ import { BlockItem } from './types';
2
+ export declare const bulletList: BlockItem;
3
+ export declare const orderedList: BlockItem;
4
+ export declare const taskList: BlockItem;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const separator: BlockItem;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const table: BlockItem;
@@ -0,0 +1,2 @@
1
+ import { BlockItem } from './types';
2
+ export declare const tableOfContents: BlockItem;
@@ -0,0 +1,26 @@
1
+ import { Range, Editor } from '@tiptap/core';
2
+ import { JSX } from 'react/jsx-runtime';
3
+ export interface CommandProps {
4
+ editor: Editor;
5
+ range: Range;
6
+ }
7
+ export type BlockItem = {
8
+ title: string;
9
+ description?: string;
10
+ searchTerms: string[];
11
+ icon?: JSX.Element;
12
+ render?: (editor: Editor) => JSX.Element | null | true;
13
+ preview?: string | ((editor: Editor) => JSX.Element | null);
14
+ } & ({
15
+ command: (options: CommandProps) => void;
16
+ id?: never;
17
+ commands?: never;
18
+ } | {
19
+ id: string;
20
+ command?: never;
21
+ commands?: BlockItem[];
22
+ });
23
+ export type BlockGroupItem = {
24
+ title: string;
25
+ commands: BlockItem[];
26
+ };
@@ -0,0 +1,8 @@
1
+ import { BlockItem } from './types';
2
+ export declare const text: BlockItem;
3
+ export declare const heading1: BlockItem;
4
+ export declare const heading2: BlockItem;
5
+ export declare const heading3: BlockItem;
6
+ export declare const hardBreak: BlockItem;
7
+ export declare const blockquote: BlockItem;
8
+ export declare const clearLine: BlockItem;
@@ -0,0 +1,5 @@
1
+ import { Editor } from '@tiptap/core';
2
+ declare const BubbleMoreOption: ({ editor }: {
3
+ editor: Editor;
4
+ }) => import("react").JSX.Element;
5
+ export default BubbleMoreOption;
@@ -0,0 +1,7 @@
1
+ import { Editor } from '@tiptap/core';
2
+ interface ImageBubbleMenuProps {
3
+ editor: Editor | null;
4
+ onReplaceClick: () => void;
5
+ }
6
+ declare const ImageBubbleMenu: ({ editor, onReplaceClick }: ImageBubbleMenuProps) => import("react").JSX.Element | undefined;
7
+ export default ImageBubbleMenu;
@@ -0,0 +1,5 @@
1
+ import { Editor } from '@tiptap/react';
2
+ declare const IndentButtons: ({ editor }: {
3
+ editor: Editor;
4
+ }) => import("react").JSX.Element;
5
+ export default IndentButtons;
@@ -0,0 +1,5 @@
1
+ import { Editor } from '@tiptap/core';
2
+ declare const MyBubbleMenu: ({ editor }: {
3
+ editor: Editor | null;
4
+ }) => import("react").JSX.Element | undefined;
5
+ export default MyBubbleMenu;
@@ -0,0 +1,6 @@
1
+ import { default as React } from 'react';
2
+ import { Editor } from '@tiptap/core';
3
+ declare const PickLink: ({ editor }: {
4
+ editor: Editor;
5
+ }) => React.JSX.Element;
6
+ export default PickLink;
@@ -0,0 +1,5 @@
1
+ import { Editor } from '@tiptap/core';
2
+ declare const TextTurnInto: ({ editor }: {
3
+ editor: Editor;
4
+ }) => import("react").JSX.Element;
5
+ export default TextTurnInto;
@@ -0,0 +1,4 @@
1
+ export declare const AlignLeft: (props: any) => import("react").JSX.Element;
2
+ export declare const AlignRight: (props: any) => import("react").JSX.Element;
3
+ export declare const AlignCenter: (props: any) => import("react").JSX.Element;
4
+ export declare const CaptionIcon: (props: any) => import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { Editor } from '@tiptap/core';
2
+ declare const ColorDropdown: ({ editor }: {
3
+ editor: Editor;
4
+ }) => import("react").JSX.Element;
5
+ export default ColorDropdown;
@@ -0,0 +1,5 @@
1
+ import { Color } from './type';
2
+ export declare const ColorItem: ({ color, onClick, }: {
3
+ color: Color;
4
+ onClick: () => void;
5
+ }) => import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { Color } from './type';
2
+ import { Editor } from '@tiptap/core';
3
+ declare const Colors: ({ editor, setColor, }: {
4
+ editor: Editor | null;
5
+ setColor: (color: Color) => void;
6
+ }) => import("react").JSX.Element;
7
+ export default Colors;
@@ -0,0 +1,15 @@
1
+ import { Editor } from '@tiptap/react';
2
+ type Color = {
3
+ name: string;
4
+ value: string;
5
+ type: string;
6
+ };
7
+ interface HighlightButtonProps {
8
+ tooltip: string;
9
+ color: Color;
10
+ onClick: () => void;
11
+ isActive?: boolean;
12
+ editor: Editor;
13
+ }
14
+ declare const HighlightButton: ({ tooltip, color, onClick, editor, }: HighlightButtonProps) => import("react").JSX.Element;
15
+ export default HighlightButton;
@@ -0,0 +1,9 @@
1
+ import { Editor } from '@tiptap/core';
2
+ interface TextButtonProps {
3
+ tooltip: string;
4
+ color: string;
5
+ onClick: () => void;
6
+ editor: Editor;
7
+ }
8
+ declare const TextButton: ({ tooltip, color, onClick, editor }: TextButtonProps) => import("react").JSX.Element;
9
+ export default TextButton;
@@ -0,0 +1,12 @@
1
+ import { Color, GroupColors } from './type';
2
+ import { Messages } from '../../i18n';
3
+ export declare const RECENT_COLORS_KEY = "recentlyUsedColors";
4
+ export declare const MAX_RECENT = 3;
5
+ export declare const colors: Color[];
6
+ /**
7
+ * Nhóm màu, dựng theo ngôn ngữ đang dùng.
8
+ *
9
+ * Là hàm chứ không phải hằng vì nhãn phải dịch được, mà module cấp cao nhất
10
+ * thì không gọi hook được.
11
+ */
12
+ export declare const createGroupColors: (t: Messages) => GroupColors[];
@@ -0,0 +1,2 @@
1
+ export declare const TextIcon: (props: any) => import("react").JSX.Element;
2
+ export declare const AlignmentIcon: (props: any) => import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ export type Color = {
2
+ name: string;
3
+ value: string;
4
+ type: string;
5
+ };
6
+ export type GroupColors = {
7
+ title: string;
8
+ colors: Color[];
9
+ };
@@ -0,0 +1,5 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ import { Messages } from '../../i18n';
3
+ import { Color, GroupColors } from './type';
4
+ export declare const getRecentColors: () => Color[];
5
+ export declare const handleAddRecentUsed: (color: Color, setItems: Dispatch<SetStateAction<GroupColors[]>>, t: Messages) => void;
@@ -0,0 +1,16 @@
1
+ import { Extension } from '@tiptap/core';
2
+ export interface IndentOptions {
3
+ types: string[];
4
+ minLevel: number;
5
+ maxLevel: number;
6
+ indentSize: number;
7
+ }
8
+ declare module '@tiptap/core' {
9
+ interface Commands<ReturnType> {
10
+ indent: {
11
+ indent: () => ReturnType;
12
+ outdent: () => ReturnType;
13
+ };
14
+ }
15
+ }
16
+ export declare const Indent: Extension<any, any>;
@@ -0,0 +1,8 @@
1
+ import { EmojiItem } from '@tiptap/extension-emoji';
2
+ interface EmojiListProps {
3
+ items: EmojiItem[];
4
+ selectedIndex: number;
5
+ onSelectIndex: (index: number) => void;
6
+ }
7
+ declare const EmojiList: ({ items, onSelectIndex }: EmojiListProps) => import("react").JSX.Element;
8
+ export default EmojiList;
@@ -0,0 +1,14 @@
1
+ import { EmojiItem } from '@tiptap/extension-emoji';
2
+ import { Editor } from '@tiptap/core';
3
+ type CommandProps = {
4
+ name: string;
5
+ };
6
+ type EmojiListProps = {
7
+ items: EmojiItem[];
8
+ editor: Editor;
9
+ command: (arg0: CommandProps) => void;
10
+ range: Range;
11
+ query: string;
12
+ };
13
+ declare const EmojiPicker: import('react').ForwardRefExoticComponent<EmojiListProps & import('react').RefAttributes<unknown>>;
14
+ export default EmojiPicker;
@@ -0,0 +1,3 @@
1
+ import { SuggestionOptions } from '@tiptap/suggestion';
2
+ declare const _default: Omit<SuggestionOptions, "editor">;
3
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import { UploadFunction } from '../node/image-upload/image-upload-node-extension';
2
+ import { AttachmentUploadFunction } from '../node/attachment';
3
+ type Handlers = {
4
+ /** Ảnh: chèn thành node `image` để xem trực tiếp. */
5
+ uploadImage?: UploadFunction;
6
+ /** Tệp khác: chèn thành node `attachment` để tải về. */
7
+ uploadAttachment?: AttachmentUploadFunction;
8
+ };
9
+ /**
10
+ * Xử lý tệp được kéo-thả hoặc dán vào editor.
11
+ *
12
+ * Không giới hạn `allowedMimeTypes` nữa: bản trước chỉ nhận bốn định dạng ảnh,
13
+ * nên kéo một file Word vào editor thì trình duyệt mở file đó thay vì chèn.
14
+ *
15
+ * Ảnh và tệp thường đi hai đường khác nhau vì hiển thị khác nhau, nhưng cả hai
16
+ * đều chỉ nhận URL do app chủ trả về.
17
+ */
18
+ export declare function createFileHandler({ uploadImage, uploadAttachment }: Handlers): import('@tiptap/core').Extension<Omit<import('@tiptap/extension-file-handler').FileHandlePluginOptions, "editor" | "key">, any>;
19
+ export {};
@@ -0,0 +1,2 @@
1
+ import { Extension } from '@tiptap/core';
2
+ export declare const GlobalBlockBackground: Extension<any, any>;
@@ -0,0 +1,51 @@
1
+ import { AnyExtension, Editor } from '@tiptap/core';
2
+ import { Node as ProseMirrorNode } from '@tiptap/pm/model';
3
+ import { BlockGroupItem } from '../blocks/types';
4
+ import { Locale } from '../../i18n';
5
+ import { AttachmentUploadFunction } from '../node/attachment';
6
+ import { UploadFunction } from '../node/image-upload/image-upload-node-extension';
7
+ import { MentionSource } from './mention/types';
8
+ export type NotionEditorExtensionOptions = {
9
+ /** Extension bổ sung của app chủ, nối vào sau bộ mặc định. */
10
+ extensions?: AnyExtension[];
11
+ /** Nhóm block hiển thị trong slash menu. */
12
+ blocks?: BlockGroupItem[];
13
+ /**
14
+ * Chữ mờ cho document rỗng. Heading rỗng luôn hiện `Heading N`, còn các
15
+ * node rỗng khác không hiện gì.
16
+ *
17
+ * Truyền hàm để tự quyết định hoàn toàn — khi đó quy tắc trên bị bỏ qua.
18
+ */
19
+ placeholder?: string | ((props: {
20
+ editor: Editor;
21
+ node: ProseMirrorNode;
22
+ }) => string);
23
+ /**
24
+ * Hàm đẩy ảnh lên server, trả về URL công khai. Không truyền thì khối
25
+ * upload ảnh sẽ báo lỗi khi người dùng chọn file, còn kéo-thả rơi về base64.
26
+ */
27
+ uploadImage?: UploadFunction;
28
+ /**
29
+ * Hàm đưa tệp (Word, PDF, bảng tính…) lên và trả về URL công khai.
30
+ *
31
+ * Package chỉ nhận URL — nó không biết gì về R2 hay bất kỳ storage nào.
32
+ * Không truyền thì khối đính kèm báo lỗi khi người dùng chọn tệp.
33
+ */
34
+ uploadAttachment?: AttachmentUploadFunction;
35
+ /** Dung lượng tối đa cho tệp đính kèm, tính bằng byte. */
36
+ maxAttachmentSize?: number;
37
+ /** Kích thước file tối đa cho khối upload ảnh, tính bằng byte. */
38
+ maxImageSize?: number;
39
+ /** Nguồn dữ liệu cho `@mention`. Bỏ trống thì tắt hẳn tính năng mention. */
40
+ mentionSource?: MentionSource;
41
+ /** Ngôn ngữ của nhãn trong editor. Mặc định tiếng Việt. */
42
+ locale?: Locale;
43
+ };
44
+ /**
45
+ * Dựng bộ extension của editor.
46
+ *
47
+ * Mọi thứ phụ thuộc môi trường (upload ảnh, danh bạ mention, placeholder) đều
48
+ * đi vào qua tham số, nên bản thân package không giữ tham chiếu nào tới app
49
+ * chủ.
50
+ */
51
+ export declare function extensions(options?: NotionEditorExtensionOptions): AnyExtension[];
@@ -0,0 +1,11 @@
1
+ import { default as React } from 'react';
2
+ import { SuggestionProps } from '@tiptap/suggestion';
3
+ import { MentionItem } from './types';
4
+ export interface DropdownMenuRef {
5
+ onKeyDown: (params: {
6
+ event: KeyboardEvent | React.KeyboardEvent;
7
+ }) => boolean;
8
+ }
9
+ type MentionListProps = SuggestionProps<MentionItem>;
10
+ declare const MentionList: React.ForwardRefExoticComponent<MentionListProps & React.RefAttributes<DropdownMenuRef>>;
11
+ export default MentionList;
@@ -0,0 +1,11 @@
1
+ import { SuggestionOptions } from '@tiptap/suggestion';
2
+ import { MentionItem, MentionSource } from './types';
3
+ /**
4
+ * Dựng cấu hình suggestion cho `@mention` quanh một nguồn dữ liệu do app chủ
5
+ * cung cấp.
6
+ *
7
+ * Bản template gốc hardcode danh sách diễn viên thập niên 80 ngay trong file
8
+ * này. Tách thành factory để cùng một editor phục vụ được nhiều ngữ cảnh
9
+ * (nhân sự, tài liệu, khách hàng…) mà không phải fork extension.
10
+ */
11
+ export declare function createMentionSuggestion(source: MentionSource): Omit<SuggestionOptions<MentionItem>, "editor">;