@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.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/block-drag-handler.d.ts +189 -0
- package/dist/block-drag-handler.d.ts.map +1 -0
- package/dist/block-drag-handler.js +745 -0
- package/dist/block-drag-handler.js.map +1 -0
- package/dist/block-renderer.d.ts +402 -0
- package/dist/block-renderer.d.ts.map +1 -0
- package/dist/block-renderer.js +424 -0
- package/dist/block-renderer.js.map +1 -0
- package/dist/clipboard.d.ts +178 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +432 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/command-bus.d.ts +113 -0
- package/dist/command-bus.d.ts.map +1 -0
- package/dist/command-bus.js +70 -0
- package/dist/command-bus.js.map +1 -0
- package/dist/composition.d.ts +220 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +271 -0
- package/dist/composition.js.map +1 -0
- package/dist/content-extraction.d.ts +69 -0
- package/dist/content-extraction.d.ts.map +1 -0
- package/dist/content-extraction.js +228 -0
- package/dist/content-extraction.js.map +1 -0
- package/dist/content-handler-file.d.ts +40 -0
- package/dist/content-handler-file.d.ts.map +1 -0
- package/dist/content-handler-file.js +91 -0
- package/dist/content-handler-file.js.map +1 -0
- package/dist/content-handler-image.d.ts +82 -0
- package/dist/content-handler-image.d.ts.map +1 -0
- package/dist/content-handler-image.js +120 -0
- package/dist/content-handler-image.js.map +1 -0
- package/dist/content-handler-url.d.ts +129 -0
- package/dist/content-handler-url.d.ts.map +1 -0
- package/dist/content-handler-url.js +244 -0
- package/dist/content-handler-url.js.map +1 -0
- package/dist/content-handlers.d.ts +67 -0
- package/dist/content-handlers.d.ts.map +1 -0
- package/dist/content-handlers.js +263 -0
- package/dist/content-handlers.js.map +1 -0
- package/dist/content-pipeline.d.ts +383 -0
- package/dist/content-pipeline.d.ts.map +1 -0
- package/dist/content-pipeline.js +232 -0
- package/dist/content-pipeline.js.map +1 -0
- package/dist/cursor-nav.d.ts +149 -0
- package/dist/cursor-nav.d.ts.map +1 -0
- package/dist/cursor-nav.js +230 -0
- package/dist/cursor-nav.js.map +1 -0
- package/dist/cursor-rect.d.ts +65 -0
- package/dist/cursor-rect.d.ts.map +1 -0
- package/dist/cursor-rect.js +98 -0
- package/dist/cursor-rect.js.map +1 -0
- package/dist/drop-indicator.d.ts +108 -0
- package/dist/drop-indicator.d.ts.map +1 -0
- package/dist/drop-indicator.js +236 -0
- package/dist/drop-indicator.js.map +1 -0
- package/dist/editor.d.ts +41 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +710 -0
- package/dist/editor.js.map +1 -0
- package/dist/floating-toolbar.d.ts +93 -0
- package/dist/floating-toolbar.d.ts.map +1 -0
- package/dist/floating-toolbar.js +159 -0
- package/dist/floating-toolbar.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -0
- package/dist/input-bridge.d.ts +273 -0
- package/dist/input-bridge.d.ts.map +1 -0
- package/dist/input-bridge.js +884 -0
- package/dist/input-bridge.js.map +1 -0
- package/dist/link-popover.d.ts +38 -0
- package/dist/link-popover.d.ts.map +1 -0
- package/dist/link-popover.js +278 -0
- package/dist/link-popover.js.map +1 -0
- package/dist/mark-renderer.d.ts +275 -0
- package/dist/mark-renderer.d.ts.map +1 -0
- package/dist/mark-renderer.js +210 -0
- package/dist/mark-renderer.js.map +1 -0
- package/dist/perf.d.ts +145 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +260 -0
- package/dist/perf.js.map +1 -0
- package/dist/plugin-kit.d.ts +265 -0
- package/dist/plugin-kit.d.ts.map +1 -0
- package/dist/plugin-kit.js +234 -0
- package/dist/plugin-kit.js.map +1 -0
- package/dist/plugins/alignment-plugin.d.ts +68 -0
- package/dist/plugins/alignment-plugin.d.ts.map +1 -0
- package/dist/plugins/alignment-plugin.js +98 -0
- package/dist/plugins/alignment-plugin.js.map +1 -0
- package/dist/plugins/block-utils.d.ts +113 -0
- package/dist/plugins/block-utils.d.ts.map +1 -0
- package/dist/plugins/block-utils.js +191 -0
- package/dist/plugins/block-utils.js.map +1 -0
- package/dist/plugins/blockquote-plugin.d.ts +39 -0
- package/dist/plugins/blockquote-plugin.d.ts.map +1 -0
- package/dist/plugins/blockquote-plugin.js +88 -0
- package/dist/plugins/blockquote-plugin.js.map +1 -0
- package/dist/plugins/bold-plugin.d.ts +37 -0
- package/dist/plugins/bold-plugin.d.ts.map +1 -0
- package/dist/plugins/bold-plugin.js +48 -0
- package/dist/plugins/bold-plugin.js.map +1 -0
- package/dist/plugins/callout-plugin.d.ts +100 -0
- package/dist/plugins/callout-plugin.d.ts.map +1 -0
- package/dist/plugins/callout-plugin.js +200 -0
- package/dist/plugins/callout-plugin.js.map +1 -0
- package/dist/plugins/code-block-plugin.d.ts +62 -0
- package/dist/plugins/code-block-plugin.d.ts.map +1 -0
- package/dist/plugins/code-block-plugin.js +176 -0
- package/dist/plugins/code-block-plugin.js.map +1 -0
- package/dist/plugins/code-plugin.d.ts +37 -0
- package/dist/plugins/code-plugin.d.ts.map +1 -0
- package/dist/plugins/code-plugin.js +48 -0
- package/dist/plugins/code-plugin.js.map +1 -0
- package/dist/plugins/embed-plugin.d.ts +90 -0
- package/dist/plugins/embed-plugin.d.ts.map +1 -0
- package/dist/plugins/embed-plugin.js +147 -0
- package/dist/plugins/embed-plugin.js.map +1 -0
- package/dist/plugins/font-family-plugin.d.ts +58 -0
- package/dist/plugins/font-family-plugin.d.ts.map +1 -0
- package/dist/plugins/font-family-plugin.js +57 -0
- package/dist/plugins/font-family-plugin.js.map +1 -0
- package/dist/plugins/font-size-plugin.d.ts +57 -0
- package/dist/plugins/font-size-plugin.d.ts.map +1 -0
- package/dist/plugins/font-size-plugin.js +56 -0
- package/dist/plugins/font-size-plugin.js.map +1 -0
- package/dist/plugins/heading-plugin.d.ts +52 -0
- package/dist/plugins/heading-plugin.d.ts.map +1 -0
- package/dist/plugins/heading-plugin.js +114 -0
- package/dist/plugins/heading-plugin.js.map +1 -0
- package/dist/plugins/hr-plugin.d.ts +33 -0
- package/dist/plugins/hr-plugin.d.ts.map +1 -0
- package/dist/plugins/hr-plugin.js +75 -0
- package/dist/plugins/hr-plugin.js.map +1 -0
- package/dist/plugins/image-plugin.d.ts +115 -0
- package/dist/plugins/image-plugin.d.ts.map +1 -0
- package/dist/plugins/image-plugin.js +199 -0
- package/dist/plugins/image-plugin.js.map +1 -0
- package/dist/plugins/indent-plugin.d.ts +62 -0
- package/dist/plugins/indent-plugin.d.ts.map +1 -0
- package/dist/plugins/indent-plugin.js +128 -0
- package/dist/plugins/indent-plugin.js.map +1 -0
- package/dist/plugins/index.d.ts +45 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +42 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/italic-plugin.d.ts +37 -0
- package/dist/plugins/italic-plugin.d.ts.map +1 -0
- package/dist/plugins/italic-plugin.js +48 -0
- package/dist/plugins/italic-plugin.js.map +1 -0
- package/dist/plugins/link-plugin.d.ts +129 -0
- package/dist/plugins/link-plugin.d.ts.map +1 -0
- package/dist/plugins/link-plugin.js +212 -0
- package/dist/plugins/link-plugin.js.map +1 -0
- package/dist/plugins/list-plugin.d.ts +53 -0
- package/dist/plugins/list-plugin.d.ts.map +1 -0
- package/dist/plugins/list-plugin.js +309 -0
- package/dist/plugins/list-plugin.js.map +1 -0
- package/dist/plugins/mark-utils.d.ts +173 -0
- package/dist/plugins/mark-utils.d.ts.map +1 -0
- package/dist/plugins/mark-utils.js +425 -0
- package/dist/plugins/mark-utils.js.map +1 -0
- package/dist/plugins/mention-plugin.d.ts +191 -0
- package/dist/plugins/mention-plugin.d.ts.map +1 -0
- package/dist/plugins/mention-plugin.js +295 -0
- package/dist/plugins/mention-plugin.js.map +1 -0
- package/dist/plugins/strikethrough-plugin.d.ts +37 -0
- package/dist/plugins/strikethrough-plugin.d.ts.map +1 -0
- package/dist/plugins/strikethrough-plugin.js +48 -0
- package/dist/plugins/strikethrough-plugin.js.map +1 -0
- package/dist/plugins/text-color-plugin.d.ts +57 -0
- package/dist/plugins/text-color-plugin.d.ts.map +1 -0
- package/dist/plugins/text-color-plugin.js +56 -0
- package/dist/plugins/text-color-plugin.js.map +1 -0
- package/dist/plugins/underline-plugin.d.ts +37 -0
- package/dist/plugins/underline-plugin.d.ts.map +1 -0
- package/dist/plugins/underline-plugin.js +48 -0
- package/dist/plugins/underline-plugin.js.map +1 -0
- package/dist/presets.d.ts +95 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +159 -0
- package/dist/presets.js.map +1 -0
- package/dist/renderer.d.ts +125 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +415 -0
- package/dist/renderer.js.map +1 -0
- package/dist/scroll-to-cursor.d.ts +25 -0
- package/dist/scroll-to-cursor.d.ts.map +1 -0
- package/dist/scroll-to-cursor.js +59 -0
- package/dist/scroll-to-cursor.js.map +1 -0
- package/dist/selection-sync.d.ts +159 -0
- package/dist/selection-sync.d.ts.map +1 -0
- package/dist/selection-sync.js +527 -0
- package/dist/selection-sync.js.map +1 -0
- package/dist/shortcut-handler.d.ts +98 -0
- package/dist/shortcut-handler.d.ts.map +1 -0
- package/dist/shortcut-handler.js +155 -0
- package/dist/shortcut-handler.js.map +1 -0
- package/dist/toolbar.d.ts +103 -0
- package/dist/toolbar.d.ts.map +1 -0
- package/dist/toolbar.js +134 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/trigger-manager.d.ts +205 -0
- package/dist/trigger-manager.d.ts.map +1 -0
- package/dist/trigger-manager.js +466 -0
- package/dist/trigger-manager.js.map +1 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- 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":"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"}
|