@lexical/clipboard 0.44.1-nightly.20260519.0 → 0.45.1-dev.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/dist/ClipboardImportExtension.d.ts +236 -0
- package/{LexicalClipboard.dev.js → dist/LexicalClipboard.dev.js} +442 -85
- package/dist/LexicalClipboard.dev.mjs +1163 -0
- package/{LexicalClipboard.js.flow → dist/LexicalClipboard.js.flow} +4 -0
- package/{LexicalClipboard.mjs → dist/LexicalClipboard.mjs} +5 -0
- package/{LexicalClipboard.node.mjs → dist/LexicalClipboard.node.mjs} +5 -0
- package/dist/LexicalClipboard.prod.js +9 -0
- package/dist/LexicalClipboard.prod.mjs +9 -0
- package/dist/caretFromPoint.d.ts +12 -0
- package/{clipboard.d.ts → dist/clipboard.d.ts} +6 -5
- package/{index.d.ts → dist/index.d.ts} +2 -0
- package/package.json +35 -20
- package/src/ClipboardImportExtension.ts +536 -0
- package/src/caretFromPoint.ts +41 -0
- package/{LexicalClipboard.dev.mjs → src/clipboard.ts} +369 -232
- package/src/index.ts +41 -0
- package/LexicalClipboard.prod.js +0 -9
- package/LexicalClipboard.prod.mjs +0 -9
- /package/{LexicalClipboard.js → dist/LexicalClipboard.js} +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { BaseSelection } from 'lexical';
|
|
9
|
+
import { LexicalClipboardData } from './clipboard';
|
|
10
|
+
/**
|
|
11
|
+
* A middleware function in a per-MIME-type clipboard-import stack. Mirrors
|
|
12
|
+
* the shape of {@link ExportMimeTypeFunction} on the export side.
|
|
13
|
+
*
|
|
14
|
+
* - `data` is the non-empty string returned by `DataTransfer.getData(mime)`
|
|
15
|
+
* for this MIME type.
|
|
16
|
+
* - `selection` is the current editor selection at the insertion point.
|
|
17
|
+
* - `$next` defers to the next-lower handler in the stack (i.e. the handler
|
|
18
|
+
* that was registered earlier). Returns `true` if that handler claimed
|
|
19
|
+
* the data; `false` if no handler accepted it.
|
|
20
|
+
* - `dataTransfer` is the full {@link DataTransfer} the paste/drop came
|
|
21
|
+
* from, so a handler can inspect companion MIME types or attached
|
|
22
|
+
* files in addition to the slot it was invoked for (e.g. peek at
|
|
23
|
+
* `'application/x-vscode-source'` while handling `'text/html'`). When
|
|
24
|
+
* threading through the new pipeline, pass this into
|
|
25
|
+
* `$generateNodesFromDOMViaExtension(dom, {
|
|
26
|
+
* context: [contextValue(ImportSourceDataTransfer, dataTransfer)],
|
|
27
|
+
* })` so rules and preprocessors can read it via
|
|
28
|
+
* `ctx.get(ImportSourceDataTransfer)`.
|
|
29
|
+
*
|
|
30
|
+
* The function should return `true` if it consumed the data (the caller
|
|
31
|
+
* stops trying further handlers for this MIME type and does not move on to
|
|
32
|
+
* the next MIME type). Return `$next()` to delegate. Return `false` if the
|
|
33
|
+
* function decided not to handle the data after inspecting it (e.g. the
|
|
34
|
+
* JSON namespace didn't match) so a lower-priority handler — or the next
|
|
35
|
+
* MIME type — gets a chance.
|
|
36
|
+
*
|
|
37
|
+
* @experimental
|
|
38
|
+
*/
|
|
39
|
+
export type ImportMimeTypeFunction = (data: string, selection: BaseSelection, $next: () => boolean, dataTransfer: DataTransfer) => boolean;
|
|
40
|
+
/**
|
|
41
|
+
* A mapping from MIME type to a stack of {@link ImportMimeTypeFunction}.
|
|
42
|
+
*
|
|
43
|
+
* Each entry is an ordered array; the function at the highest index runs
|
|
44
|
+
* first and may call `next()` to fall through to the function below it.
|
|
45
|
+
* The default config provides one handler each for
|
|
46
|
+
* `'application/x-lexical-editor'`, `'text/html'`, and `'text/plain'` that
|
|
47
|
+
* matches the legacy {@link $insertDataTransferForRichText} behavior.
|
|
48
|
+
*
|
|
49
|
+
* When {@link ClipboardImportExtension} merges a partial config, new
|
|
50
|
+
* functions are appended to the existing array for each MIME type, so
|
|
51
|
+
* later-registered handlers run before earlier ones (including the
|
|
52
|
+
* defaults) and may delegate to them via `next()`.
|
|
53
|
+
*
|
|
54
|
+
* @experimental
|
|
55
|
+
*/
|
|
56
|
+
export type ImportMimeTypeConfig = {
|
|
57
|
+
[key in keyof LexicalClipboardData | (string & {})]?: ImportMimeTypeFunction[] | undefined;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Per-MIME-type ordering weights. Lower numbers run first.
|
|
61
|
+
*
|
|
62
|
+
* Composable across extensions: each extension contributes weights for
|
|
63
|
+
* its MIME types without needing to coordinate. A partial config that
|
|
64
|
+
* sets `{'application/vnd.myapp+json': 5}` slots its type between the
|
|
65
|
+
* built-in `application/x-lexical-editor` (0) and `text/html` (10) — no
|
|
66
|
+
* need to enumerate the full ordering. mergeConfig spreads pairs (later
|
|
67
|
+
* keys override earlier ones for the same MIME type, so an extension
|
|
68
|
+
* can also re-rank a built-in by repeating its key with a new weight).
|
|
69
|
+
*
|
|
70
|
+
* Iteration: every MIME type that has a handler stack and is present in
|
|
71
|
+
* the dataTransfer (regardless of whether it has an explicit weight) is
|
|
72
|
+
* tried; MIME types with no explicit weight sort to the end, behind all
|
|
73
|
+
* weighted ones, in lexical order.
|
|
74
|
+
*
|
|
75
|
+
* @experimental
|
|
76
|
+
*/
|
|
77
|
+
export type ImportMimeTypePriority = {
|
|
78
|
+
readonly [key in keyof LexicalClipboardData | (string & {})]?: number | undefined;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Configuration for {@link ClipboardImportExtension}.
|
|
82
|
+
*
|
|
83
|
+
* @experimental
|
|
84
|
+
*/
|
|
85
|
+
export interface ClipboardImportConfig {
|
|
86
|
+
/**
|
|
87
|
+
* The per-MIME-type deserializer stacks used by
|
|
88
|
+
* {@link $insertDataTransferForRichText} when handling a paste or drop
|
|
89
|
+
* event.
|
|
90
|
+
*
|
|
91
|
+
* Merged with `[...prev, ...override]` per MIME type, matching the
|
|
92
|
+
* behavior of {@link GetClipboardDataExtension.$exportMimeType}.
|
|
93
|
+
*
|
|
94
|
+
* Apps add a stack under a brand-new key to register a brand-new MIME
|
|
95
|
+
* type. Set a {@link priority} weight to control where in the
|
|
96
|
+
* iteration it sits relative to the built-ins.
|
|
97
|
+
*/
|
|
98
|
+
$importMimeType: ImportMimeTypeConfig;
|
|
99
|
+
/**
|
|
100
|
+
* See {@link ImportMimeTypePriority}. Spread-merged across configs —
|
|
101
|
+
* extensions contribute weights without coordinating with each other.
|
|
102
|
+
*/
|
|
103
|
+
priority: ImportMimeTypePriority;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Default per-MIME-type weights reproducing the legacy
|
|
107
|
+
* `$insertDataTransferForRichText` ordering:
|
|
108
|
+
*
|
|
109
|
+
* `application/x-lexical-editor` (0) → `text/html` (10) →
|
|
110
|
+
* `text/plain` (20) → `text/uri-list` (30).
|
|
111
|
+
*
|
|
112
|
+
* Gaps between weights let third-party MIME types slot in (e.g. weight
|
|
113
|
+
* 5 to run between lexical and html). Apps can also override built-in
|
|
114
|
+
* weights to demote them.
|
|
115
|
+
*
|
|
116
|
+
* @experimental
|
|
117
|
+
*/
|
|
118
|
+
export declare const DEFAULT_IMPORT_MIME_TYPE_PRIORITY: ImportMimeTypePriority;
|
|
119
|
+
/**
|
|
120
|
+
* The default per-MIME-type handler stacks reproducing the legacy
|
|
121
|
+
* {@link $insertDataTransferForRichText} behavior exactly. Stacked
|
|
122
|
+
* extensions append on top of these.
|
|
123
|
+
*
|
|
124
|
+
* @experimental
|
|
125
|
+
*/
|
|
126
|
+
export declare const DEFAULT_IMPORT_MIME_TYPE: ImportMimeTypeConfig;
|
|
127
|
+
/**
|
|
128
|
+
* Output of {@link ClipboardImportExtension}: the merged configuration
|
|
129
|
+
* plus a self-contained {@link $insertDataTransfer} function that owns
|
|
130
|
+
* the entire paste-side iteration over the priority list. Apps look this
|
|
131
|
+
* up via peer-dependency and call it directly; {@link
|
|
132
|
+
* $insertDataTransferForRichText} delegates to it.
|
|
133
|
+
*
|
|
134
|
+
* @experimental
|
|
135
|
+
*/
|
|
136
|
+
export interface ClipboardImportOutput extends ClipboardImportConfig {
|
|
137
|
+
/**
|
|
138
|
+
* Try every MIME type in `priority` order against the `DataTransfer`,
|
|
139
|
+
* invoking the configured stack for the first one that has a non-empty
|
|
140
|
+
* payload. Returns `true` if any stack claimed the data.
|
|
141
|
+
*/
|
|
142
|
+
$insertDataTransfer(dataTransfer: DataTransfer, selection: BaseSelection): boolean;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* @internal
|
|
146
|
+
*
|
|
147
|
+
* Look up the {@link ClipboardImportOutput} on the active editor. Returns
|
|
148
|
+
* a static default-backed output when no {@link ClipboardImportExtension}
|
|
149
|
+
* is configured, so callers can always invoke `output.$insertDataTransfer`
|
|
150
|
+
* regardless of whether the editor opted in.
|
|
151
|
+
*/
|
|
152
|
+
export declare function $getImportOutput(): ClipboardImportOutput;
|
|
153
|
+
/**
|
|
154
|
+
* @experimental
|
|
155
|
+
*
|
|
156
|
+
* Mirror of {@link GetClipboardDataExtension} for the import direction.
|
|
157
|
+
* Holds a per-MIME-type stack of {@link ImportMimeTypeFunction}s.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* Route `text/html` pastes through {@link DOMImportExtension}, leaving the
|
|
161
|
+
* defaults for other MIME types untouched:
|
|
162
|
+
* ```ts
|
|
163
|
+
* import {configExtension, defineExtension, $getEditor} from 'lexical';
|
|
164
|
+
* import {
|
|
165
|
+
* ClipboardImportExtension,
|
|
166
|
+
* $insertGeneratedNodes,
|
|
167
|
+
* } from '@lexical/clipboard';
|
|
168
|
+
* import {
|
|
169
|
+
* contextValue,
|
|
170
|
+
* DOMImportExtension,
|
|
171
|
+
* ImportSource,
|
|
172
|
+
* ImportSourceDataTransfer,
|
|
173
|
+
* $generateNodesFromDOMViaExtension,
|
|
174
|
+
* } from '@lexical/html';
|
|
175
|
+
*
|
|
176
|
+
* defineExtension({
|
|
177
|
+
* name: 'app',
|
|
178
|
+
* dependencies: [
|
|
179
|
+
* DOMImportExtension,
|
|
180
|
+
* configExtension(ClipboardImportExtension, {
|
|
181
|
+
* $importMimeType: {
|
|
182
|
+
* 'text/html': [
|
|
183
|
+
* (html, selection, _$next, dataTransfer) => {
|
|
184
|
+
* const parser = new DOMParser();
|
|
185
|
+
* const dom = parser.parseFromString(html, 'text/html');
|
|
186
|
+
* const nodes = $generateNodesFromDOMViaExtension(dom, {
|
|
187
|
+
* context: [
|
|
188
|
+
* contextValue(ImportSource, 'paste'),
|
|
189
|
+
* contextValue(ImportSourceDataTransfer, dataTransfer),
|
|
190
|
+
* ],
|
|
191
|
+
* });
|
|
192
|
+
* $insertGeneratedNodes($getEditor(), nodes, selection);
|
|
193
|
+
* return true;
|
|
194
|
+
* },
|
|
195
|
+
* ],
|
|
196
|
+
* },
|
|
197
|
+
* }),
|
|
198
|
+
* ],
|
|
199
|
+
* });
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export declare const ClipboardImportExtension: import("lexical").LexicalExtension<ClipboardImportConfig, "@lexical/clipboard/Import", ClipboardImportOutput, unknown>;
|
|
203
|
+
/**
|
|
204
|
+
* @experimental
|
|
205
|
+
*
|
|
206
|
+
* Drop-in extension that routes `text/html` clipboard pastes and drops
|
|
207
|
+
* through the {@link DOMImportExtension} pipeline (rules, schemas,
|
|
208
|
+
* preprocessors, overlays) instead of the legacy
|
|
209
|
+
* {@link $generateNodesFromDOM}. Add to your extension dependencies along
|
|
210
|
+
* with the per-package import extensions you want active
|
|
211
|
+
* ({@link CoreImportExtension}, {@link RichTextImportExtension}, etc.).
|
|
212
|
+
*
|
|
213
|
+
* The original {@link DataTransfer} and `'paste'` source kind are forwarded
|
|
214
|
+
* into the import context so rules and preprocessors can read them via
|
|
215
|
+
* `ctx.get(ImportSourceDataTransfer)` / `ctx.get(ImportSource)`.
|
|
216
|
+
*
|
|
217
|
+
* Equivalent to stacking this `text/html` handler manually via
|
|
218
|
+
* `configExtension(ClipboardImportExtension, {...})`.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```ts
|
|
222
|
+
* import {defineExtension} from 'lexical';
|
|
223
|
+
* import {ClipboardDOMImportExtension} from '@lexical/clipboard';
|
|
224
|
+
* import {CoreImportExtension, RichTextImportExtension} from '@lexical/html';
|
|
225
|
+
*
|
|
226
|
+
* defineExtension({
|
|
227
|
+
* name: 'app',
|
|
228
|
+
* dependencies: [
|
|
229
|
+
* CoreImportExtension,
|
|
230
|
+
* RichTextImportExtension,
|
|
231
|
+
* ClipboardDOMImportExtension,
|
|
232
|
+
* ],
|
|
233
|
+
* });
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export declare const ClipboardDOMImportExtension: import("lexical").LexicalExtension<import("lexical").ExtensionConfigBase, "@lexical/clipboard/DOMImport", unknown, unknown>;
|