@rtif-sdk/web 1.0.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 (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/block-drag-handler.d.ts +189 -0
  4. package/dist/block-drag-handler.d.ts.map +1 -0
  5. package/dist/block-drag-handler.js +745 -0
  6. package/dist/block-drag-handler.js.map +1 -0
  7. package/dist/block-renderer.d.ts +402 -0
  8. package/dist/block-renderer.d.ts.map +1 -0
  9. package/dist/block-renderer.js +424 -0
  10. package/dist/block-renderer.js.map +1 -0
  11. package/dist/clipboard.d.ts +178 -0
  12. package/dist/clipboard.d.ts.map +1 -0
  13. package/dist/clipboard.js +432 -0
  14. package/dist/clipboard.js.map +1 -0
  15. package/dist/command-bus.d.ts +113 -0
  16. package/dist/command-bus.d.ts.map +1 -0
  17. package/dist/command-bus.js +70 -0
  18. package/dist/command-bus.js.map +1 -0
  19. package/dist/composition.d.ts +220 -0
  20. package/dist/composition.d.ts.map +1 -0
  21. package/dist/composition.js +271 -0
  22. package/dist/composition.js.map +1 -0
  23. package/dist/content-extraction.d.ts +69 -0
  24. package/dist/content-extraction.d.ts.map +1 -0
  25. package/dist/content-extraction.js +228 -0
  26. package/dist/content-extraction.js.map +1 -0
  27. package/dist/content-handler-file.d.ts +40 -0
  28. package/dist/content-handler-file.d.ts.map +1 -0
  29. package/dist/content-handler-file.js +91 -0
  30. package/dist/content-handler-file.js.map +1 -0
  31. package/dist/content-handler-image.d.ts +82 -0
  32. package/dist/content-handler-image.d.ts.map +1 -0
  33. package/dist/content-handler-image.js +120 -0
  34. package/dist/content-handler-image.js.map +1 -0
  35. package/dist/content-handler-url.d.ts +129 -0
  36. package/dist/content-handler-url.d.ts.map +1 -0
  37. package/dist/content-handler-url.js +244 -0
  38. package/dist/content-handler-url.js.map +1 -0
  39. package/dist/content-handlers.d.ts +67 -0
  40. package/dist/content-handlers.d.ts.map +1 -0
  41. package/dist/content-handlers.js +263 -0
  42. package/dist/content-handlers.js.map +1 -0
  43. package/dist/content-pipeline.d.ts +383 -0
  44. package/dist/content-pipeline.d.ts.map +1 -0
  45. package/dist/content-pipeline.js +232 -0
  46. package/dist/content-pipeline.js.map +1 -0
  47. package/dist/cursor-nav.d.ts +149 -0
  48. package/dist/cursor-nav.d.ts.map +1 -0
  49. package/dist/cursor-nav.js +230 -0
  50. package/dist/cursor-nav.js.map +1 -0
  51. package/dist/cursor-rect.d.ts +65 -0
  52. package/dist/cursor-rect.d.ts.map +1 -0
  53. package/dist/cursor-rect.js +98 -0
  54. package/dist/cursor-rect.js.map +1 -0
  55. package/dist/drop-indicator.d.ts +108 -0
  56. package/dist/drop-indicator.d.ts.map +1 -0
  57. package/dist/drop-indicator.js +236 -0
  58. package/dist/drop-indicator.js.map +1 -0
  59. package/dist/editor.d.ts +41 -0
  60. package/dist/editor.d.ts.map +1 -0
  61. package/dist/editor.js +710 -0
  62. package/dist/editor.js.map +1 -0
  63. package/dist/floating-toolbar.d.ts +93 -0
  64. package/dist/floating-toolbar.d.ts.map +1 -0
  65. package/dist/floating-toolbar.js +159 -0
  66. package/dist/floating-toolbar.js.map +1 -0
  67. package/dist/index.d.ts +62 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +119 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/input-bridge.d.ts +273 -0
  72. package/dist/input-bridge.d.ts.map +1 -0
  73. package/dist/input-bridge.js +884 -0
  74. package/dist/input-bridge.js.map +1 -0
  75. package/dist/link-popover.d.ts +38 -0
  76. package/dist/link-popover.d.ts.map +1 -0
  77. package/dist/link-popover.js +278 -0
  78. package/dist/link-popover.js.map +1 -0
  79. package/dist/mark-renderer.d.ts +275 -0
  80. package/dist/mark-renderer.d.ts.map +1 -0
  81. package/dist/mark-renderer.js +210 -0
  82. package/dist/mark-renderer.js.map +1 -0
  83. package/dist/perf.d.ts +145 -0
  84. package/dist/perf.d.ts.map +1 -0
  85. package/dist/perf.js +260 -0
  86. package/dist/perf.js.map +1 -0
  87. package/dist/plugin-kit.d.ts +265 -0
  88. package/dist/plugin-kit.d.ts.map +1 -0
  89. package/dist/plugin-kit.js +234 -0
  90. package/dist/plugin-kit.js.map +1 -0
  91. package/dist/plugins/alignment-plugin.d.ts +68 -0
  92. package/dist/plugins/alignment-plugin.d.ts.map +1 -0
  93. package/dist/plugins/alignment-plugin.js +98 -0
  94. package/dist/plugins/alignment-plugin.js.map +1 -0
  95. package/dist/plugins/block-utils.d.ts +113 -0
  96. package/dist/plugins/block-utils.d.ts.map +1 -0
  97. package/dist/plugins/block-utils.js +191 -0
  98. package/dist/plugins/block-utils.js.map +1 -0
  99. package/dist/plugins/blockquote-plugin.d.ts +39 -0
  100. package/dist/plugins/blockquote-plugin.d.ts.map +1 -0
  101. package/dist/plugins/blockquote-plugin.js +88 -0
  102. package/dist/plugins/blockquote-plugin.js.map +1 -0
  103. package/dist/plugins/bold-plugin.d.ts +37 -0
  104. package/dist/plugins/bold-plugin.d.ts.map +1 -0
  105. package/dist/plugins/bold-plugin.js +48 -0
  106. package/dist/plugins/bold-plugin.js.map +1 -0
  107. package/dist/plugins/callout-plugin.d.ts +100 -0
  108. package/dist/plugins/callout-plugin.d.ts.map +1 -0
  109. package/dist/plugins/callout-plugin.js +200 -0
  110. package/dist/plugins/callout-plugin.js.map +1 -0
  111. package/dist/plugins/code-block-plugin.d.ts +62 -0
  112. package/dist/plugins/code-block-plugin.d.ts.map +1 -0
  113. package/dist/plugins/code-block-plugin.js +176 -0
  114. package/dist/plugins/code-block-plugin.js.map +1 -0
  115. package/dist/plugins/code-plugin.d.ts +37 -0
  116. package/dist/plugins/code-plugin.d.ts.map +1 -0
  117. package/dist/plugins/code-plugin.js +48 -0
  118. package/dist/plugins/code-plugin.js.map +1 -0
  119. package/dist/plugins/embed-plugin.d.ts +90 -0
  120. package/dist/plugins/embed-plugin.d.ts.map +1 -0
  121. package/dist/plugins/embed-plugin.js +147 -0
  122. package/dist/plugins/embed-plugin.js.map +1 -0
  123. package/dist/plugins/font-family-plugin.d.ts +58 -0
  124. package/dist/plugins/font-family-plugin.d.ts.map +1 -0
  125. package/dist/plugins/font-family-plugin.js +57 -0
  126. package/dist/plugins/font-family-plugin.js.map +1 -0
  127. package/dist/plugins/font-size-plugin.d.ts +57 -0
  128. package/dist/plugins/font-size-plugin.d.ts.map +1 -0
  129. package/dist/plugins/font-size-plugin.js +56 -0
  130. package/dist/plugins/font-size-plugin.js.map +1 -0
  131. package/dist/plugins/heading-plugin.d.ts +52 -0
  132. package/dist/plugins/heading-plugin.d.ts.map +1 -0
  133. package/dist/plugins/heading-plugin.js +114 -0
  134. package/dist/plugins/heading-plugin.js.map +1 -0
  135. package/dist/plugins/hr-plugin.d.ts +33 -0
  136. package/dist/plugins/hr-plugin.d.ts.map +1 -0
  137. package/dist/plugins/hr-plugin.js +75 -0
  138. package/dist/plugins/hr-plugin.js.map +1 -0
  139. package/dist/plugins/image-plugin.d.ts +115 -0
  140. package/dist/plugins/image-plugin.d.ts.map +1 -0
  141. package/dist/plugins/image-plugin.js +199 -0
  142. package/dist/plugins/image-plugin.js.map +1 -0
  143. package/dist/plugins/indent-plugin.d.ts +62 -0
  144. package/dist/plugins/indent-plugin.d.ts.map +1 -0
  145. package/dist/plugins/indent-plugin.js +128 -0
  146. package/dist/plugins/indent-plugin.js.map +1 -0
  147. package/dist/plugins/index.d.ts +45 -0
  148. package/dist/plugins/index.d.ts.map +1 -0
  149. package/dist/plugins/index.js +42 -0
  150. package/dist/plugins/index.js.map +1 -0
  151. package/dist/plugins/italic-plugin.d.ts +37 -0
  152. package/dist/plugins/italic-plugin.d.ts.map +1 -0
  153. package/dist/plugins/italic-plugin.js +48 -0
  154. package/dist/plugins/italic-plugin.js.map +1 -0
  155. package/dist/plugins/link-plugin.d.ts +129 -0
  156. package/dist/plugins/link-plugin.d.ts.map +1 -0
  157. package/dist/plugins/link-plugin.js +212 -0
  158. package/dist/plugins/link-plugin.js.map +1 -0
  159. package/dist/plugins/list-plugin.d.ts +53 -0
  160. package/dist/plugins/list-plugin.d.ts.map +1 -0
  161. package/dist/plugins/list-plugin.js +309 -0
  162. package/dist/plugins/list-plugin.js.map +1 -0
  163. package/dist/plugins/mark-utils.d.ts +173 -0
  164. package/dist/plugins/mark-utils.d.ts.map +1 -0
  165. package/dist/plugins/mark-utils.js +425 -0
  166. package/dist/plugins/mark-utils.js.map +1 -0
  167. package/dist/plugins/mention-plugin.d.ts +191 -0
  168. package/dist/plugins/mention-plugin.d.ts.map +1 -0
  169. package/dist/plugins/mention-plugin.js +295 -0
  170. package/dist/plugins/mention-plugin.js.map +1 -0
  171. package/dist/plugins/strikethrough-plugin.d.ts +37 -0
  172. package/dist/plugins/strikethrough-plugin.d.ts.map +1 -0
  173. package/dist/plugins/strikethrough-plugin.js +48 -0
  174. package/dist/plugins/strikethrough-plugin.js.map +1 -0
  175. package/dist/plugins/text-color-plugin.d.ts +57 -0
  176. package/dist/plugins/text-color-plugin.d.ts.map +1 -0
  177. package/dist/plugins/text-color-plugin.js +56 -0
  178. package/dist/plugins/text-color-plugin.js.map +1 -0
  179. package/dist/plugins/underline-plugin.d.ts +37 -0
  180. package/dist/plugins/underline-plugin.d.ts.map +1 -0
  181. package/dist/plugins/underline-plugin.js +48 -0
  182. package/dist/plugins/underline-plugin.js.map +1 -0
  183. package/dist/presets.d.ts +95 -0
  184. package/dist/presets.d.ts.map +1 -0
  185. package/dist/presets.js +159 -0
  186. package/dist/presets.js.map +1 -0
  187. package/dist/renderer.d.ts +125 -0
  188. package/dist/renderer.d.ts.map +1 -0
  189. package/dist/renderer.js +415 -0
  190. package/dist/renderer.js.map +1 -0
  191. package/dist/scroll-to-cursor.d.ts +25 -0
  192. package/dist/scroll-to-cursor.d.ts.map +1 -0
  193. package/dist/scroll-to-cursor.js +59 -0
  194. package/dist/scroll-to-cursor.js.map +1 -0
  195. package/dist/selection-sync.d.ts +159 -0
  196. package/dist/selection-sync.d.ts.map +1 -0
  197. package/dist/selection-sync.js +527 -0
  198. package/dist/selection-sync.js.map +1 -0
  199. package/dist/shortcut-handler.d.ts +98 -0
  200. package/dist/shortcut-handler.d.ts.map +1 -0
  201. package/dist/shortcut-handler.js +155 -0
  202. package/dist/shortcut-handler.js.map +1 -0
  203. package/dist/toolbar.d.ts +103 -0
  204. package/dist/toolbar.d.ts.map +1 -0
  205. package/dist/toolbar.js +134 -0
  206. package/dist/toolbar.js.map +1 -0
  207. package/dist/trigger-manager.d.ts +205 -0
  208. package/dist/trigger-manager.d.ts.map +1 -0
  209. package/dist/trigger-manager.js +466 -0
  210. package/dist/trigger-manager.js.map +1 -0
  211. package/dist/types.d.ts +216 -0
  212. package/dist/types.d.ts.map +1 -0
  213. package/dist/types.js +2 -0
  214. package/dist/types.js.map +1 -0
  215. package/package.json +30 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Content extraction — converts browser clipboard and drag events into
3
+ * {@link ContentItem} arrays for the content pipeline.
4
+ *
5
+ * This module bridges between the browser's DataTransfer API and the
6
+ * content pipeline's abstract ContentItem interface. It handles deduplication,
7
+ * lazy data access, and file wrapping.
8
+ *
9
+ * @module
10
+ */
11
+ // ---------------------------------------------------------------------------
12
+ // extractFromPaste
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Extract content items from a ClipboardEvent.
16
+ *
17
+ * Uses the `DataTransferItemList` API when available for lazy data access.
18
+ * Falls back to `getData()` for string types. Deduplicates entries where both
19
+ * APIs provide the same MIME type.
20
+ *
21
+ * @param e - The clipboard event (from a 'paste' handler)
22
+ * @returns Array of ContentItem objects for pipeline processing
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * root.addEventListener('paste', (e) => {
27
+ * e.preventDefault();
28
+ * const items = extractFromPaste(e);
29
+ * pipeline.process(items, contextOpts);
30
+ * });
31
+ * ```
32
+ */
33
+ export function extractFromPaste(e) {
34
+ const clipboardData = e.clipboardData;
35
+ if (!clipboardData)
36
+ return [];
37
+ return extractFromDataTransfer(clipboardData, 'paste');
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // extractFromDrop
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * Extract content items from a DragEvent.
44
+ *
45
+ * Uses the `DataTransferItemList` API when available, falling back to
46
+ * `DataTransfer.files` and `getData()`. Items are created with source 'drop'.
47
+ *
48
+ * @param e - The drag event (from a 'drop' handler)
49
+ * @returns Array of ContentItem objects for pipeline processing
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * root.addEventListener('drop', (e) => {
54
+ * e.preventDefault();
55
+ * const items = extractFromDrop(e);
56
+ * pipeline.process(items, contextOpts);
57
+ * });
58
+ * ```
59
+ */
60
+ export function extractFromDrop(e) {
61
+ const dataTransfer = e.dataTransfer;
62
+ if (!dataTransfer)
63
+ return [];
64
+ return extractFromDataTransfer(dataTransfer, 'drop');
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // fileToContentItem
68
+ // ---------------------------------------------------------------------------
69
+ /**
70
+ * Create a ContentItem from a File object.
71
+ *
72
+ * The `getString()` method returns `file.text()` for text MIME types,
73
+ * null otherwise. `getFile()` and `getBlob()` always return the file.
74
+ *
75
+ * @param file - The File to wrap
76
+ * @param source - How the file entered the editor
77
+ * @returns A ContentItem wrapping the file
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const fileInput = document.querySelector('input[type=file]');
82
+ * const file = fileInput.files[0];
83
+ * const item = fileToContentItem(file, 'input');
84
+ * ```
85
+ */
86
+ export function fileToContentItem(file, source) {
87
+ return {
88
+ type: file.type || 'application/octet-stream',
89
+ source,
90
+ async getString() {
91
+ if (isTextMimeType(file.type)) {
92
+ return file.text();
93
+ }
94
+ return null;
95
+ },
96
+ async getFile() {
97
+ return file;
98
+ },
99
+ async getBlob() {
100
+ return file;
101
+ },
102
+ };
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // Internal helpers
106
+ // ---------------------------------------------------------------------------
107
+ /**
108
+ * Check whether a MIME type represents text content.
109
+ */
110
+ function isTextMimeType(type) {
111
+ return (type.startsWith('text/') ||
112
+ type === 'application/json' ||
113
+ type === 'application/x-rtif+json' ||
114
+ type === 'application/xml');
115
+ }
116
+ /**
117
+ * Extract content items from a DataTransfer object.
118
+ *
119
+ * Uses DataTransferItemList when available for proper lazy access.
120
+ * Falls back to getData() for string types and .files for file types.
121
+ * Deduplicates: if both DataTransferItem and getData produce the same
122
+ * MIME type, the DataTransferItem version wins.
123
+ */
124
+ function extractFromDataTransfer(dt, source) {
125
+ const result = [];
126
+ const seenTypes = new Set();
127
+ // Prefer DataTransferItemList (modern API with lazy access)
128
+ if (dt.items && dt.items.length > 0) {
129
+ for (let i = 0; i < dt.items.length; i++) {
130
+ const dtItem = dt.items[i];
131
+ if (!dtItem)
132
+ continue;
133
+ const mimeType = dtItem.type;
134
+ if (dtItem.kind === 'string') {
135
+ seenTypes.add(mimeType);
136
+ // Capture the DataTransferItem reference for lazy string retrieval.
137
+ // We must call getAsString() synchronously during the event, so we
138
+ // eagerly resolve the string and store it in a closure.
139
+ const stringPromise = getStringFromDataTransferItem(dtItem);
140
+ result.push({
141
+ type: mimeType,
142
+ source,
143
+ getString: () => stringPromise,
144
+ async getFile() {
145
+ return null;
146
+ },
147
+ async getBlob() {
148
+ return null;
149
+ },
150
+ });
151
+ }
152
+ else if (dtItem.kind === 'file') {
153
+ const file = dtItem.getAsFile();
154
+ if (file) {
155
+ seenTypes.add(mimeType);
156
+ result.push(fileToContentItem(file, source));
157
+ }
158
+ }
159
+ }
160
+ }
161
+ // Fall back to getData() for string types not already captured.
162
+ // This handles browsers where DataTransferItemList is incomplete.
163
+ for (const type of dt.types) {
164
+ if (seenTypes.has(type))
165
+ continue;
166
+ // 'Files' is a special type indicator, not a real MIME type
167
+ if (type === 'Files')
168
+ continue;
169
+ try {
170
+ const data = dt.getData(type);
171
+ if (data) {
172
+ seenTypes.add(type);
173
+ result.push({
174
+ type,
175
+ source,
176
+ async getString() {
177
+ return data;
178
+ },
179
+ async getFile() {
180
+ return null;
181
+ },
182
+ async getBlob() {
183
+ return null;
184
+ },
185
+ });
186
+ }
187
+ }
188
+ catch {
189
+ // getData() may throw in some browsers for certain types
190
+ continue;
191
+ }
192
+ }
193
+ // Fall back to .files for file types not already captured
194
+ if (dt.files && dt.files.length > 0) {
195
+ for (let i = 0; i < dt.files.length; i++) {
196
+ const file = dt.files[i];
197
+ if (!file)
198
+ continue;
199
+ const fileType = file.type || 'application/octet-stream';
200
+ if (seenTypes.has(fileType))
201
+ continue;
202
+ seenTypes.add(fileType);
203
+ result.push(fileToContentItem(file, source));
204
+ }
205
+ }
206
+ return result;
207
+ }
208
+ /**
209
+ * Get a string from a DataTransferItem using the callback-based API,
210
+ * wrapped in a Promise.
211
+ *
212
+ * Note: In some browsers, getAsString() must be called synchronously
213
+ * during the event handler. The callback fires asynchronously, but the
214
+ * registration is synchronous.
215
+ */
216
+ function getStringFromDataTransferItem(item) {
217
+ return new Promise((resolve) => {
218
+ try {
219
+ item.getAsString((str) => {
220
+ resolve(str);
221
+ });
222
+ }
223
+ catch {
224
+ resolve(null);
225
+ }
226
+ });
227
+ }
228
+ //# sourceMappingURL=content-extraction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-extraction.js","sourceRoot":"","sources":["../src/content-extraction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * File drop content handler — processes dropped text-based files (JSON, XML,
3
+ * CSS, JavaScript, etc.) by extracting their text content and inserting it
4
+ * into the editor.
5
+ *
6
+ * Only handles drop events (not paste) to avoid conflicting with the plain
7
+ * text handler on paste. Uses the same newline-splitting pattern as the
8
+ * plain text handler.
9
+ *
10
+ * Priority: -105 (runs after plain text at -100, as a catch-all for dropped files).
11
+ *
12
+ * @module
13
+ */
14
+ import type { ContentHandler } from './content-pipeline.js';
15
+ /**
16
+ * Create a content handler for dropped text-based files.
17
+ *
18
+ * Accepts common text-based MIME types (`text/*`, `application/json`,
19
+ * `application/xml`, `application/javascript`) but only from drop events.
20
+ * Paste events are skipped via `canHandle` to avoid conflicting with the
21
+ * plain text handler.
22
+ *
23
+ * Extracts the file's text content and inserts it into the document,
24
+ * splitting on newlines to create separate blocks.
25
+ *
26
+ * Priority: -105 (lowest, runs after all other handlers).
27
+ *
28
+ * @returns A ContentHandler for dropped text files
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const handler = createFileDropHandler();
33
+ * pipeline.register(handler);
34
+ *
35
+ * // Dropping a .json file into the editor will extract its text content
36
+ * // and insert it as blocks, one per line.
37
+ * ```
38
+ */
39
+ export declare function createFileDropHandler(): ContentHandler;
40
+ //# sourceMappingURL=content-handler-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-handler-file.d.ts","sourceRoot":"","sources":["../src/content-handler-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,uBAAuB,CAAC;AAM/B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,IAAI,cAAc,CA2DtD"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * File drop content handler — processes dropped text-based files (JSON, XML,
3
+ * CSS, JavaScript, etc.) by extracting their text content and inserting it
4
+ * into the editor.
5
+ *
6
+ * Only handles drop events (not paste) to avoid conflicting with the plain
7
+ * text handler on paste. Uses the same newline-splitting pattern as the
8
+ * plain text handler.
9
+ *
10
+ * Priority: -105 (runs after plain text at -100, as a catch-all for dropped files).
11
+ *
12
+ * @module
13
+ */
14
+ // ---------------------------------------------------------------------------
15
+ // Factory
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Create a content handler for dropped text-based files.
19
+ *
20
+ * Accepts common text-based MIME types (`text/*`, `application/json`,
21
+ * `application/xml`, `application/javascript`) but only from drop events.
22
+ * Paste events are skipped via `canHandle` to avoid conflicting with the
23
+ * plain text handler.
24
+ *
25
+ * Extracts the file's text content and inserts it into the document,
26
+ * splitting on newlines to create separate blocks.
27
+ *
28
+ * Priority: -105 (lowest, runs after all other handlers).
29
+ *
30
+ * @returns A ContentHandler for dropped text files
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const handler = createFileDropHandler();
35
+ * pipeline.register(handler);
36
+ *
37
+ * // Dropping a .json file into the editor will extract its text content
38
+ * // and insert it as blocks, one per line.
39
+ * ```
40
+ */
41
+ export function createFileDropHandler() {
42
+ return {
43
+ id: 'rtif:file-drop',
44
+ accept: [
45
+ 'text/*',
46
+ 'application/json',
47
+ 'application/xml',
48
+ 'application/javascript',
49
+ ],
50
+ priority: -105,
51
+ async canHandle(item) {
52
+ return item.source === 'drop';
53
+ },
54
+ async handle(item, context) {
55
+ const file = await item.getFile();
56
+ if (file === null)
57
+ return false;
58
+ const text = await file.text();
59
+ if (text === '')
60
+ return false;
61
+ const insertOffset = context.deleteSelectionAndGetOffset();
62
+ const ops = [];
63
+ let currentOffset = insertOffset;
64
+ const lines = text.split('\n');
65
+ for (let i = 0; i < lines.length; i++) {
66
+ const line = lines[i];
67
+ if (i > 0) {
68
+ ops.push({
69
+ type: 'split_block',
70
+ offset: currentOffset,
71
+ newBlockId: context.generateBlockId(),
72
+ });
73
+ currentOffset += 1;
74
+ }
75
+ if (line.length > 0) {
76
+ ops.push({
77
+ type: 'insert_text',
78
+ offset: currentOffset,
79
+ text: line,
80
+ });
81
+ currentOffset += line.length;
82
+ }
83
+ }
84
+ if (ops.length > 0) {
85
+ context.dispatch(ops);
86
+ }
87
+ return true;
88
+ },
89
+ };
90
+ }
91
+ //# sourceMappingURL=content-handler-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-handler-file.js","sourceRoot":"","sources":["../src/content-handler-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,EAAE,EAAE,gBAAgB;QACpB,MAAM,EAAE;YACN,QAAQ;YACR,kBAAkB;YAClB,iBAAiB;YACjB,wBAAwB;SACzB;QACD,QAAQ,EAAE,CAAC,GAAG;QAEd,KAAK,CAAC,SAAS,CAAC,IAAiB;YAC/B,OAAO,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC;QAChC,CAAC;QAED,KAAK,CAAC,MAAM,CACV,IAAiB,EACjB,OAAuB;YAEvB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YAEhC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,IAAI,KAAK,EAAE;gBAAE,OAAO,KAAK,CAAC;YAE9B,MAAM,YAAY,GAAG,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAC3D,MAAM,GAAG,GAAgB,EAAE,CAAC;YAC5B,IAAI,aAAa,GAAG,YAAY,CAAC;YAEjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;gBAEvB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACV,GAAG,CAAC,IAAI,CAAC;wBACP,IAAI,EAAE,aAAa;wBACnB,MAAM,EAAE,aAAa;wBACrB,UAAU,EAAE,OAAO,CAAC,eAAe,EAAE;qBACtC,CAAC,CAAC;oBACH,aAAa,IAAI,CAAC,CAAC;gBACrB,CAAC;gBAED,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACpB,GAAG,CAAC,IAAI,CAAC;wBACP,IAAI,EAAE,aAAa;wBACnB,MAAM,EAAE,aAAa;wBACrB,IAAI,EAAE,IAAI;qBACX,CAAC,CAAC;oBACH,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC;gBAC/B,CAAC;YACH,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Image content handler — processes pasted/dropped image files into RTIF
3
+ * image blocks. Reads the file as a data URL for immediate display, with
4
+ * optional async upload to swap in a final URL.
5
+ *
6
+ * Priority: -85 (runs after RTIF JSON, before HTML and plain text).
7
+ *
8
+ * @module
9
+ */
10
+ import type { ContentHandler } from './content-pipeline.js';
11
+ /**
12
+ * Configuration for the image content handler.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const handler = createImageContentHandler({
17
+ * upload: async (file) => {
18
+ * const url = await myUploadService.upload(file);
19
+ * return url;
20
+ * },
21
+ * maxFileSize: 5 * 1024 * 1024, // 5 MB
22
+ * });
23
+ * ```
24
+ */
25
+ export interface ImageContentHandlerConfig {
26
+ /**
27
+ * Upload function. Called after the image block is created with a data URL.
28
+ * Returns the final URL to replace the data URL. If omitted, the data URL
29
+ * is permanent.
30
+ *
31
+ * @param file - The image File object
32
+ * @returns The final URL for the image
33
+ */
34
+ readonly upload?: (file: File) => Promise<string>;
35
+ /**
36
+ * Maximum file size in bytes. Files exceeding this size are rejected
37
+ * (handler returns false). 0 or undefined means no limit.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * maxFileSize: 10 * 1024 * 1024 // 10 MB
42
+ * ```
43
+ */
44
+ readonly maxFileSize?: number;
45
+ }
46
+ /**
47
+ * Read a File as a data URL using FileReader.
48
+ *
49
+ * @param file - The file to read
50
+ * @returns A promise resolving to the data URL string
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const dataUrl = await readFileAsDataUrl(imageFile);
55
+ * // "data:image/png;base64,iVBOR..."
56
+ * ```
57
+ */
58
+ export declare function readFileAsDataUrl(file: File): Promise<string>;
59
+ /**
60
+ * Create a content handler for image paste/drop.
61
+ *
62
+ * Accepts `image/*` content and converts it to an RTIF image block.
63
+ * Reads the file as a data URL for immediate display. If an `upload`
64
+ * function is provided, it is called after the block is created to
65
+ * swap the data URL for a final URL.
66
+ *
67
+ * Priority: -85 (between RTIF JSON at -80 and HTML at -90).
68
+ *
69
+ * @param config - Optional configuration for upload and file size limits
70
+ * @returns A ContentHandler for image files
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const handler = createImageContentHandler({
75
+ * upload: async (file) => uploadToS3(file),
76
+ * maxFileSize: 5 * 1024 * 1024,
77
+ * });
78
+ * pipeline.register(handler);
79
+ * ```
80
+ */
81
+ export declare function createImageContentHandler(config?: ImageContentHandlerConfig): ContentHandler;
82
+ //# sourceMappingURL=content-handler-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-handler-image.d.ts","sourceRoot":"","sources":["../src/content-handler-image.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,uBAAuB,CAAC;AAM/B;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAElD;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7D;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,CAAC,EAAE,yBAAyB,GACjC,cAAc,CAyEhB"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Image content handler — processes pasted/dropped image files into RTIF
3
+ * image blocks. Reads the file as a data URL for immediate display, with
4
+ * optional async upload to swap in a final URL.
5
+ *
6
+ * Priority: -85 (runs after RTIF JSON, before HTML and plain text).
7
+ *
8
+ * @module
9
+ */
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Read a File as a data URL using FileReader.
15
+ *
16
+ * @param file - The file to read
17
+ * @returns A promise resolving to the data URL string
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const dataUrl = await readFileAsDataUrl(imageFile);
22
+ * // "data:image/png;base64,iVBOR..."
23
+ * ```
24
+ */
25
+ export function readFileAsDataUrl(file) {
26
+ return new Promise((resolve, reject) => {
27
+ const reader = new FileReader();
28
+ reader.onload = () => resolve(reader.result);
29
+ reader.onerror = () => reject(reader.error);
30
+ reader.readAsDataURL(file);
31
+ });
32
+ }
33
+ // ---------------------------------------------------------------------------
34
+ // Factory
35
+ // ---------------------------------------------------------------------------
36
+ /**
37
+ * Create a content handler for image paste/drop.
38
+ *
39
+ * Accepts `image/*` content and converts it to an RTIF image block.
40
+ * Reads the file as a data URL for immediate display. If an `upload`
41
+ * function is provided, it is called after the block is created to
42
+ * swap the data URL for a final URL.
43
+ *
44
+ * Priority: -85 (between RTIF JSON at -80 and HTML at -90).
45
+ *
46
+ * @param config - Optional configuration for upload and file size limits
47
+ * @returns A ContentHandler for image files
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const handler = createImageContentHandler({
52
+ * upload: async (file) => uploadToS3(file),
53
+ * maxFileSize: 5 * 1024 * 1024,
54
+ * });
55
+ * pipeline.register(handler);
56
+ * ```
57
+ */
58
+ export function createImageContentHandler(config) {
59
+ return {
60
+ id: 'rtif:image',
61
+ accept: ['image/*'],
62
+ priority: -85,
63
+ async handle(item, context) {
64
+ const file = await item.getFile();
65
+ if (file === null)
66
+ return false;
67
+ // Validate file size
68
+ if (config?.maxFileSize && config.maxFileSize > 0) {
69
+ if (file.size > config.maxFileSize)
70
+ return false;
71
+ }
72
+ // Read image as data URL
73
+ const dataUrl = await readFileAsDataUrl(file);
74
+ // Delete selection and get insert offset
75
+ const insertOffset = context.deleteSelectionAndGetOffset();
76
+ // Generate block IDs
77
+ const imageBlockId = context.generateBlockId();
78
+ const trailingBlockId = context.generateBlockId();
79
+ // Compose operations:
80
+ // 1. Split at cursor → trailing text goes to imageBlockId
81
+ // 2. Split at start of imageBlockId → trailing text goes to trailingBlockId
82
+ // 3. Set imageBlockId type to 'image'
83
+ // 4. Set imageBlockId attrs with src and alt
84
+ const ops = [
85
+ { type: 'split_block', offset: insertOffset, newBlockId: imageBlockId },
86
+ { type: 'split_block', offset: insertOffset + 1, newBlockId: trailingBlockId },
87
+ { type: 'set_block_type', blockId: imageBlockId, blockType: 'image' },
88
+ {
89
+ type: 'set_block_attrs',
90
+ blockId: imageBlockId,
91
+ attrs: { src: dataUrl, alt: file.name },
92
+ },
93
+ ];
94
+ context.dispatch(ops);
95
+ // Fire-and-forget upload if configured
96
+ if (config?.upload) {
97
+ const engine = context.engine;
98
+ void (async () => {
99
+ try {
100
+ const finalUrl = await config.upload(file);
101
+ // Guard: verify block still exists and is still an image
102
+ const block = engine.state.doc.blocks.find((b) => b.id === imageBlockId);
103
+ if (!block || block.type !== 'image')
104
+ return;
105
+ engine.dispatch({
106
+ type: 'set_block_attrs',
107
+ blockId: imageBlockId,
108
+ attrs: { src: finalUrl },
109
+ });
110
+ }
111
+ catch {
112
+ // Upload failed — keep the data URL. Silently swallow the error.
113
+ }
114
+ })();
115
+ }
116
+ return true;
117
+ },
118
+ };
119
+ }
120
+ //# sourceMappingURL=content-handler-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-handler-image.js","sourceRoot":"","sources":["../src/content-handler-image.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkDH,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAU;IAC1C,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAChC,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAgB,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAkC;IAElC,OAAO;QACL,EAAE,EAAE,YAAY;QAChB,MAAM,EAAE,CAAC,SAAS,CAAC;QACnB,QAAQ,EAAE,CAAC,EAAE;QAEb,KAAK,CAAC,MAAM,CACV,IAAiB,EACjB,OAAuB;YAEvB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YAEhC,qBAAqB;YACrB,IAAI,MAAM,EAAE,WAAW,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;gBAClD,IAAI,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,WAAW;oBAAE,OAAO,KAAK,CAAC;YACnD,CAAC;YAED,yBAAyB;YACzB,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAE9C,yCAAyC;YACzC,MAAM,YAAY,GAAG,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAE3D,qBAAqB;YACrB,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;YAC/C,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;YAElD,sBAAsB;YACtB,0DAA0D;YAC1D,4EAA4E;YAC5E,sCAAsC;YACtC,6CAA6C;YAC7C,MAAM,GAAG,GAAgB;gBACvB,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE;gBACvE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,GAAG,CAAC,EAAE,UAAU,EAAE,eAAe,EAAE;gBAC9E,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE;gBACrE;oBACE,IAAI,EAAE,iBAAiB;oBACvB,OAAO,EAAE,YAAY;oBACrB,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE;iBACxC;aACF,CAAC;YAEF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAEtB,uCAAuC;YACvC,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;gBACnB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBAC9B,KAAK,CAAC,KAAK,IAAI,EAAE;oBACf,IAAI,CAAC;wBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,CAAC;wBAE5C,yDAAyD;wBACzD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAC7B,CAAC;wBACF,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;4BAAE,OAAO;wBAE7C,MAAM,CAAC,QAAQ,CAAC;4BACd,IAAI,EAAE,iBAAiB;4BACvB,OAAO,EAAE,YAAY;4BACrB,KAAK,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE;yBACzB,CAAC,CAAC;oBACL,CAAC;oBAAC,MAAM,CAAC;wBACP,iEAAiE;oBACnE,CAAC;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC"}