@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.
@@ -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>;