@prosekit/extensions 0.7.17 → 0.7.19
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.
@@ -17,6 +17,7 @@ import { DedentListOptions } from 'prosemirror-flat-list';
|
|
17
17
|
import { config as default_alias_1 } from '@prosekit/dev/config-vitest';
|
18
18
|
import { DocExtension } from '@prosekit/core';
|
19
19
|
import { EditorState } from '@prosekit/pm/state';
|
20
|
+
import type { EditorView } from '@prosekit/pm/view';
|
20
21
|
import { Extension } from '@prosekit/core';
|
21
22
|
import { ExtensionTyping } from '@prosekit/core';
|
22
23
|
import { ExtractMarkActions } from '@prosekit/core';
|
@@ -572,6 +573,14 @@ export { defineDropCursor as defineDropCursor_alias_1 }
|
|
572
573
|
*/
|
573
574
|
export declare function defineEnterRule({ regex, handler, stop, }: EnterRuleOptions): PlainExtension;
|
574
575
|
|
576
|
+
declare function defineFileDropHandler(handler: FileDropHandler): PlainExtension;
|
577
|
+
export { defineFileDropHandler }
|
578
|
+
export { defineFileDropHandler as defineFileDropHandler_alias_1 }
|
579
|
+
|
580
|
+
declare function defineFilePasteHandler(handler: FilePasteHandler): PlainExtension;
|
581
|
+
export { defineFilePasteHandler }
|
582
|
+
export { defineFilePasteHandler as defineFilePasteHandler_alias_1 }
|
583
|
+
|
575
584
|
/**
|
576
585
|
* Capture clicks near and arrow-key-motion past places that don't have a
|
577
586
|
* normally selectable position nearby, and create a gap cursor selection for
|
@@ -1234,6 +1243,66 @@ declare const exitTable: Command;
|
|
1234
1243
|
export { exitTable }
|
1235
1244
|
export { exitTable as exitTable_alias_1 }
|
1236
1245
|
|
1246
|
+
/**
|
1247
|
+
* A function that handles one of the files in a drop event.
|
1248
|
+
*
|
1249
|
+
* Returns `true` if the file was handled and thus should not be handled by
|
1250
|
+
* other handlers.
|
1251
|
+
*/
|
1252
|
+
export declare type FileDropHandler = (options: FileDropHandlerOptions) => boolean | void;
|
1253
|
+
|
1254
|
+
declare interface FileDropHandlerOptions {
|
1255
|
+
/**
|
1256
|
+
* The editor view.
|
1257
|
+
*/
|
1258
|
+
view: EditorView;
|
1259
|
+
/**
|
1260
|
+
* The event that triggered the drop.
|
1261
|
+
*/
|
1262
|
+
event: DragEvent;
|
1263
|
+
/**
|
1264
|
+
* The file that was dropped.
|
1265
|
+
*/
|
1266
|
+
file: File;
|
1267
|
+
/**
|
1268
|
+
* The position of the document where the file was dropped.
|
1269
|
+
*/
|
1270
|
+
pos: number;
|
1271
|
+
}
|
1272
|
+
export { FileDropHandlerOptions }
|
1273
|
+
export { FileDropHandlerOptions as FileDropHandlerOptions_alias_1 }
|
1274
|
+
|
1275
|
+
declare type FileHandler<E extends Event> = (options: {
|
1276
|
+
view: EditorView;
|
1277
|
+
event: E;
|
1278
|
+
file: File;
|
1279
|
+
}) => boolean | void;
|
1280
|
+
|
1281
|
+
/**
|
1282
|
+
* A function that handles one of the files in a paste event.
|
1283
|
+
*
|
1284
|
+
* Returns `true` if the file was handled and thus should not be handled by
|
1285
|
+
* other handlers.
|
1286
|
+
*/
|
1287
|
+
export declare type FilePasteHandler = (options: FilePasteHandlerOptions) => boolean | void;
|
1288
|
+
|
1289
|
+
declare interface FilePasteHandlerOptions {
|
1290
|
+
/**
|
1291
|
+
* The editor view.
|
1292
|
+
*/
|
1293
|
+
view: EditorView;
|
1294
|
+
/**
|
1295
|
+
* The event that triggered the paste.
|
1296
|
+
*/
|
1297
|
+
event: ClipboardEvent;
|
1298
|
+
/**
|
1299
|
+
* The file that was pasted.
|
1300
|
+
*/
|
1301
|
+
file: File;
|
1302
|
+
}
|
1303
|
+
export { FilePasteHandlerOptions }
|
1304
|
+
export { FilePasteHandlerOptions as FilePasteHandlerOptions_alias_1 }
|
1305
|
+
|
1237
1306
|
/**
|
1238
1307
|
* Try to find a resolved pos of a cell by using the given pos as a hit point.
|
1239
1308
|
*
|
@@ -1267,6 +1336,8 @@ export declare function getPluginState(state: EditorState): PredictionPluginStat
|
|
1267
1336
|
|
1268
1337
|
export declare function getTrMeta(tr: Transaction): PredictionPluginState;
|
1269
1338
|
|
1339
|
+
export declare function handleEvent<E extends Event>(view: EditorView, event: E, handlers: FileHandler<E>[], getFiles: (event: E) => File[]): boolean;
|
1340
|
+
|
1270
1341
|
declare interface HeadingAttrs {
|
1271
1342
|
level: number;
|
1272
1343
|
}
|
@@ -1359,6 +1430,8 @@ export { HorizontalRuleSpecExtension as HorizontalRuleSpecExtension_alias_1 }
|
|
1359
1430
|
*/
|
1360
1431
|
declare interface ImageAttrs {
|
1361
1432
|
src?: string | null;
|
1433
|
+
width?: number | null;
|
1434
|
+
height?: number | null;
|
1362
1435
|
}
|
1363
1436
|
export { ImageAttrs }
|
1364
1437
|
export { ImageAttrs as ImageAttrs_alias_1 }
|
@@ -1706,9 +1779,10 @@ export declare type ModClickPreventionExtension = PlainExtension;
|
|
1706
1779
|
|
1707
1780
|
export declare interface PlaceholderOptions {
|
1708
1781
|
/**
|
1709
|
-
* The placeholder
|
1782
|
+
* The placeholder to use. It can be a static string or a function that
|
1783
|
+
* receives the current editor state and returns a string.
|
1710
1784
|
*/
|
1711
|
-
placeholder: string;
|
1785
|
+
placeholder: string | ((state: EditorState) => string);
|
1712
1786
|
/**
|
1713
1787
|
* By default, the placeholder text will be shown whenever the current text
|
1714
1788
|
* cursor is in an empty text node. If you only want to show the placeholder
|
@@ -1956,6 +2030,8 @@ export declare function setupTest(): {
|
|
1956
2030
|
}>;
|
1957
2031
|
image: NodeAction< {
|
1958
2032
|
src?: (string | null) | undefined;
|
2033
|
+
width?: (number | null) | undefined;
|
2034
|
+
height?: (number | null) | undefined;
|
1959
2035
|
}>;
|
1960
2036
|
list: NodeAction< {
|
1961
2037
|
kind?: ("bullet" | "ordered" | "task" | "toggle") | undefined;
|
@@ -2215,6 +2291,82 @@ export declare const undo: Command;
|
|
2215
2291
|
export { UnwrapListOptions }
|
2216
2292
|
export { UnwrapListOptions as UnwrapListOptions_alias_1 }
|
2217
2293
|
|
2294
|
+
/**
|
2295
|
+
* The implementation of the actual upload function. You need to implement this
|
2296
|
+
* function to upload files to your desired destination.
|
2297
|
+
*/
|
2298
|
+
declare type Uploader<Result> = (options: UploaderOptions) => Promise<Result>;
|
2299
|
+
export { Uploader }
|
2300
|
+
export { Uploader as Uploader_alias_1 }
|
2301
|
+
|
2302
|
+
declare interface UploaderOptions {
|
2303
|
+
/**
|
2304
|
+
* The file to be uploaded.
|
2305
|
+
*/
|
2306
|
+
file: File;
|
2307
|
+
/**
|
2308
|
+
* A callback function that should be called with the upload progress updates.
|
2309
|
+
*/
|
2310
|
+
onProgress: (progress: UploadProgress) => void;
|
2311
|
+
}
|
2312
|
+
export { UploaderOptions }
|
2313
|
+
export { UploaderOptions as UploaderOptions_alias_1 }
|
2314
|
+
|
2315
|
+
/**
|
2316
|
+
* An interface representing the upload progress.
|
2317
|
+
*/
|
2318
|
+
declare interface UploadProgress {
|
2319
|
+
loaded: number;
|
2320
|
+
total: number;
|
2321
|
+
}
|
2322
|
+
export { UploadProgress }
|
2323
|
+
export { UploadProgress as UploadProgress_alias_1 }
|
2324
|
+
|
2325
|
+
/**
|
2326
|
+
* A class that represents a upload task.
|
2327
|
+
*/
|
2328
|
+
declare class UploadTask<Result> {
|
2329
|
+
/**
|
2330
|
+
* An [object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)
|
2331
|
+
* representing the file to be uploaded. This URL will be revoked once the
|
2332
|
+
* upload is complete successfully.
|
2333
|
+
*/
|
2334
|
+
readonly objectURL: string;
|
2335
|
+
/**
|
2336
|
+
* A boolean indicating whether the upload is complete (either successfully or with an error).
|
2337
|
+
*/
|
2338
|
+
protected done: boolean;
|
2339
|
+
/**
|
2340
|
+
* A promise that fulfills once the upload is complete, or rejects if an error occurs.
|
2341
|
+
*/
|
2342
|
+
readonly finished: Promise<Result>;
|
2343
|
+
private subscribers;
|
2344
|
+
/**
|
2345
|
+
* Creates a new upload task. You can find the upload task by its object URL
|
2346
|
+
* later using `UploadTask.get()`.
|
2347
|
+
*
|
2348
|
+
* @param options - The options for the upload task.
|
2349
|
+
*/
|
2350
|
+
constructor({ file, uploader }: {
|
2351
|
+
file: File;
|
2352
|
+
uploader: Uploader<Result>;
|
2353
|
+
});
|
2354
|
+
/**
|
2355
|
+
* Subscribes to progress updates. Returns a function to unsubscribe.
|
2356
|
+
*/
|
2357
|
+
subscribeProgress(callback: (progress: UploadProgress) => void): VoidFunction;
|
2358
|
+
/**
|
2359
|
+
* Finds an upload task by its object URL.
|
2360
|
+
*/
|
2361
|
+
static get<Result = unknown>(objectURL: string): UploadTask<Result> | undefined;
|
2362
|
+
/**
|
2363
|
+
* Deletes an upload task by its object URL.
|
2364
|
+
*/
|
2365
|
+
static delete(objectURL: string): void;
|
2366
|
+
}
|
2367
|
+
export { UploadTask }
|
2368
|
+
export { UploadTask as UploadTask_alias_1 }
|
2369
|
+
|
2218
2370
|
/**
|
2219
2371
|
* @internal
|
2220
2372
|
*/
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export { defineFilePasteHandler_alias_1 as defineFilePasteHandler } from './_tsup-dts-rollup';
|
2
|
+
export { FilePasteHandlerOptions_alias_1 as FilePasteHandlerOptions } from './_tsup-dts-rollup';
|
3
|
+
export { defineFileDropHandler_alias_1 as defineFileDropHandler } from './_tsup-dts-rollup';
|
4
|
+
export { FileDropHandlerOptions_alias_1 as FileDropHandlerOptions } from './_tsup-dts-rollup';
|
5
|
+
export { UploadProgress_alias_1 as UploadProgress } from './_tsup-dts-rollup';
|
6
|
+
export { UploaderOptions_alias_1 as UploaderOptions } from './_tsup-dts-rollup';
|
7
|
+
export { Uploader_alias_1 as Uploader } from './_tsup-dts-rollup';
|
8
|
+
export { UploadTask_alias_1 as UploadTask } from './_tsup-dts-rollup';
|
@@ -0,0 +1,151 @@
|
|
1
|
+
// src/file/file-paste-handler.ts
|
2
|
+
import {
|
3
|
+
defineFacet,
|
4
|
+
defineFacetPayload,
|
5
|
+
editorEventFacet
|
6
|
+
} from "@prosekit/core";
|
7
|
+
|
8
|
+
// src/file/helpers.ts
|
9
|
+
function handleFile(view, event, file, handlers) {
|
10
|
+
for (let i = handlers.length - 1; i >= 0; i--) {
|
11
|
+
const handler = handlers[i];
|
12
|
+
if (handler({ view, event, file })) {
|
13
|
+
return true;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
return false;
|
17
|
+
}
|
18
|
+
function handleEvent(view, event, handlers, getFiles3) {
|
19
|
+
const files = getFiles3(event);
|
20
|
+
let handled = false;
|
21
|
+
for (const file of files) {
|
22
|
+
if (handleFile(view, event, file, handlers)) {
|
23
|
+
handled = true;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
return handled;
|
27
|
+
}
|
28
|
+
|
29
|
+
// src/file/file-paste-handler.ts
|
30
|
+
function defineFilePasteHandler(handler) {
|
31
|
+
return defineFacetPayload(facet, [handler]);
|
32
|
+
}
|
33
|
+
function getFiles(event) {
|
34
|
+
var _a, _b;
|
35
|
+
return Array.from((_b = (_a = event.clipboardData) == null ? void 0 : _a.files) != null ? _b : []);
|
36
|
+
}
|
37
|
+
var facet = defineFacet({
|
38
|
+
parent: editorEventFacet,
|
39
|
+
singleton: true,
|
40
|
+
reducer: (handlers) => {
|
41
|
+
const pasteHandler = (view, event) => {
|
42
|
+
return handleEvent(view, event, handlers, getFiles);
|
43
|
+
};
|
44
|
+
return ["paste", pasteHandler];
|
45
|
+
}
|
46
|
+
});
|
47
|
+
|
48
|
+
// src/file/file-drop-handler.ts
|
49
|
+
import {
|
50
|
+
defineFacet as defineFacet2,
|
51
|
+
defineFacetPayload as defineFacetPayload2,
|
52
|
+
editorEventFacet as editorEventFacet2
|
53
|
+
} from "@prosekit/core";
|
54
|
+
function defineFileDropHandler(handler) {
|
55
|
+
return defineFacetPayload2(facet2, [handler]);
|
56
|
+
}
|
57
|
+
function getFiles2(event) {
|
58
|
+
var _a, _b;
|
59
|
+
return Array.from((_b = (_a = event.dataTransfer) == null ? void 0 : _a.files) != null ? _b : []);
|
60
|
+
}
|
61
|
+
var facet2 = defineFacet2({
|
62
|
+
parent: editorEventFacet2,
|
63
|
+
singleton: true,
|
64
|
+
reducer: (handlers) => {
|
65
|
+
const dropHandler = (view, event) => {
|
66
|
+
const position = view.posAtCoords({ left: event.x, top: event.y });
|
67
|
+
if (!position) {
|
68
|
+
return false;
|
69
|
+
}
|
70
|
+
const pos = position.inside > 0 ? position.inside : position.pos;
|
71
|
+
return handleEvent(
|
72
|
+
view,
|
73
|
+
event,
|
74
|
+
handlers.map((handler) => (options) => handler({ ...options, pos })),
|
75
|
+
getFiles2
|
76
|
+
);
|
77
|
+
};
|
78
|
+
return ["drop", dropHandler];
|
79
|
+
}
|
80
|
+
});
|
81
|
+
|
82
|
+
// src/file/file-upload.ts
|
83
|
+
var UploadTask = class {
|
84
|
+
/**
|
85
|
+
* Creates a new upload task. You can find the upload task by its object URL
|
86
|
+
* later using `UploadTask.get()`.
|
87
|
+
*
|
88
|
+
* @param options - The options for the upload task.
|
89
|
+
*/
|
90
|
+
constructor({ file, uploader }) {
|
91
|
+
/**
|
92
|
+
* A boolean indicating whether the upload is complete (either successfully or with an error).
|
93
|
+
*/
|
94
|
+
this.done = false;
|
95
|
+
this.subscribers = [];
|
96
|
+
this.objectURL = URL.createObjectURL(file);
|
97
|
+
this.finished = new Promise((resolve, reject) => {
|
98
|
+
const maybePromise = uploader({
|
99
|
+
file,
|
100
|
+
onProgress: (progress) => {
|
101
|
+
for (const subscriber of this.subscribers) {
|
102
|
+
subscriber(progress);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
});
|
106
|
+
Promise.resolve(maybePromise).then(
|
107
|
+
(result) => {
|
108
|
+
this.done = true;
|
109
|
+
URL.revokeObjectURL(this.objectURL);
|
110
|
+
resolve(result);
|
111
|
+
},
|
112
|
+
(error) => {
|
113
|
+
this.done = true;
|
114
|
+
reject(
|
115
|
+
new Error("[prosekit] Failed to upload file", { cause: error })
|
116
|
+
);
|
117
|
+
}
|
118
|
+
);
|
119
|
+
});
|
120
|
+
store.set(this.objectURL, this);
|
121
|
+
}
|
122
|
+
/**
|
123
|
+
* Subscribes to progress updates. Returns a function to unsubscribe.
|
124
|
+
*/
|
125
|
+
subscribeProgress(callback) {
|
126
|
+
this.subscribers.push(callback);
|
127
|
+
return () => {
|
128
|
+
this.subscribers = this.subscribers.filter(
|
129
|
+
(subscriber) => subscriber !== callback
|
130
|
+
);
|
131
|
+
};
|
132
|
+
}
|
133
|
+
/**
|
134
|
+
* Finds an upload task by its object URL.
|
135
|
+
*/
|
136
|
+
static get(objectURL) {
|
137
|
+
return store.get(objectURL);
|
138
|
+
}
|
139
|
+
/**
|
140
|
+
* Deletes an upload task by its object URL.
|
141
|
+
*/
|
142
|
+
static delete(objectURL) {
|
143
|
+
store.delete(objectURL);
|
144
|
+
}
|
145
|
+
};
|
146
|
+
var store = /* @__PURE__ */ new Map();
|
147
|
+
export {
|
148
|
+
UploadTask,
|
149
|
+
defineFileDropHandler,
|
150
|
+
defineFilePasteHandler
|
151
|
+
};
|
@@ -17,7 +17,9 @@ function defineImageSpec() {
|
|
17
17
|
return defineNodeSpec({
|
18
18
|
name: "image",
|
19
19
|
attrs: {
|
20
|
-
src: { default: null }
|
20
|
+
src: { default: null },
|
21
|
+
width: { default: null },
|
22
|
+
height: { default: null }
|
21
23
|
},
|
22
24
|
group: "block",
|
23
25
|
defining: true,
|
@@ -30,7 +32,17 @@ function defineImageSpec() {
|
|
30
32
|
return { src: null };
|
31
33
|
}
|
32
34
|
const src = element.getAttribute("src") || null;
|
33
|
-
|
35
|
+
let width = null;
|
36
|
+
let height = null;
|
37
|
+
const rect = element.getBoundingClientRect();
|
38
|
+
if (rect.width > 0 && rect.height > 0) {
|
39
|
+
width = rect.width;
|
40
|
+
height = rect.height;
|
41
|
+
} else if (element instanceof HTMLImageElement && element.naturalWidth > 0 && element.naturalHeight > 0) {
|
42
|
+
width = element.naturalWidth;
|
43
|
+
height = element.naturalHeight;
|
44
|
+
}
|
45
|
+
return { src, width, height };
|
34
46
|
}
|
35
47
|
}
|
36
48
|
],
|
@@ -1,22 +1,25 @@
|
|
1
1
|
// src/placeholder/index.ts
|
2
|
-
import { definePlugin, isInCodeBlock } from "@prosekit/core";
|
2
|
+
import { definePlugin, isInCodeBlock, maybeRun } from "@prosekit/core";
|
3
3
|
import { Plugin, PluginKey } from "@prosekit/pm/state";
|
4
4
|
import { Decoration, DecorationSet } from "@prosekit/pm/view";
|
5
5
|
function definePlaceholder(options) {
|
6
6
|
return definePlugin(createPlaceholderPlugin(options));
|
7
7
|
}
|
8
|
-
function createPlaceholderPlugin(
|
8
|
+
function createPlaceholderPlugin({
|
9
|
+
placeholder,
|
10
|
+
strategy = "block"
|
11
|
+
}) {
|
9
12
|
return new Plugin({
|
10
13
|
key: new PluginKey("prosekit-placeholder"),
|
11
14
|
props: {
|
12
15
|
decorations: (state) => {
|
13
|
-
if (
|
16
|
+
if (strategy === "doc" && !isDocEmpty(state.doc)) {
|
14
17
|
return null;
|
15
18
|
}
|
16
19
|
if (isInCodeBlock(state.selection)) {
|
17
20
|
return null;
|
18
21
|
}
|
19
|
-
const placeholderText =
|
22
|
+
const placeholderText = maybeRun(placeholder, state);
|
20
23
|
const deco = createPlaceholderDecoration(state, placeholderText);
|
21
24
|
if (!deco) {
|
22
25
|
return null;
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prosekit/extensions",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.7.
|
4
|
+
"version": "0.7.19",
|
5
5
|
"private": false,
|
6
6
|
"author": {
|
7
7
|
"name": "ocavue",
|
@@ -73,6 +73,11 @@
|
|
73
73
|
"import": "./dist/prosekit-extensions-enter-rule.js",
|
74
74
|
"default": "./dist/prosekit-extensions-enter-rule.js"
|
75
75
|
},
|
76
|
+
"./file": {
|
77
|
+
"types": "./dist/prosekit-extensions-file.d.ts",
|
78
|
+
"import": "./dist/prosekit-extensions-file.js",
|
79
|
+
"default": "./dist/prosekit-extensions-file.js"
|
80
|
+
},
|
76
81
|
"./gap-cursor": {
|
77
82
|
"types": "./dist/prosekit-extensions-gap-cursor.d.ts",
|
78
83
|
"import": "./dist/prosekit-extensions-gap-cursor.js",
|
@@ -214,8 +219,8 @@
|
|
214
219
|
"prosemirror-highlight": "^0.9.0",
|
215
220
|
"prosemirror-search": "^1.0.0",
|
216
221
|
"prosemirror-tables": "^1.5.0",
|
217
|
-
"shiki": "^1.
|
218
|
-
"@prosekit/core": "^0.7.
|
222
|
+
"shiki": "^1.22.0",
|
223
|
+
"@prosekit/core": "^0.7.12",
|
219
224
|
"@prosekit/pm": "^0.1.8"
|
220
225
|
},
|
221
226
|
"peerDependencies": {
|
@@ -239,17 +244,17 @@
|
|
239
244
|
}
|
240
245
|
},
|
241
246
|
"devDependencies": {
|
242
|
-
"@vitest/browser": "^2.
|
247
|
+
"@vitest/browser": "^2.1.3",
|
243
248
|
"just-pick": "^4.2.0",
|
244
249
|
"loro-crdt": "^0.16.12",
|
245
250
|
"loro-prosemirror": "^0.0.7",
|
246
|
-
"tsup": "^8.
|
251
|
+
"tsup": "^8.3.0",
|
247
252
|
"type-fest": "^4.26.1",
|
248
|
-
"typescript": "^5.
|
249
|
-
"vitest": "^2.
|
253
|
+
"typescript": "^5.6.3",
|
254
|
+
"vitest": "^2.1.3",
|
250
255
|
"y-prosemirror": "^1.2.12",
|
251
256
|
"y-protocols": "^1.0.6",
|
252
|
-
"yjs": "^13.6.
|
257
|
+
"yjs": "^13.6.20",
|
253
258
|
"@prosekit/dev": "0.0.0"
|
254
259
|
},
|
255
260
|
"scripts": {
|
@@ -286,6 +291,9 @@
|
|
286
291
|
"enter-rule": [
|
287
292
|
"./dist/prosekit-extensions-enter-rule.d.ts"
|
288
293
|
],
|
294
|
+
"file": [
|
295
|
+
"./dist/prosekit-extensions-file.d.ts"
|
296
|
+
],
|
289
297
|
"gap-cursor": [
|
290
298
|
"./dist/prosekit-extensions-gap-cursor.d.ts"
|
291
299
|
],
|