@prosekit/core 0.0.0-next-20230709094459 → 0.0.0-next-20240421132240

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.
@@ -1,9 +1,27 @@
1
- // src/commands/toggle-mark.ts
2
- import { toggleMark as baseToggleMark } from "@prosekit/pm/commands";
1
+ // src/commands/add-mark.ts
2
+ import "@prosekit/pm/model";
3
+ import "@prosekit/pm/state";
4
+
5
+ // src/utils/get-mark-type.ts
6
+ import "@prosekit/pm/model";
3
7
 
4
8
  // src/error.ts
5
9
  var ProseKitError = class extends Error {
6
10
  };
11
+ var EditorNotFoundError = class extends ProseKitError {
12
+ constructor() {
13
+ super(
14
+ "Unable to find editor. Pass it as an argument or call this function inside a ProseKit component."
15
+ );
16
+ }
17
+ };
18
+ var DOMDocumentNotFoundError = class extends ProseKitError {
19
+ constructor() {
20
+ super(
21
+ "Unable to find browser Document. When not in the browser environment, you need to pass a DOM Document."
22
+ );
23
+ }
24
+ };
7
25
 
8
26
  // src/utils/get-mark-type.ts
9
27
  function getMarkType(schema, type) {
@@ -17,134 +35,384 @@ function getMarkType(schema, type) {
17
35
  return type;
18
36
  }
19
37
 
20
- // src/commands/toggle-mark.ts
21
- function toggleMark(options) {
22
- return (state, dispatch, view) => {
23
- return baseToggleMark(
24
- getMarkType(state.schema, options.type),
25
- options.attrs
26
- )(state, dispatch, view);
38
+ // src/commands/add-mark.ts
39
+ function addMark(options) {
40
+ return (state, dispatch) => {
41
+ var _a, _b;
42
+ const mark = getMarkType(state.schema, options.type).create(options.attrs);
43
+ const from = (_a = options.from) != null ? _a : state.selection.from;
44
+ const to = (_b = options.to) != null ? _b : state.selection.to;
45
+ if (from > to) {
46
+ return false;
47
+ }
48
+ dispatch == null ? void 0 : dispatch(state.tr.addMark(from, to, mark));
49
+ return true;
27
50
  };
28
51
  }
29
52
 
30
- // src/editor/editor.ts
31
- import { Schema } from "@prosekit/pm/model";
32
- import { EditorState } from "@prosekit/pm/state";
33
- import { EditorView } from "@prosekit/pm/view";
34
-
35
- // src/types/void-function.ts
36
- function voidFunction() {
53
+ // src/commands/expand-mark.ts
54
+ import { TextSelection } from "@prosekit/pm/state";
55
+ function expandMark(options) {
56
+ return (state, dispatch) => {
57
+ const markType = getMarkType(state.schema, options.type);
58
+ const predicate = (mark) => mark.type === markType;
59
+ const from = expandMarkBefore(state.selection.$from, predicate);
60
+ const to = expandMarkAfter(state.selection.$to, predicate);
61
+ if (from === state.selection.from && to === state.selection.to) {
62
+ return false;
63
+ }
64
+ if (dispatch) {
65
+ dispatch(state.tr.setSelection(TextSelection.create(state.doc, from, to)));
66
+ }
67
+ return true;
68
+ };
37
69
  }
38
-
39
- // src/types/priority.ts
40
- var Priority = /* @__PURE__ */ ((Priority2) => {
41
- Priority2[Priority2["lowest"] = 4] = "lowest";
42
- Priority2[Priority2["low"] = 3] = "low";
43
- Priority2[Priority2["default"] = 2] = "default";
44
- Priority2[Priority2["high"] = 1] = "high";
45
- Priority2[Priority2["highest"] = 0] = "highest";
46
- return Priority2;
47
- })(Priority || {});
48
-
49
- // src/editor/facet.ts
50
- var nextIndex = 0;
51
- var Facet = class _Facet {
52
- constructor(combine, next) {
53
- /** @internal */
54
- this.index = nextIndex++;
55
- this.combine = combine;
56
- this.next = next;
70
+ function expandMarkBefore($pos, predicate) {
71
+ const { parent } = $pos;
72
+ if (!$pos.marks().some(predicate)) {
73
+ return $pos.pos;
57
74
  }
58
- static define({ combine, next }) {
59
- return new _Facet(combine, next);
75
+ const index = $pos.index();
76
+ let boundaryIndex = index;
77
+ for (let i = index; i >= 0; i--) {
78
+ const node = parent.child(i);
79
+ if (node.marks.some(predicate)) {
80
+ boundaryIndex = i;
81
+ } else {
82
+ break;
83
+ }
60
84
  }
61
- /** @internal */
62
- static defineSlot({
63
- combine
64
- }) {
65
- return new _Facet(combine, null);
85
+ return $pos.posAtIndex(boundaryIndex);
86
+ }
87
+ function expandMarkAfter($pos, predicate) {
88
+ const { parent } = $pos;
89
+ if (!$pos.marks().some(predicate)) {
90
+ return $pos.pos;
66
91
  }
67
- extension(inputs) {
68
- return new FacetExtension(this, inputs);
92
+ const index = Math.max(0, $pos.indexAfter() - 1);
93
+ const childCount = parent.childCount;
94
+ let boundaryIndex = index;
95
+ for (let i = index; i < childCount; i++) {
96
+ const node = parent.child(i);
97
+ if (node.marks.some(predicate)) {
98
+ boundaryIndex = i;
99
+ } else {
100
+ break;
101
+ }
69
102
  }
70
- };
71
- var FacetExtension = class {
72
- constructor(facet, inputs) {
73
- this.facet = facet;
74
- this.inputs = inputs;
103
+ return $pos.posAtIndex(boundaryIndex) + parent.child(boundaryIndex).nodeSize;
104
+ }
105
+
106
+ // src/commands/insert-node.ts
107
+ import "@prosekit/pm/state";
108
+ import { insertPoint } from "@prosekit/pm/transform";
109
+
110
+ // src/utils/get-node-type.ts
111
+ import "@prosekit/pm/model";
112
+ function getNodeType(schema, type) {
113
+ if (typeof type === "string") {
114
+ const nodeType = schema.nodes[type];
115
+ if (!nodeType) {
116
+ throw new ProseKitError(`Cannot find ProseMirror node type "${type}"`);
117
+ }
118
+ return nodeType;
75
119
  }
76
- };
77
- function sortFacets(unsorted) {
78
- var _a;
79
- const facets = unsorted.filter((val) => val);
80
- const facetMap = [];
81
- const inbounds = [];
82
- let facetCount = 0;
83
- for (const facet of facets) {
84
- const index = facet.index;
85
- if (facetMap[index] != null) {
86
- continue;
120
+ return type;
121
+ }
122
+
123
+ // src/utils/set-selection-around.ts
124
+ import { TextSelection as TextSelection2 } from "@prosekit/pm/state";
125
+ function setSelectionAround(tr, pos) {
126
+ const docSize = tr.doc.content.size;
127
+ const $pos = tr.doc.resolve(pos > docSize ? docSize : pos < 0 ? 0 : pos);
128
+ const selection = TextSelection2.between($pos, $pos);
129
+ tr.setSelection(selection);
130
+ }
131
+
132
+ // src/commands/insert-node.ts
133
+ function insertNode(options) {
134
+ return (state, dispatch) => {
135
+ var _a;
136
+ const node = options.node ? options.node : options.type ? getNodeType(state.schema, options.type).createChecked(options.attrs) : null;
137
+ if (!node) {
138
+ throw new ProseKitError("You must provide either a node or a type");
139
+ }
140
+ const insertPos = insertPoint(
141
+ state.doc,
142
+ (_a = options.pos) != null ? _a : state.selection.to,
143
+ node.type
144
+ );
145
+ if (insertPos == null)
146
+ return false;
147
+ if (dispatch) {
148
+ const tr = state.tr.insert(insertPos, node);
149
+ setSelectionAround(tr, insertPos + node.nodeSize);
150
+ dispatch(tr);
87
151
  }
88
- if (inbounds[index] == null) {
89
- inbounds[index] = 0;
152
+ return true;
153
+ };
154
+ }
155
+
156
+ // src/commands/remove-mark.ts
157
+ import "@prosekit/pm/model";
158
+ import "@prosekit/pm/state";
159
+ function removeMark(options) {
160
+ return (state, dispatch) => {
161
+ var _a, _b;
162
+ const markType = getMarkType(state.schema, options.type);
163
+ const mark = options.attrs ? markType.create(options.attrs) : markType;
164
+ const from = (_a = options.from) != null ? _a : state.selection.from;
165
+ const to = (_b = options.to) != null ? _b : state.selection.to;
166
+ if (from > to) {
167
+ return false;
90
168
  }
91
- facetCount++;
92
- facetMap[index] = facet;
93
- if (facet.next) {
94
- const nextIndex2 = facet.next.index;
95
- if (inbounds[nextIndex2] == null) {
96
- inbounds[nextIndex2] = 0;
169
+ dispatch == null ? void 0 : dispatch(state.tr.removeMark(from, to, mark));
170
+ return true;
171
+ };
172
+ }
173
+
174
+ // src/commands/set-block-type.ts
175
+ import "@prosekit/pm/state";
176
+
177
+ // src/utils/get-custom-selection.ts
178
+ import { TextSelection as TextSelection3 } from "@prosekit/pm/state";
179
+ function getCustomSelection(state, from, to) {
180
+ const pos = from != null ? from : to;
181
+ if (pos != null) {
182
+ const $from = state.doc.resolve(from != null ? from : pos);
183
+ const $to = state.doc.resolve(to != null ? to : pos);
184
+ return TextSelection3.between($from, $to);
185
+ }
186
+ return state.selection;
187
+ }
188
+
189
+ // src/commands/set-block-type.ts
190
+ function setBlockType(options) {
191
+ return (state, dispatch) => {
192
+ const nodeType = getNodeType(state.schema, options.type);
193
+ const selection = getCustomSelection(state, options.from, options.to);
194
+ const attrs = options.attrs;
195
+ let applicable = false;
196
+ for (let i = 0; i < selection.ranges.length && !applicable; i++) {
197
+ const {
198
+ $from: { pos: from },
199
+ $to: { pos: to }
200
+ } = selection.ranges[i];
201
+ state.doc.nodesBetween(from, to, (node, pos) => {
202
+ if (applicable)
203
+ return false;
204
+ if (!node.isTextblock || node.hasMarkup(nodeType, attrs))
205
+ return;
206
+ if (node.type == nodeType) {
207
+ applicable = true;
208
+ } else {
209
+ const $pos = state.doc.resolve(pos), index = $pos.index();
210
+ applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType);
211
+ }
212
+ });
213
+ }
214
+ if (!applicable)
215
+ return false;
216
+ if (dispatch) {
217
+ const tr = state.tr;
218
+ for (const range of selection.ranges) {
219
+ const {
220
+ $from: { pos: from },
221
+ $to: { pos: to }
222
+ } = range;
223
+ tr.setBlockType(from, to, nodeType, attrs);
97
224
  }
98
- inbounds[nextIndex2] += 1;
99
- if (facetMap[nextIndex2] == null) {
100
- facets.push(facet.next);
225
+ dispatch(tr.scrollIntoView());
226
+ }
227
+ return true;
228
+ };
229
+ }
230
+
231
+ // src/commands/set-node-attrs.ts
232
+ function setNodeAttrs(options) {
233
+ return (state, dispatch) => {
234
+ var _a;
235
+ const nodeType = getNodeType(state.schema, options.type);
236
+ const pos = (_a = options.pos) != null ? _a : state.selection.$from.before();
237
+ const node = state.doc.nodeAt(pos);
238
+ if (!node || node.type !== nodeType) {
239
+ return false;
240
+ }
241
+ if (dispatch) {
242
+ const { tr } = state;
243
+ for (const [key, value] of Object.entries(options.attrs)) {
244
+ if (value !== void 0) {
245
+ tr.setNodeAttribute(pos, key, value);
246
+ }
101
247
  }
248
+ dispatch(tr);
249
+ }
250
+ return true;
251
+ };
252
+ }
253
+
254
+ // src/commands/toggle-mark.ts
255
+ import { toggleMark as baseToggleMark } from "@prosekit/pm/commands";
256
+ import "@prosekit/pm/model";
257
+ import "@prosekit/pm/state";
258
+ function toggleMark({
259
+ type,
260
+ attrs
261
+ }) {
262
+ return (state, dispatch, view) => {
263
+ return baseToggleMark(getMarkType(state.schema, type), attrs)(
264
+ state,
265
+ dispatch,
266
+ view
267
+ );
268
+ };
269
+ }
270
+
271
+ // src/commands/toggle-node.ts
272
+ import { setBlockType as setBlockType2 } from "@prosekit/pm/commands";
273
+ import "@prosekit/pm/model";
274
+ import "@prosekit/pm/state";
275
+
276
+ // src/utils/attrs-match.ts
277
+ function attrsMatch(nodeOrMark, attrs) {
278
+ const currentAttrs = nodeOrMark.attrs;
279
+ for (const [key, value] of Object.entries(attrs)) {
280
+ if (currentAttrs[key] !== value) {
281
+ return false;
102
282
  }
103
283
  }
104
- const sortedFacets = [];
105
- const sortedIndexes = [];
106
- inbounds.forEach((inbound, index) => {
107
- if (inbound === 0) {
108
- sortedIndexes.push(index);
284
+ return true;
285
+ }
286
+
287
+ // src/utils/is-node-active.ts
288
+ function isNodeActive(state, type, attrs) {
289
+ const $pos = state.selection.$from;
290
+ const nodeType = getNodeType(state.schema, type);
291
+ for (let depth = $pos.depth; depth >= 0; depth--) {
292
+ const node = $pos.node(depth);
293
+ if (node.type === nodeType && (!attrs || attrsMatch(node, attrs))) {
294
+ return true;
109
295
  }
110
- });
111
- for (const index of sortedIndexes) {
112
- const facet = facetMap[index];
113
- sortedFacets.push(facet);
114
- const nextIndex2 = (_a = facet.next) == null ? void 0 : _a.index;
115
- if (nextIndex2 == null)
116
- continue;
117
- inbounds[nextIndex2] -= 1;
118
- if (inbounds[nextIndex2] === 0) {
119
- sortedIndexes.push(nextIndex2);
296
+ }
297
+ return false;
298
+ }
299
+
300
+ // src/commands/toggle-node.ts
301
+ function toggleNode({
302
+ type,
303
+ attrs
304
+ }) {
305
+ return (state, dispatch, view) => {
306
+ if (isNodeActive(state, type, attrs)) {
307
+ const defaultType = state.schema.topNodeType.contentMatch.defaultType;
308
+ if (!defaultType) {
309
+ return false;
310
+ }
311
+ return setBlockType2(defaultType)(state, dispatch, view);
312
+ } else {
313
+ const nodeType = getNodeType(state.schema, type);
314
+ return setBlockType2(nodeType, attrs)(state, dispatch, view);
315
+ }
316
+ };
317
+ }
318
+
319
+ // src/editor/editor.ts
320
+ import { Schema as Schema6 } from "@prosekit/pm/model";
321
+ import { EditorState as EditorState2 } from "@prosekit/pm/state";
322
+ import { EditorView } from "@prosekit/pm/view";
323
+
324
+ // src/extensions/default-state.ts
325
+ import { Selection } from "@prosekit/pm/state";
326
+
327
+ // src/utils/uniq-array.ts
328
+ function uniqPush(prev, next) {
329
+ const result = [...prev];
330
+ for (const item of next) {
331
+ if (!result.includes(item)) {
332
+ result.push(item);
120
333
  }
121
334
  }
122
- if (facetCount !== sortedFacets.length) {
123
- throw new Error(`Facet has circular dependency`);
335
+ return result;
336
+ }
337
+ function uniqRemove(prev, next) {
338
+ const result = [...prev];
339
+ for (const item of next) {
340
+ const index = result.indexOf(item);
341
+ if (index !== -1) {
342
+ result.splice(index, 1);
343
+ }
124
344
  }
125
- return sortedFacets;
345
+ return result;
126
346
  }
127
347
 
128
- // src/editor/slot.ts
129
- import OrderedMap from "orderedmap";
130
- var schemaSlot = Facet.defineSlot({
131
- combine: (specs) => {
132
- var _a;
133
- let nodes = OrderedMap.from({});
134
- let marks = OrderedMap.from({});
135
- let topNode = void 0;
136
- for (const spec of specs) {
137
- nodes = nodes.append(spec.nodes);
138
- marks = marks.append((_a = spec.marks) != null ? _a : {});
139
- topNode = topNode != null ? topNode : spec.topNode;
348
+ // src/facets/base-extension.ts
349
+ import "@prosekit/pm/model";
350
+ var BaseExtension = class {
351
+ constructor() {
352
+ this.extension = [];
353
+ }
354
+ };
355
+
356
+ // src/facets/facet.ts
357
+ var facetCount = 0;
358
+ function getFacetCount() {
359
+ return facetCount;
360
+ }
361
+ var Facet = class _Facet {
362
+ constructor(converter, next, singleton) {
363
+ /**
364
+ * @internal
365
+ */
366
+ this.index = facetCount++;
367
+ /**
368
+ * @internal
369
+ */
370
+ this.isSchema = false;
371
+ this.converter = converter;
372
+ this.next = next;
373
+ this.singleton = singleton;
374
+ }
375
+ static define({
376
+ converter,
377
+ convert,
378
+ next,
379
+ singleton
380
+ }) {
381
+ const converterFunction = converter ? converter : convert ? () => ({
382
+ create: convert,
383
+ update: convert
384
+ }) : null;
385
+ if (!converterFunction) {
386
+ throw new ProseKitError("Facet must have either 'convert' or 'converter'");
140
387
  }
141
- return { nodes, marks, topNode };
388
+ return new _Facet(converterFunction, next, singleton != null ? singleton : false);
142
389
  }
143
- });
144
- var stateSlot = Facet.defineSlot({
145
- combine: (callbacks) => {
390
+ /**
391
+ * @internal
392
+ */
393
+ static defineRootFacet(options) {
394
+ return _Facet.define(options);
395
+ }
396
+ extension(payloads) {
397
+ return new FacetExtensionImpl(this, payloads);
398
+ }
399
+ };
400
+ var FacetExtensionImpl = class extends BaseExtension {
401
+ constructor(facet, payloads) {
402
+ var _a;
403
+ super();
404
+ this.facet = facet;
405
+ this.payloads = payloads;
406
+ this.schema = null;
407
+ this.hasSchema = !!(facet.isSchema || ((_a = facet.next) == null ? void 0 : _a.isSchema));
408
+ }
409
+ };
410
+
411
+ // src/facets/state.ts
412
+ var stateFacet = Facet.defineRootFacet({
413
+ convert: (callbacks) => {
146
414
  return (ctx) => {
147
- var _a, _b, _c, _d, _e;
415
+ var _a, _b, _c, _d, _e, _f;
148
416
  const configs = callbacks.map((cb) => cb(ctx));
149
417
  const config = {
150
418
  schema: ctx.schema,
@@ -156,10 +424,12 @@ var stateSlot = Facet.defineSlot({
156
424
  config.doc = (_b = config.doc) != null ? _b : c.doc;
157
425
  config.selection = (_c = config.selection) != null ? _c : c.selection;
158
426
  config.storedMarks = [...config.storedMarks, ...(_d = c.storedMarks) != null ? _d : []];
159
- config.plugins = [...config.plugins, ...(_e = c.plugins) != null ? _e : []];
427
+ config.plugins = uniqPush((_e = config.plugins) != null ? _e : [], (_f = c.plugins) != null ? _f : []);
160
428
  }
161
429
  if (!config.doc && !config.schema) {
162
- throw new Error("Can't create state without a schema nor a document");
430
+ throw new ProseKitError(
431
+ "Can't create state without a schema nor a document"
432
+ );
163
433
  }
164
434
  if (config.doc) {
165
435
  config.schema = void 0;
@@ -168,35 +438,240 @@ var stateSlot = Facet.defineSlot({
168
438
  };
169
439
  }
170
440
  });
171
- var viewSlot = Facet.defineSlot({
172
- combine: (props) => {
173
- return Object.assign({}, ...props);
441
+
442
+ // src/utils/parse.ts
443
+ import { DOMParser, DOMSerializer } from "@prosekit/pm/model";
444
+ import { EditorState } from "@prosekit/pm/state";
445
+
446
+ // src/utils/get-dom-api.ts
447
+ function findGlobalBrowserDocument() {
448
+ if (typeof document !== "undefined") {
449
+ return document;
174
450
  }
175
- });
176
- var commandSlot = Facet.defineSlot({
177
- combine: (inputs) => {
451
+ if (typeof globalThis !== "undefined" && globalThis.document) {
452
+ return globalThis.document;
453
+ }
454
+ }
455
+ function findGlobalBrowserWindow() {
456
+ if (typeof window !== "undefined") {
457
+ return window;
458
+ }
459
+ if (typeof globalThis !== "undefined" && globalThis.window) {
460
+ return globalThis.window;
461
+ }
462
+ }
463
+ function findBrowserDocument(options) {
464
+ var _a, _b, _c;
465
+ return (_c = (_a = options == null ? void 0 : options.document) != null ? _a : findGlobalBrowserDocument()) != null ? _c : (_b = findGlobalBrowserWindow()) == null ? void 0 : _b.document;
466
+ }
467
+ function findBrowserWindow(options) {
468
+ var _a, _b, _c, _d;
469
+ return (_d = (_b = (_a = options == null ? void 0 : options.document) == null ? void 0 : _a.defaultView) != null ? _b : findGlobalBrowserWindow()) != null ? _d : (_c = findBrowserDocument(options)) == null ? void 0 : _c.defaultView;
470
+ }
471
+ function getBrowserDocument(options) {
472
+ const doc = findBrowserDocument(options);
473
+ if (doc)
474
+ return doc;
475
+ throw new DOMDocumentNotFoundError();
476
+ }
477
+ function getBrowserWindow(options) {
478
+ const win = findBrowserWindow(options);
479
+ if (win)
480
+ return win;
481
+ throw new DOMDocumentNotFoundError();
482
+ }
483
+
484
+ // src/utils/parse.ts
485
+ function jsonFromState(state) {
486
+ return state.toJSON();
487
+ }
488
+ function stateFromJSON(json, options) {
489
+ return EditorState.fromJSON({ schema: options.schema }, json);
490
+ }
491
+ function jsonFromNode(node) {
492
+ return node.toJSON();
493
+ }
494
+ function nodeFromJSON(json, options) {
495
+ return options.schema.nodeFromJSON(json);
496
+ }
497
+ function nodeFromElement(element, options) {
498
+ const Parser = options.DOMParser || DOMParser;
499
+ const schema = options.schema;
500
+ return Parser.fromSchema(schema).parse(element);
501
+ }
502
+ function elementFromNode(node, options) {
503
+ const Serializer = (options == null ? void 0 : options.DOMSerializer) || DOMSerializer;
504
+ const document2 = getBrowserDocument(options);
505
+ const schema = node.type.schema;
506
+ const serializer = Serializer.fromSchema(schema);
507
+ if (schema.topNodeType !== node.type) {
508
+ return serializer.serializeNode(node, { document: document2 });
509
+ } else {
510
+ return serializer.serializeFragment(
511
+ node.content,
512
+ { document: document2 },
513
+ document2.createElement("div")
514
+ );
515
+ }
516
+ }
517
+ function elementFromHTML(html, options) {
518
+ const win = getBrowserWindow(options);
519
+ const parser = new win.DOMParser();
520
+ return parser.parseFromString(`<body><div>${html}</div></body>`, "text/html").body.firstElementChild;
521
+ }
522
+ function htmlFromElement(element) {
523
+ return element.outerHTML;
524
+ }
525
+ function nodeFromHTML(html, options) {
526
+ return nodeFromElement(elementFromHTML(html, options), options);
527
+ }
528
+ function htmlFromNode(node, options) {
529
+ return elementFromNode(node, options).outerHTML;
530
+ }
531
+ function jsonFromElement(element, options) {
532
+ return jsonFromNode(nodeFromElement(element, options));
533
+ }
534
+ function elementFromJSON(json, options) {
535
+ return elementFromNode(nodeFromJSON(json, options), options);
536
+ }
537
+ function jsonFromHTML(html, options) {
538
+ return jsonFromElement(elementFromHTML(html, options), options);
539
+ }
540
+ function htmlFromJSON(json, options) {
541
+ return htmlFromElement(elementFromJSON(json, options));
542
+ }
543
+
544
+ // src/extensions/default-state.ts
545
+ function defineDefaultState({
546
+ defaultDoc,
547
+ defaultHTML,
548
+ defaultSelection
549
+ }) {
550
+ if (defaultHTML && defaultDoc) {
551
+ throw new ProseKitError(
552
+ "Only one of defaultHTML and defaultDoc can be provided"
553
+ );
554
+ }
555
+ return stateFacet.extension([
556
+ ({ schema }) => {
557
+ const config = {};
558
+ if (defaultHTML) {
559
+ if (typeof defaultHTML === "string") {
560
+ defaultDoc = jsonFromHTML(defaultHTML, { schema });
561
+ } else {
562
+ defaultDoc = jsonFromElement(defaultHTML, { schema });
563
+ }
564
+ }
565
+ if (defaultDoc) {
566
+ config.doc = schema.nodeFromJSON(defaultDoc);
567
+ if (defaultSelection) {
568
+ config.selection = Selection.fromJSON(config.doc, defaultSelection);
569
+ }
570
+ }
571
+ return config;
572
+ }
573
+ ]);
574
+ }
575
+
576
+ // src/types/priority.ts
577
+ var Priority = /* @__PURE__ */ ((Priority2) => {
578
+ Priority2[Priority2["lowest"] = 4] = "lowest";
579
+ Priority2[Priority2["low"] = 3] = "low";
580
+ Priority2[Priority2["default"] = 2] = "default";
581
+ Priority2[Priority2["high"] = 1] = "high";
582
+ Priority2[Priority2["highest"] = 0] = "highest";
583
+ return Priority2;
584
+ })(Priority || {});
585
+
586
+ // src/facets/command.ts
587
+ var commandFacet = Facet.defineRootFacet({
588
+ convert: (inputs) => {
178
589
  return Object.assign({}, ...inputs);
179
590
  }
180
591
  });
181
592
 
182
- // src/editor/flatten.ts
183
- function flatten(root) {
593
+ // src/facets/schema.ts
594
+ import OrderedMap from "orderedmap";
595
+ var schemaFacet = Facet.defineRootFacet({
596
+ convert: (specs) => {
597
+ var _a;
598
+ let nodes = OrderedMap.from({});
599
+ let marks = OrderedMap.from({});
600
+ let topNode = void 0;
601
+ for (const spec of specs) {
602
+ nodes = nodes.append(spec.nodes);
603
+ marks = marks.append((_a = spec.marks) != null ? _a : {});
604
+ topNode = topNode != null ? topNode : spec.topNode;
605
+ }
606
+ return { nodes, marks, topNode };
607
+ }
608
+ });
609
+ schemaFacet.isSchema = true;
610
+
611
+ // src/facets/view.ts
612
+ var viewFacet = Facet.defineRootFacet({
613
+ convert: (props) => {
614
+ return Object.assign({}, ...props);
615
+ }
616
+ });
617
+
618
+ // src/facets/flatten.ts
619
+ function flattenInputTuple(inputTuple) {
620
+ return [
621
+ ...inputTuple[0],
622
+ ...inputTuple[1],
623
+ ...inputTuple[2],
624
+ ...inputTuple[3],
625
+ ...inputTuple[4]
626
+ ];
627
+ }
628
+ function mergeInputTuple(tupleA, tupleB) {
629
+ if (!tupleA)
630
+ return tupleB;
631
+ if (!tupleB)
632
+ return tupleA;
633
+ const [a0, a1, a2, a3, a4] = tupleA;
634
+ const [b0, b1, b2, b3, b4] = tupleB;
635
+ return [
636
+ uniqPush(a0, b0),
637
+ uniqPush(a1, b1),
638
+ uniqPush(a2, b2),
639
+ uniqPush(a3, b3),
640
+ uniqPush(a4, b4)
641
+ ];
642
+ }
643
+ function removeInputTuple(tupleA, tupleB) {
644
+ if (!tupleA)
645
+ return [[], [], [], [], []];
646
+ if (!tupleB)
647
+ return tupleA;
648
+ const [a0, a1, a2, a3, a4] = tupleA;
649
+ const [b0, b1, b2, b3, b4] = tupleB;
650
+ return [
651
+ uniqRemove(a0, b0),
652
+ uniqRemove(a1, b1),
653
+ uniqRemove(a2, b2),
654
+ uniqRemove(a3, b3),
655
+ uniqRemove(a4, b4)
656
+ ];
657
+ }
658
+ function extractFacets(root) {
184
659
  var _a;
185
660
  const extensions = [root];
186
661
  const priorities = [2 /* default */];
187
662
  const facets = [];
188
- const inputs = [];
663
+ const payloads = [];
189
664
  while (extensions.length > 0) {
190
665
  const ext = extensions.pop();
191
666
  const pri = priorities.pop();
192
- if (ext instanceof FacetExtension) {
667
+ if (ext instanceof FacetExtensionImpl) {
193
668
  const facet = ext.facet;
194
669
  if (!facets[facet.index]) {
195
670
  facets[facet.index] = facet;
196
- inputs[facet.index] = [[], [], [], [], []];
671
+ payloads[facet.index] = [[], [], [], [], []];
197
672
  }
198
- const facetInputs = ext.inputs;
199
- inputs[facet.index][pri].push(...facetInputs);
673
+ const facetPayloads = ext.payloads;
674
+ payloads[facet.index][pri].push(...facetPayloads);
200
675
  } else if (ext.extension) {
201
676
  const p = (_a = ext.priority) != null ? _a : pri;
202
677
  if (Array.isArray(ext.extension)) {
@@ -209,103 +684,371 @@ function flatten(root) {
209
684
  priorities.push(p);
210
685
  }
211
686
  } else {
212
- throw new Error("Invalid extension");
687
+ throw new ProseKitError("Invalid extension");
213
688
  }
214
689
  }
690
+ return [facets, payloads];
691
+ }
692
+ function updateExtension(prevInputs, prevConverters, extension, mode) {
693
+ var _a;
694
+ const modifyInputTuple = mode === "add" ? mergeInputTuple : removeInputTuple;
695
+ const [facets, inputs] = extractFacets(extension);
215
696
  let schemaInput = null;
216
697
  let stateInput = null;
217
698
  let viewInput = null;
218
699
  let commandInput = null;
219
- const sortedFacets = sortFacets(facets);
220
- for (const facet of sortedFacets) {
700
+ for (let index = getFacetCount(); index >= 0; index--) {
701
+ const facet = facets[index];
702
+ if (!facet) {
703
+ continue;
704
+ }
221
705
  const nextFacet = facet.next;
222
706
  if (nextFacet) {
707
+ facets[_a = nextFacet.index] || (facets[_a] = nextFacet);
708
+ }
709
+ if (!inputs[facet.index]) {
710
+ continue;
711
+ }
712
+ const inputTuple = modifyInputTuple(prevInputs[index], inputs[index]);
713
+ prevInputs[index] = inputTuple;
714
+ if (facet.next && !facet.singleton) {
715
+ let hasOutput = false;
716
+ const outputTuple = [[], [], [], [], []];
223
717
  for (let pri = 0; pri < 5; pri++) {
224
- const input = inputs[facet.index][pri];
225
- if (input.length > 0) {
226
- const output = facet.combine(input);
227
- if (!inputs[nextFacet.index]) {
228
- inputs[nextFacet.index] = [[], [], [], [], []];
229
- }
230
- inputs[nextFacet.index][pri].push(output);
718
+ const inputArray = inputTuple[pri];
719
+ if (inputArray.length === 0) {
720
+ continue;
721
+ }
722
+ const converterTuple = prevConverters[index] || (prevConverters[index] = [
723
+ void 0,
724
+ void 0,
725
+ void 0,
726
+ void 0,
727
+ void 0
728
+ ]);
729
+ const prevConverter = converterTuple[pri];
730
+ const converter = prevConverter || facet.converter();
731
+ prevConverters[index][pri] = converter;
732
+ const output = prevConverter ? converter.update(inputArray) : converter.create(inputArray);
733
+ if (!output) {
734
+ continue;
231
735
  }
736
+ hasOutput = true;
737
+ outputTuple[pri].push(output);
232
738
  }
233
- } else if (inputs[facet.index]) {
234
- const [i1, i2, i3, i4, i5] = inputs[facet.index];
235
- const jointInputs = [...i1, ...i2, ...i3, ...i4, ...i5];
236
- const output = facet.combine(jointInputs);
237
- switch (facet) {
238
- case schemaSlot:
239
- schemaInput = output;
240
- break;
241
- case stateSlot:
242
- stateInput = output;
243
- break;
244
- case viewSlot:
245
- viewInput = output;
246
- break;
247
- case commandSlot:
248
- commandInput = output;
249
- break;
250
- default:
251
- throw new Error("Invalid facet");
739
+ if (!hasOutput) {
740
+ continue;
741
+ }
742
+ inputs[facet.next.index] = modifyInputTuple(
743
+ inputs[facet.next.index],
744
+ outputTuple
745
+ );
746
+ continue;
747
+ } else {
748
+ const inputArray = flattenInputTuple(inputTuple);
749
+ prevConverters[index] || (prevConverters[index] = [
750
+ void 0,
751
+ void 0,
752
+ void 0,
753
+ void 0,
754
+ void 0
755
+ ]);
756
+ const prevConverter = prevConverters[index][2 /* default */];
757
+ const converter = prevConverter || facet.converter();
758
+ prevConverters[index][2 /* default */] = converter;
759
+ const output = prevConverter ? converter.update(inputArray) : converter.create(inputArray);
760
+ if (!output) {
761
+ continue;
762
+ }
763
+ if (facet.next) {
764
+ const outputTuple = [[], [], [output], [], []];
765
+ inputs[facet.next.index] = modifyInputTuple(
766
+ inputs[facet.next.index],
767
+ outputTuple
768
+ );
769
+ } else {
770
+ switch (facet) {
771
+ case schemaFacet:
772
+ schemaInput = output;
773
+ break;
774
+ case stateFacet:
775
+ stateInput = output;
776
+ break;
777
+ case viewFacet:
778
+ viewInput = output;
779
+ break;
780
+ case commandFacet:
781
+ commandInput = output;
782
+ break;
783
+ default:
784
+ throw new ProseKitError("Invalid root facet");
785
+ }
252
786
  }
253
787
  }
254
788
  }
255
789
  return { schemaInput, stateInput, viewInput, commandInput };
256
790
  }
257
791
 
258
- // src/editor/editor.ts
259
- function createEditor({
260
- extension
261
- }) {
262
- const { schemaInput, stateInput, viewInput, commandInput } = flatten(extension);
263
- if (!schemaInput) {
264
- throw new Error("Schema must be defined");
792
+ // src/editor/builder.ts
793
+ import "@prosekit/pm/model";
794
+
795
+ // src/utils/is-mark-active.ts
796
+ function isMarkActive(state, type, attrs) {
797
+ const { from, $from, to, empty } = state.selection;
798
+ const markType = getMarkType(state.schema, type);
799
+ if (empty) {
800
+ const mark = attrs ? markType.create(attrs) : markType;
801
+ return !!mark.isInSet(state.storedMarks || $from.marks());
802
+ } else {
803
+ const markOrType = attrs ? markType.create(attrs) : markType;
804
+ return state.doc.rangeHasMark(from, to, markOrType);
805
+ }
806
+ }
807
+
808
+ // src/utils/type-assertion.ts
809
+ import { Mark, ProseMirrorNode } from "@prosekit/pm/model";
810
+ import {
811
+ AllSelection,
812
+ NodeSelection,
813
+ TextSelection as TextSelection4
814
+ } from "@prosekit/pm/state";
815
+ function isProseMirrorNode(node) {
816
+ return node instanceof ProseMirrorNode;
817
+ }
818
+ function isMark(mark) {
819
+ return mark instanceof Mark;
820
+ }
821
+ function isTextSelection(sel) {
822
+ return sel instanceof TextSelection4;
823
+ }
824
+ function isNodeSelection(sel) {
825
+ return sel instanceof NodeSelection;
826
+ }
827
+ function isAllSelection(sel) {
828
+ return sel instanceof AllSelection;
829
+ }
830
+
831
+ // src/editor/builder.ts
832
+ function createNodeBuilder(getState, type) {
833
+ const builder = (...args) => buildNode(type, args);
834
+ builder.isActive = (attrs) => {
835
+ const state = getState();
836
+ return state ? isNodeActive(state, type, attrs) : false;
837
+ };
838
+ return builder;
839
+ }
840
+ function createMarkBuilder(getState, type) {
841
+ const builder = (...args) => buildMark(type, args);
842
+ builder.isActive = (attrs) => {
843
+ const state = getState();
844
+ return state ? isMarkActive(state, type, attrs) : false;
845
+ };
846
+ return builder;
847
+ }
848
+ function buildMark(type, args) {
849
+ const [attrs, children] = normalizeArgs(args);
850
+ return flattenChildren(type.schema, children, type.create(attrs));
851
+ }
852
+ function buildNode(type, args) {
853
+ const [attrs, children] = normalizeArgs(args);
854
+ const node = type.createAndFill(attrs, flattenChildren(type.schema, children));
855
+ if (!node) {
856
+ throw new ProseKitError(`Couldn't create node ${type.name}`);
857
+ }
858
+ return node;
859
+ }
860
+ function flattenChildren(schema, children, mark) {
861
+ const nodes = [];
862
+ for (const child of children) {
863
+ if (typeof child === "string") {
864
+ if (child) {
865
+ nodes.push(schema.text(child, mark ? [mark] : null));
866
+ }
867
+ } else if (Array.isArray(child)) {
868
+ nodes.push(...flattenChildren(schema, child, mark));
869
+ } else if (isProseMirrorNode(child)) {
870
+ nodes.push(mark ? child.mark(mark.addToSet(child.marks)) : child);
871
+ } else {
872
+ throw new ProseKitError(`Invalid node child: ${typeof child}`);
873
+ }
874
+ }
875
+ return nodes;
876
+ }
877
+ function normalizeArgs(args) {
878
+ const [attrs, ...children] = args;
879
+ if (isNodeChild(attrs)) {
880
+ children.unshift(attrs);
881
+ return [null, children];
882
+ } else if (typeof attrs === "object") {
883
+ return [attrs, children];
884
+ } else {
885
+ return [null, children];
886
+ }
887
+ }
888
+ function isNodeChild(value) {
889
+ if (!value) {
890
+ return false;
891
+ }
892
+ return typeof value === "string" || Array.isArray(value) || isProseMirrorNode(value);
893
+ }
894
+
895
+ // src/facets/union-extension.ts
896
+ import { Schema as Schema5 } from "@prosekit/pm/model";
897
+ var UnionExtensionImpl = class extends BaseExtension {
898
+ constructor(extension = []) {
899
+ super();
900
+ this.extension = extension;
901
+ this._schema = void 0;
902
+ this.hasSchemaCount = 0;
903
+ for (const e of extension) {
904
+ if (e instanceof BaseExtension) {
905
+ this.hasSchemaCount += e.hasSchema ? 1 : 0;
906
+ } else {
907
+ throw new ProseKitError("Invalid extension");
908
+ }
909
+ }
265
910
  }
266
- const schema = new Schema(schemaInput);
267
- const stateConfig = stateInput ? stateInput({ schema }) : { schema };
268
- const state = EditorState.create(stateConfig);
269
- const directEditorProps = { state, ...viewInput };
270
- const instance = new EditorInstance(directEditorProps);
271
- if (commandInput) {
272
- for (const [name, commandCreator] of Object.entries(commandInput)) {
273
- instance.addCommand(name, commandCreator);
911
+ get hasSchema() {
912
+ return this.hasSchemaCount > 0;
913
+ }
914
+ get schema() {
915
+ var _a;
916
+ if (this._schema !== void 0) {
917
+ return this._schema;
918
+ }
919
+ if (this.hasSchemaCount === 0) {
920
+ this._schema = null;
921
+ return this._schema;
922
+ }
923
+ if (this.hasSchemaCount === 1) {
924
+ const schema = (_a = this.extension.find((e) => e.hasSchema)) == null ? void 0 : _a.schema;
925
+ if (schema) {
926
+ this._schema = schema;
927
+ return this._schema;
928
+ }
274
929
  }
930
+ const { schemaInput } = updateExtension([], [], this, "add");
931
+ this._schema = schemaInput ? new Schema5(schemaInput) : null;
932
+ return this._schema;
275
933
  }
276
- return Editor.create(instance);
934
+ };
935
+
936
+ // src/editor/union.ts
937
+ function union(extension) {
938
+ const array = Array.isArray(extension) ? extension : [extension];
939
+ return new UnionExtensionImpl(
940
+ array
941
+ );
942
+ }
943
+
944
+ // src/editor/editor.ts
945
+ function createEditor(options) {
946
+ const { defaultDoc, defaultHTML, defaultSelection } = options;
947
+ let extension = options.extension;
948
+ if (defaultDoc || defaultHTML) {
949
+ extension = union([
950
+ extension,
951
+ defineDefaultState({
952
+ defaultDoc,
953
+ defaultHTML,
954
+ defaultSelection
955
+ })
956
+ ]);
957
+ }
958
+ return Editor.create(new EditorInstance(extension));
277
959
  }
278
960
  var EditorInstance = class {
279
- constructor(directEditorProps) {
280
- this.directEditorProps = directEditorProps;
961
+ constructor(extension) {
281
962
  this.view = null;
282
- this.commandDispatchers = {};
963
+ this.commandAppliers = {};
964
+ this.payloads = [];
965
+ this.converters = [];
283
966
  this.mount = this.mount.bind(this);
284
967
  this.unmount = this.unmount.bind(this);
285
- this.schema = directEditorProps.state.schema;
968
+ const { schemaInput, stateInput, viewInput, commandInput } = updateExtension(this.payloads, this.converters, extension, "add");
969
+ if (!schemaInput) {
970
+ throw new ProseKitError("Schema must be defined");
971
+ }
972
+ const schema = new Schema6(schemaInput);
973
+ const stateConfig = stateInput ? stateInput({ schema }) : { schema };
974
+ const state = EditorState2.create(stateConfig);
975
+ this.cachedState = state;
976
+ if (commandInput) {
977
+ for (const [name, commandCreator] of Object.entries(commandInput)) {
978
+ this.defineCommand(name, commandCreator);
979
+ }
980
+ }
981
+ this.directEditorProps = { state, ...viewInput };
982
+ this.schema = this.directEditorProps.state.schema;
983
+ const getState = () => this.getState();
984
+ this.nodeBuilders = Object.fromEntries(
985
+ Object.values(this.schema.nodes).map((type) => [
986
+ type.name,
987
+ createNodeBuilder(getState, type)
988
+ ])
989
+ );
990
+ this.markBuilders = Object.fromEntries(
991
+ Object.values(this.schema.marks).map((type) => [
992
+ type.name,
993
+ createMarkBuilder(getState, type)
994
+ ])
995
+ );
996
+ }
997
+ getState() {
998
+ if (this.view) {
999
+ this.cachedState = this.view.state;
1000
+ }
1001
+ return this.cachedState;
1002
+ }
1003
+ updateExtension(extension, mode) {
1004
+ var _a;
1005
+ const { schemaInput, stateInput, viewInput, commandInput } = updateExtension(this.payloads, this.converters, extension, mode);
1006
+ if (schemaInput) {
1007
+ throw new ProseKitError("Schema cannot be changed");
1008
+ }
1009
+ if (viewInput) {
1010
+ throw new ProseKitError("View cannot be changed");
1011
+ }
1012
+ const plugins = (_a = stateInput == null ? void 0 : stateInput({ schema: this.schema })) == null ? void 0 : _a.plugins;
1013
+ if (plugins && plugins.length > 0) {
1014
+ if (!this.view) {
1015
+ throw new ProseKitError(
1016
+ "Unexpected inner state: EditorInstance.view is not defined"
1017
+ );
1018
+ }
1019
+ const state = this.view.state.reconfigure({ plugins });
1020
+ this.view.updateState(state);
1021
+ }
1022
+ if (commandInput) {
1023
+ const names = Object.keys(commandInput);
1024
+ for (const name of names) {
1025
+ this.defineCommand(name, commandInput[name]);
1026
+ }
1027
+ }
286
1028
  }
287
1029
  mount(place) {
288
1030
  if (this.view) {
289
- throw new Error("Editor is already mounted");
1031
+ throw new ProseKitError("Editor is already mounted");
290
1032
  }
291
1033
  if (!place) {
292
- throw new Error("Can't mount editor without a place");
1034
+ throw new ProseKitError("Can't mount editor without a place");
293
1035
  }
294
1036
  this.view = new EditorView({ mount: place }, this.directEditorProps);
295
1037
  }
296
1038
  unmount() {
297
1039
  if (!this.view) {
298
- throw new Error("Editor is not mounted yet");
1040
+ throw new ProseKitError("Editor is not mounted yet");
299
1041
  }
300
1042
  this.view.destroy();
301
1043
  this.view = null;
302
1044
  }
303
1045
  get assertView() {
304
- if (!this.view)
305
- throw new Error("Editor is not mounted");
1046
+ if (!this.view) {
1047
+ throw new ProseKitError("Editor is not mounted");
1048
+ }
306
1049
  return this.view;
307
1050
  }
308
- addPlugins(plugins) {
1051
+ definePlugins(plugins) {
309
1052
  const view = this.assertView;
310
1053
  const state = view.state;
311
1054
  const newPlugins = [...plugins, ...state.plugins];
@@ -321,16 +1064,27 @@ var EditorInstance = class {
321
1064
  const newState = state.reconfigure({ plugins: newPlugins });
322
1065
  view.setProps({ state: newState });
323
1066
  }
324
- addCommand(name, commandCreator) {
325
- const dispatcher = (...args) => {
326
- const view = this.assertView;
1067
+ defineCommand(name, commandCreator) {
1068
+ const applier = (...args) => {
1069
+ const view = this.view;
1070
+ if (!view) {
1071
+ return false;
1072
+ }
327
1073
  const command = commandCreator(...args);
328
1074
  return command(view.state, view.dispatch.bind(view), view);
329
1075
  };
330
- this.commandDispatchers[name] = dispatcher;
1076
+ applier.canApply = (...args) => {
1077
+ const view = this.view;
1078
+ if (!view) {
1079
+ return false;
1080
+ }
1081
+ const command = commandCreator(...args);
1082
+ return command(view.state, void 0, view);
1083
+ };
1084
+ this.commandAppliers[name] = applier;
331
1085
  }
332
1086
  removeCommand(name) {
333
- delete this.commandDispatchers[name];
1087
+ delete this.commandAppliers[name];
334
1088
  }
335
1089
  };
336
1090
  var Editor = class _Editor {
@@ -341,25 +1095,47 @@ var Editor = class _Editor {
341
1095
  this.unmount = this.unmount.bind(this);
342
1096
  this.use = this.use.bind(this);
343
1097
  }
344
- /** @internal */
1098
+ /**
1099
+ * @internal
1100
+ */
345
1101
  static create(instance) {
346
1102
  if (!(instance instanceof EditorInstance)) {
347
- throw new TypeError("Editor's instance is not EditorInstance");
1103
+ throw new TypeError("Invalid EditorInstance");
348
1104
  }
349
1105
  return new _Editor(instance);
350
1106
  }
1107
+ /**
1108
+ * Whether the editor is mounted.
1109
+ */
351
1110
  get mounted() {
352
1111
  return !!this.instance.view;
353
1112
  }
1113
+ /**
1114
+ * The editor view.
1115
+ */
354
1116
  get view() {
355
1117
  return this.instance.assertView;
356
1118
  }
1119
+ /**
1120
+ * The editor schema.
1121
+ */
357
1122
  get schema() {
358
1123
  return this.instance.schema;
359
1124
  }
360
1125
  get commands() {
361
- return this.instance.commandDispatchers;
1126
+ return this.instance.commandAppliers;
362
1127
  }
1128
+ /**
1129
+ * Whether the editor is focused.
1130
+ */
1131
+ get focused() {
1132
+ var _a, _b;
1133
+ return (_b = (_a = this.instance.view) == null ? void 0 : _a.hasFocus()) != null ? _b : false;
1134
+ }
1135
+ /**
1136
+ * Mount the editor to the given HTML element.
1137
+ * Pass `null` or `undefined` to unmount the editor.
1138
+ */
363
1139
  mount(place) {
364
1140
  if (!place) {
365
1141
  return this.unmount();
@@ -367,11 +1143,28 @@ var Editor = class _Editor {
367
1143
  this.instance.mount(place);
368
1144
  this.afterMounted.forEach((callback) => callback());
369
1145
  }
1146
+ /**
1147
+ * Unmount the editor. This is equivalent to `mount(null)`.
1148
+ */
370
1149
  unmount() {
371
1150
  if (this.mounted) {
372
1151
  this.instance.unmount();
373
1152
  }
374
1153
  }
1154
+ /**
1155
+ * Focus the editor.
1156
+ */
1157
+ focus() {
1158
+ var _a;
1159
+ (_a = this.instance.view) == null ? void 0 : _a.focus();
1160
+ }
1161
+ /**
1162
+ * Blur the editor.
1163
+ */
1164
+ blur() {
1165
+ var _a;
1166
+ (_a = this.instance.view) == null ? void 0 : _a.dom.blur();
1167
+ }
375
1168
  use(extension) {
376
1169
  if (!this.mounted) {
377
1170
  let lazyRemove = null;
@@ -383,218 +1176,563 @@ var Editor = class _Editor {
383
1176
  lazyRemove == null ? void 0 : lazyRemove();
384
1177
  };
385
1178
  }
386
- const { schemaInput, stateInput, viewInput, commandInput } = flatten(extension);
387
- if (schemaInput) {
388
- throw new ProseKitError("Schema cannot be changed");
389
- }
390
- if (viewInput) {
391
- throw new ProseKitError("View cannot be changed");
392
- }
393
- if (stateInput) {
394
- const stateConfig = stateInput({ schema: this.schema });
395
- const plugins = stateConfig.plugins;
396
- if (plugins && plugins.length > 0) {
397
- this.instance.addPlugins(plugins);
398
- return () => this.instance.removePlugins(plugins);
399
- }
400
- }
401
- if (commandInput) {
402
- const names = Object.keys(commandInput);
403
- for (const name of names) {
404
- this.instance.addCommand(name, commandInput[name]);
405
- }
406
- return () => {
407
- for (const name of names) {
408
- this.instance.removeCommand(name);
409
- }
410
- };
411
- }
412
- return voidFunction;
1179
+ this.instance.updateExtension(extension, "add");
1180
+ return () => this.instance.updateExtension(extension, "remove");
413
1181
  }
414
- };
415
-
416
- // src/editor/type-utils.ts
417
- function defineExtension(extension) {
418
- if (extension && Array.isArray(extension)) {
419
- return { extension };
1182
+ get state() {
1183
+ return this.instance.getState();
420
1184
  }
421
- return extension;
422
- }
1185
+ get nodes() {
1186
+ return this.instance.nodeBuilders;
1187
+ }
1188
+ get marks() {
1189
+ return this.instance.markBuilders;
1190
+ }
1191
+ };
423
1192
 
424
1193
  // src/editor/with-priority.ts
425
1194
  function withPriority(extension, priority) {
426
- return { extension, priority };
1195
+ const result = union(extension);
1196
+ result.priority = priority;
1197
+ return result;
427
1198
  }
428
1199
 
429
- // src/extensions/command.ts
430
- import { AllSelection, Selection } from "@prosekit/pm/state";
431
- import { findWrapping, insertPoint } from "@prosekit/pm/transform";
432
- function addCommands(commands) {
433
- return commandSlot.extension([commands]);
434
- }
435
- function addBaseCommands() {
436
- return addCommands({
437
- insertText: ({
438
- text,
439
- from,
440
- to
441
- }) => {
442
- return (state, dispatch) => {
443
- if (text) {
444
- dispatch == null ? void 0 : dispatch(state.tr.insertText(text, from, to));
445
- }
446
- return true;
447
- };
448
- },
449
- insertNode: ({ node, pos }) => {
450
- return (state, dispatch) => {
451
- const insertPos = insertPoint(
452
- state.doc,
453
- pos != null ? pos : state.selection.to,
454
- node.type
455
- );
456
- if (insertPos == null)
457
- return false;
458
- if (dispatch) {
459
- const tr = state.tr.insert(insertPos, node);
460
- const $pos = tr.doc.resolve(insertPos);
461
- tr.setSelection(Selection.near($pos));
462
- dispatch(tr);
463
- }
464
- return true;
465
- };
466
- },
467
- wrap: ({
468
- nodeType,
469
- attrs
470
- }) => {
471
- return (state, dispatch) => {
472
- const { $from, $to } = state.selection;
473
- const range = $from.blockRange($to);
474
- if (!range)
475
- return false;
476
- const wrapping = findWrapping(range, nodeType, attrs);
477
- if (!wrapping)
478
- return false;
479
- dispatch == null ? void 0 : dispatch(state.tr.wrap(range, wrapping));
480
- return true;
481
- };
482
- },
483
- setBlockType: ({
484
- nodeType,
485
- attrs,
486
- from,
487
- to
488
- }) => {
489
- return (state, dispatch) => {
490
- from = from != null ? from : state.selection.from;
491
- to = from != null ? from : state.selection.from;
492
- dispatch == null ? void 0 : dispatch(state.tr.setBlockType(from, to, nodeType, attrs));
493
- return true;
494
- };
495
- },
496
- selectAll: () => {
497
- return (state, dispatch) => {
498
- dispatch == null ? void 0 : dispatch(state.tr.setSelection(new AllSelection(state.doc)));
499
- return true;
500
- };
1200
+ // src/commands/insert-text.ts
1201
+ function insertText({
1202
+ text,
1203
+ from,
1204
+ to
1205
+ }) {
1206
+ return (state, dispatch) => {
1207
+ if (text) {
1208
+ dispatch == null ? void 0 : dispatch(state.tr.insertText(text, from, to));
501
1209
  }
1210
+ return true;
1211
+ };
1212
+ }
1213
+
1214
+ // src/commands/select-all.ts
1215
+ import { AllSelection as AllSelection2 } from "@prosekit/pm/state";
1216
+ function selectAll() {
1217
+ return (state, dispatch) => {
1218
+ dispatch == null ? void 0 : dispatch(state.tr.setSelection(new AllSelection2(state.doc)));
1219
+ return true;
1220
+ };
1221
+ }
1222
+
1223
+ // src/commands/wrap.ts
1224
+ import "@prosekit/pm/model";
1225
+ import "@prosekit/pm/state";
1226
+ import { findWrapping } from "@prosekit/pm/transform";
1227
+ function wrap({
1228
+ nodeType,
1229
+ attrs
1230
+ }) {
1231
+ return (state, dispatch) => {
1232
+ const { $from, $to } = state.selection;
1233
+ const range = $from.blockRange($to);
1234
+ if (!range)
1235
+ return false;
1236
+ const wrapping = findWrapping(range, nodeType, attrs);
1237
+ if (!wrapping)
1238
+ return false;
1239
+ dispatch == null ? void 0 : dispatch(state.tr.wrap(range, wrapping));
1240
+ return true;
1241
+ };
1242
+ }
1243
+
1244
+ // src/extensions/command.ts
1245
+ function defineCommands(commands) {
1246
+ return commandFacet.extension([commands]);
1247
+ }
1248
+ function defineBaseCommands() {
1249
+ return defineCommands({
1250
+ insertText,
1251
+ insertNode,
1252
+ wrap,
1253
+ setBlockType,
1254
+ setNodeAttrs,
1255
+ selectAll,
1256
+ addMark,
1257
+ removeMark
502
1258
  });
503
1259
  }
504
1260
 
1261
+ // src/utils/is-element.ts
1262
+ var hasElement = typeof Element !== "undefined";
1263
+ function isElement(value) {
1264
+ return hasElement && value instanceof Element;
1265
+ }
1266
+
1267
+ // src/utils/is-not-null.ts
1268
+ function isNotNull(value) {
1269
+ return value != null;
1270
+ }
1271
+
505
1272
  // src/extensions/node-spec.ts
506
- function addNodeSpec(options) {
507
- return nodeSpecFacet.extension([options]);
1273
+ function defineNodeSpec(options) {
1274
+ const payload = [options, void 0];
1275
+ return nodeSpecFacet.extension([payload]);
1276
+ }
1277
+ function defineNodeAttr(options) {
1278
+ const payload = [void 0, options];
1279
+ return nodeSpecFacet.extension([payload]);
508
1280
  }
509
1281
  var nodeSpecFacet = Facet.define({
510
- combine: (options) => {
1282
+ convert: (payloads) => {
511
1283
  const nodes = {};
512
- let topNode = void 0;
513
- for (const { name, spec, topNode: isTopNode } of options) {
1284
+ let topNodeName = void 0;
1285
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
1286
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNull);
1287
+ for (const { name, topNode, ...spec } of specPayloads) {
514
1288
  if (nodes[name]) {
515
- throw new Error(`Node type ${name} has already been defined`);
1289
+ throw new ProseKitError(`Node type ${name} has already been defined`);
1290
+ }
1291
+ if (topNode) {
1292
+ topNodeName = name;
516
1293
  }
517
1294
  nodes[name] = spec;
518
- if (isTopNode && !topNode) {
519
- topNode = name;
1295
+ }
1296
+ for (const {
1297
+ type,
1298
+ attr,
1299
+ default: defaultValue,
1300
+ toDOM,
1301
+ parseDOM
1302
+ } of attrPayloads) {
1303
+ const spec = nodes[type];
1304
+ if (!spec) {
1305
+ throw new ProseKitError(
1306
+ `Node type ${type} must be defined before defining attributes`
1307
+ );
1308
+ }
1309
+ if (!spec.attrs) {
1310
+ spec.attrs = {};
1311
+ }
1312
+ spec.attrs[attr] = { default: defaultValue };
1313
+ if (toDOM && spec.toDOM) {
1314
+ const existingToDom = spec.toDOM;
1315
+ spec.toDOM = (node) => {
1316
+ const dom = existingToDom(node);
1317
+ if (!dom) {
1318
+ return dom;
1319
+ }
1320
+ const attrDOM = toDOM(node.attrs[attr]);
1321
+ if (!attrDOM) {
1322
+ return dom;
1323
+ }
1324
+ const [key, value] = attrDOM;
1325
+ if (!key) {
1326
+ return dom;
1327
+ }
1328
+ if (Array.isArray(dom)) {
1329
+ if (typeof dom[1] === "object") {
1330
+ return [dom[0], { ...dom[1], [key]: value }, ...dom.slice(2)];
1331
+ } else {
1332
+ return [dom[0], { [key]: value }, ...dom.slice(1)];
1333
+ }
1334
+ } else if (isElement(dom)) {
1335
+ dom.setAttribute(key, value);
1336
+ } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
1337
+ dom.dom.setAttribute(key, value);
1338
+ }
1339
+ return dom;
1340
+ };
1341
+ }
1342
+ if (parseDOM && spec.parseDOM) {
1343
+ for (const rule of spec.parseDOM) {
1344
+ const existingGetAttrs = rule.getAttrs;
1345
+ const existingAttrs = rule.attrs;
1346
+ rule.getAttrs = (dom) => {
1347
+ var _a;
1348
+ const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
1349
+ if (attrs === false || !dom || !isElement(dom)) {
1350
+ return attrs != null ? attrs : null;
1351
+ }
1352
+ const value = parseDOM(dom);
1353
+ return {
1354
+ ...attrs,
1355
+ [attr]: value
1356
+ };
1357
+ };
1358
+ }
520
1359
  }
521
1360
  }
522
- return { nodes, topNode };
1361
+ return { nodes, topNode: topNodeName };
523
1362
  },
524
- next: schemaSlot
1363
+ next: schemaFacet,
1364
+ singleton: true
525
1365
  });
526
1366
 
527
1367
  // src/extensions/doc.ts
528
- function addDoc() {
529
- return addNodeSpec({
1368
+ function defineDoc() {
1369
+ return defineNodeSpec({
530
1370
  name: "doc",
531
- spec: {
532
- content: "block+"
533
- }
1371
+ content: "block+",
1372
+ topNode: true
534
1373
  });
535
1374
  }
536
1375
 
537
- // src/extensions/input-rules.ts
538
- import { inputRules } from "@prosekit/pm/inputrules";
1376
+ // src/extensions/events/plugin-view.ts
1377
+ import { PluginKey, ProseMirrorPlugin } from "@prosekit/pm/state";
539
1378
 
540
1379
  // src/extensions/plugin.ts
541
- function addPlugin({ plugins }) {
542
- if (typeof plugins === "function") {
543
- return pluginFacet.extension([plugins]);
544
- } else if (Array.isArray(plugins)) {
545
- return pluginFacet.extension([() => plugins]);
546
- } else {
547
- throw new TypeError("plugins must be a function or an array");
1380
+ import "@prosekit/pm/model";
1381
+ import { Plugin as Plugin2 } from "@prosekit/pm/state";
1382
+ function definePlugin(plugin) {
1383
+ if (plugin instanceof Plugin2) {
1384
+ return pluginFacet.extension([() => [plugin]]);
1385
+ }
1386
+ if (Array.isArray(plugin) && plugin.every((p) => p instanceof Plugin2)) {
1387
+ return pluginFacet.extension([() => plugin]);
1388
+ }
1389
+ if (typeof plugin === "function") {
1390
+ return pluginFacet.extension([plugin]);
548
1391
  }
1392
+ throw new TypeError("Invalid plugin");
549
1393
  }
550
1394
  var pluginFacet = Facet.define({
551
- combine: (callbacks) => {
552
- return ({ schema }) => {
553
- const plugins = callbacks.flatMap((func) => func({ schema }));
1395
+ converter: () => {
1396
+ let inputs = [];
1397
+ const output = ({ schema }) => {
1398
+ const plugins = inputs.flatMap((func) => func({ schema }));
554
1399
  return { plugins };
555
1400
  };
1401
+ return {
1402
+ create: (payloads) => {
1403
+ inputs = payloads;
1404
+ return output;
1405
+ },
1406
+ update: (payloads) => {
1407
+ inputs = payloads;
1408
+ return output;
1409
+ }
1410
+ };
556
1411
  },
557
- next: stateSlot
1412
+ next: stateFacet
558
1413
  });
559
1414
 
560
- // src/extensions/input-rules.ts
561
- function addInputRule(rules) {
562
- return inputRuleFacet.extension([rules]);
1415
+ // src/extensions/events/plugin-view.ts
1416
+ function defineMountHandler(handler) {
1417
+ return pluginViewFacet.extension([["mount", handler]]);
1418
+ }
1419
+ function defineUpdateHandler(handler) {
1420
+ return pluginViewFacet.extension([["update", handler]]);
1421
+ }
1422
+ function defineUnmountHandler(handler) {
1423
+ return pluginViewFacet.extension([["unmount", handler]]);
563
1424
  }
564
- var inputRuleFacet = Facet.define({
565
- combine: (inputs) => {
566
- return (context) => {
567
- const rules = inputs.flatMap((callback) => callback(context));
568
- return [inputRules({ rules })];
1425
+ var pluginViewFacet = Facet.define({
1426
+ converter: () => {
1427
+ let mountHandlers = [];
1428
+ let updateHandlers = [];
1429
+ let unmountHandlers = [];
1430
+ const plugin = new ProseMirrorPlugin({
1431
+ key: pluginKey,
1432
+ view: (view) => {
1433
+ mountHandlers.forEach((fn) => fn(view));
1434
+ return {
1435
+ update: (view2, prevState) => {
1436
+ updateHandlers.forEach((fn) => fn(view2, prevState));
1437
+ },
1438
+ destroy: () => {
1439
+ unmountHandlers.forEach((fn) => fn());
1440
+ }
1441
+ };
1442
+ }
1443
+ });
1444
+ const pluginFunc = () => [plugin];
1445
+ const register = (input) => {
1446
+ mountHandlers = [];
1447
+ updateHandlers = [];
1448
+ unmountHandlers = [];
1449
+ for (const args of input) {
1450
+ switch (args[0]) {
1451
+ case "mount":
1452
+ mountHandlers.push(args[1]);
1453
+ break;
1454
+ case "update":
1455
+ updateHandlers.push(args[1]);
1456
+ break;
1457
+ case "unmount":
1458
+ unmountHandlers.push(args[1]);
1459
+ break;
1460
+ }
1461
+ }
1462
+ };
1463
+ return {
1464
+ create: (input) => {
1465
+ register(input);
1466
+ return pluginFunc;
1467
+ },
1468
+ update: (input) => {
1469
+ register(input);
1470
+ return null;
1471
+ }
569
1472
  };
570
1473
  },
571
- next: pluginFacet
1474
+ next: pluginFacet,
1475
+ singleton: true
1476
+ });
1477
+ var pluginKey = new PluginKey("prosekit-plugin-view-handler");
1478
+
1479
+ // src/extensions/events/doc-change.ts
1480
+ function defineDocChangeHandler(handler) {
1481
+ return defineUpdateHandler((view, prevState) => {
1482
+ if (!view.state.doc.eq(prevState.doc)) {
1483
+ handler(view, prevState);
1484
+ }
1485
+ });
1486
+ }
1487
+
1488
+ // src/extensions/events/dom-event.ts
1489
+ import { PluginKey as PluginKey2, ProseMirrorPlugin as ProseMirrorPlugin2 } from "@prosekit/pm/state";
1490
+
1491
+ // src/utils/combine-event-handlers.ts
1492
+ function combineEventHandlers() {
1493
+ let _handlers = [];
1494
+ function setHandlers(handlers) {
1495
+ _handlers = handlers;
1496
+ }
1497
+ function combinedEventHandler(...args) {
1498
+ for (const handler of _handlers) {
1499
+ if (handler(...args)) {
1500
+ return true;
1501
+ }
1502
+ }
1503
+ return false;
1504
+ }
1505
+ return [setHandlers, combinedEventHandler];
1506
+ }
1507
+
1508
+ // src/utils/group-entries.ts
1509
+ function groupEntries(entries) {
1510
+ const map = {};
1511
+ for (const [key, value] of entries) {
1512
+ const values = map[key];
1513
+ if (!values) {
1514
+ map[key] = [value];
1515
+ } else {
1516
+ values.push(value);
1517
+ }
1518
+ }
1519
+ return map;
1520
+ }
1521
+
1522
+ // src/extensions/events/dom-event.ts
1523
+ function defineDOMEventHandler(event, handler) {
1524
+ return domEventFacet.extension([
1525
+ [event, handler]
1526
+ ]);
1527
+ }
1528
+ var domEventFacet = Facet.define({
1529
+ converter: () => {
1530
+ const setHandlersMap = {};
1531
+ const combinedHandlerMap = {};
1532
+ const update = (payloads) => {
1533
+ let hasNewEvent = false;
1534
+ for (const [event] of payloads) {
1535
+ if (!setHandlersMap[event]) {
1536
+ hasNewEvent = true;
1537
+ const [setHandlers, combinedHandler] = combineEventHandlers();
1538
+ setHandlersMap[event] = setHandlers;
1539
+ combinedHandlerMap[event] = combinedHandler;
1540
+ }
1541
+ }
1542
+ const map = groupEntries(payloads);
1543
+ for (const [event, handlers] of Object.entries(map)) {
1544
+ const setHandlers = setHandlersMap[event];
1545
+ setHandlers(handlers != null ? handlers : []);
1546
+ }
1547
+ if (hasNewEvent) {
1548
+ return new ProseMirrorPlugin2({
1549
+ key: new PluginKey2("prosekit-dom-event-handler"),
1550
+ props: { handleDOMEvents: combinedHandlerMap }
1551
+ });
1552
+ } else {
1553
+ return null;
1554
+ }
1555
+ };
1556
+ return {
1557
+ create: (payloads) => {
1558
+ const plugin = update(payloads);
1559
+ return plugin ? () => plugin : () => [];
1560
+ },
1561
+ update: (payloads) => {
1562
+ const plugin = update(payloads);
1563
+ return plugin ? () => plugin : null;
1564
+ }
1565
+ };
1566
+ },
1567
+ next: pluginFacet,
1568
+ singleton: true
572
1569
  });
573
1570
 
1571
+ // src/extensions/events/editor-event.ts
1572
+ import { PluginKey as PluginKey3, ProseMirrorPlugin as ProseMirrorPlugin3 } from "@prosekit/pm/state";
1573
+ function defineKeyDownHandler(handler) {
1574
+ return editorEventFacet.extension([["keyDown", handler]]);
1575
+ }
1576
+ function defineKeyPressHandler(handler) {
1577
+ return editorEventFacet.extension([["keyPress", handler]]);
1578
+ }
1579
+ function defineTextInputHandler(handler) {
1580
+ return editorEventFacet.extension([["textInput", handler]]);
1581
+ }
1582
+ function defineClickOnHandler(handler) {
1583
+ return editorEventFacet.extension([["clickOn", handler]]);
1584
+ }
1585
+ function defineClickHandler(handler) {
1586
+ return editorEventFacet.extension([["click", handler]]);
1587
+ }
1588
+ function defineDoubleClickOnHandler(handler) {
1589
+ return editorEventFacet.extension([["doubleClickOn", handler]]);
1590
+ }
1591
+ function defineDoubleClickHandler(handler) {
1592
+ return editorEventFacet.extension([["doubleClick", handler]]);
1593
+ }
1594
+ function defineTripleClickOnHandler(handler) {
1595
+ return editorEventFacet.extension([["tripleClickOn", handler]]);
1596
+ }
1597
+ function defineTripleClickHandler(handler) {
1598
+ return editorEventFacet.extension([["tripleClick", handler]]);
1599
+ }
1600
+ function definePasteHandler(handler) {
1601
+ return editorEventFacet.extension([["paste", handler]]);
1602
+ }
1603
+ function defineDropHandler(handler) {
1604
+ return editorEventFacet.extension([["drop", handler]]);
1605
+ }
1606
+ function defineScrollToSelectionHandler(handler) {
1607
+ return editorEventFacet.extension([["scrollToSelection", handler]]);
1608
+ }
1609
+ var editorEventFacet = Facet.define({
1610
+ converter: () => {
1611
+ const [update, plugin] = setupEditorEventPlugin();
1612
+ return {
1613
+ create: (entries) => {
1614
+ update(entries);
1615
+ return () => plugin;
1616
+ },
1617
+ update: (entries) => {
1618
+ update(entries);
1619
+ return null;
1620
+ }
1621
+ };
1622
+ },
1623
+ next: pluginFacet,
1624
+ singleton: true
1625
+ });
1626
+ function setupEditorEventPlugin() {
1627
+ const [setKeyDownHandlers, handleKeyDown] = combineEventHandlers();
1628
+ const [setKeyPressHandlers, handleKeyPress] = combineEventHandlers();
1629
+ const [setTextInputHandlers, handleTextInput] = combineEventHandlers();
1630
+ const [setClickOnHandlers, handleClickOn] = combineEventHandlers();
1631
+ const [setClickHandlers, handleClick] = combineEventHandlers();
1632
+ const [setDoubleClickOnHandlers, handleDoubleClickOn] = combineEventHandlers();
1633
+ const [setDoubleClickHandlers, handleDoubleClick] = combineEventHandlers();
1634
+ const [setTripleClickOnHandlers, handleTripleClickOn] = combineEventHandlers();
1635
+ const [setTripleClickHandlers, handleTripleClick] = combineEventHandlers();
1636
+ const [setPasteHandlers, handlePaste] = combineEventHandlers();
1637
+ const [setDropHandlers, handleDrop] = combineEventHandlers();
1638
+ const [setScrollToSelectionHandlers, handleScrollToSelection] = combineEventHandlers();
1639
+ const update = (entries) => {
1640
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1641
+ const map = groupEntries(entries);
1642
+ setKeyDownHandlers((_a = map.keyDown) != null ? _a : []);
1643
+ setKeyPressHandlers((_b = map.keyPress) != null ? _b : []);
1644
+ setTextInputHandlers((_c = map.textInput) != null ? _c : []);
1645
+ setClickOnHandlers((_d = map.clickOn) != null ? _d : []);
1646
+ setClickHandlers((_e = map.click) != null ? _e : []);
1647
+ setDoubleClickOnHandlers((_f = map.doubleClickOn) != null ? _f : []);
1648
+ setDoubleClickHandlers((_g = map.doubleClick) != null ? _g : []);
1649
+ setTripleClickOnHandlers((_h = map.tripleClickOn) != null ? _h : []);
1650
+ setTripleClickHandlers((_i = map.tripleClick) != null ? _i : []);
1651
+ setPasteHandlers((_j = map.paste) != null ? _j : []);
1652
+ setDropHandlers((_k = map.drop) != null ? _k : []);
1653
+ setScrollToSelectionHandlers((_l = map.scrollToSelection) != null ? _l : []);
1654
+ };
1655
+ const plugin = new ProseMirrorPlugin3({
1656
+ key: new PluginKey3("prosekit-editor-handler"),
1657
+ props: {
1658
+ handleKeyDown,
1659
+ handleKeyPress,
1660
+ handleTextInput,
1661
+ handleClickOn,
1662
+ handleClick,
1663
+ handleDoubleClickOn,
1664
+ handleDoubleClick,
1665
+ handleTripleClickOn,
1666
+ handleTripleClick,
1667
+ handlePaste,
1668
+ handleDrop,
1669
+ handleScrollToSelection
1670
+ }
1671
+ });
1672
+ return [update, plugin];
1673
+ }
1674
+
1675
+ // src/extensions/events/focus.ts
1676
+ function defineFocusChangeHandler(handler) {
1677
+ const handleFocus = () => handler(true);
1678
+ const handleBlur = () => handler(false);
1679
+ return domEventFacet.extension([
1680
+ ["focus", handleFocus],
1681
+ ["blur", handleBlur]
1682
+ ]);
1683
+ }
1684
+
1685
+ // src/extensions/history.ts
1686
+ import { history, redo, undo } from "@prosekit/pm/history";
1687
+
1688
+ // src/utils/env.ts
1689
+ var isMac = typeof navigator !== "undefined" ? /Mac|iP(hone|[ao]d)/.test(navigator.platform) : false;
1690
+
574
1691
  // src/extensions/keymap.ts
575
1692
  import { baseKeymap, chainCommands } from "@prosekit/pm/commands";
576
- import { keymap as createKeymapPlugin } from "@prosekit/pm/keymap";
577
- function addKeymap(keymap) {
1693
+ import { keydownHandler } from "@prosekit/pm/keymap";
1694
+ import { Plugin as Plugin3, PluginKey as PluginKey4 } from "@prosekit/pm/state";
1695
+ function defineKeymap(keymap) {
578
1696
  return keymapFacet.extension([keymap]);
579
1697
  }
580
- function addBaseKeymap() {
581
- return addKeymap(baseKeymap);
1698
+ function defineBaseKeymap(options) {
1699
+ var _a;
1700
+ const priority = (_a = options == null ? void 0 : options.priority) != null ? _a : 3 /* low */;
1701
+ return withPriority(defineKeymap(baseKeymap), priority);
582
1702
  }
583
1703
  var keymapFacet = Facet.define({
584
- combine: (keymaps) => {
585
- const keymap = mergeKeymaps(keymaps);
586
- const plugin = createKeymapPlugin(keymap);
587
- return () => [plugin];
1704
+ converter: () => {
1705
+ let handler = null;
1706
+ const handlerWrapper = (view, event) => {
1707
+ if (handler)
1708
+ return handler(view, event);
1709
+ return false;
1710
+ };
1711
+ const plugin = new Plugin3({
1712
+ key: keymapPluginKey,
1713
+ props: { handleKeyDown: handlerWrapper }
1714
+ });
1715
+ const pluginFunc = () => [plugin];
1716
+ return {
1717
+ create: (keymaps) => {
1718
+ handler = keydownHandler(mergeKeymaps(keymaps));
1719
+ return pluginFunc;
1720
+ },
1721
+ update: (keymaps) => {
1722
+ handler = keydownHandler(mergeKeymaps(keymaps));
1723
+ return null;
1724
+ }
1725
+ };
588
1726
  },
589
- next: pluginFacet
1727
+ next: pluginFacet,
1728
+ singleton: true
590
1729
  });
591
1730
  function mergeKeymaps(keymaps) {
592
1731
  const bindings = {};
593
1732
  for (const keymap of keymaps) {
594
1733
  for (const [key, command] of Object.entries(keymap)) {
595
- if (!bindings[key])
596
- bindings[key] = [];
597
- bindings[key].push(command);
1734
+ const commands = bindings[key] || (bindings[key] = []);
1735
+ commands.push(command);
598
1736
  }
599
1737
  }
600
1738
  return Object.fromEntries(
@@ -604,101 +1742,311 @@ function mergeKeymaps(keymaps) {
604
1742
  ])
605
1743
  );
606
1744
  }
1745
+ var keymapPluginKey = new PluginKey4("prosekit-keymap");
1746
+
1747
+ // src/extensions/history.ts
1748
+ function defineHistory() {
1749
+ const keymap = {
1750
+ "Mod-z": undo,
1751
+ "Shift-Mod-z": redo
1752
+ };
1753
+ if (!isMac) {
1754
+ keymap["Mod-y"] = redo;
1755
+ }
1756
+ return union([
1757
+ definePlugin(history()),
1758
+ defineKeymap(keymap),
1759
+ defineCommands({
1760
+ undo: () => undo,
1761
+ redo: () => redo
1762
+ })
1763
+ ]);
1764
+ }
607
1765
 
608
1766
  // src/extensions/mark-spec.ts
609
- function addMarkSpec(options) {
610
- return markSpecFacet.extension([options]);
1767
+ function defineMarkSpec(options) {
1768
+ const payload = [options, void 0];
1769
+ return markSpecFacet.extension([payload]);
1770
+ }
1771
+ function defineMarkAttr(options) {
1772
+ const payload = [void 0, options];
1773
+ return markSpecFacet.extension([payload]);
611
1774
  }
612
1775
  var markSpecFacet = Facet.define({
613
- combine: (options) => {
1776
+ convert: (payloads) => {
614
1777
  const marks = {};
615
- for (const { name, spec } of options) {
1778
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
1779
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNull);
1780
+ for (const { name, ...spec } of specPayloads) {
616
1781
  if (marks[name]) {
617
- throw new Error(`Mark type ${name} has already been defined`);
1782
+ throw new ProseKitError(`Mark type ${name} has already been defined`);
618
1783
  }
619
1784
  marks[name] = spec;
620
1785
  }
1786
+ for (const {
1787
+ type,
1788
+ attr,
1789
+ default: defaultValue,
1790
+ toDOM,
1791
+ parseDOM
1792
+ } of attrPayloads) {
1793
+ const spec = marks[type];
1794
+ if (!spec) {
1795
+ throw new ProseKitError(
1796
+ `Mark type ${type} must be defined before defining attributes`
1797
+ );
1798
+ }
1799
+ if (!spec.attrs) {
1800
+ spec.attrs = {};
1801
+ }
1802
+ spec.attrs[attr] = { default: defaultValue };
1803
+ if (toDOM && spec.toDOM) {
1804
+ const existingToDom = spec.toDOM;
1805
+ spec.toDOM = (mark, inline) => {
1806
+ const dom = existingToDom(mark, inline);
1807
+ if (!dom) {
1808
+ return dom;
1809
+ }
1810
+ const attrDOM = toDOM(mark.attrs[attr]);
1811
+ if (!attrDOM) {
1812
+ return dom;
1813
+ }
1814
+ const [key, value] = attrDOM;
1815
+ if (!key) {
1816
+ return dom;
1817
+ }
1818
+ if (Array.isArray(dom)) {
1819
+ if (typeof dom[1] === "object") {
1820
+ return [dom[0], { ...dom[1], [key]: value }, ...dom.slice(2)];
1821
+ } else {
1822
+ return [dom[0], { [key]: value }, ...dom.slice(1)];
1823
+ }
1824
+ } else if (isElement(dom)) {
1825
+ dom.setAttribute(key, value);
1826
+ } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
1827
+ dom.dom.setAttribute(key, value);
1828
+ }
1829
+ return dom;
1830
+ };
1831
+ }
1832
+ if (parseDOM && spec.parseDOM) {
1833
+ for (const rule of spec.parseDOM) {
1834
+ const existingGetAttrs = rule.getAttrs;
1835
+ const existingAttrs = rule.attrs;
1836
+ rule.getAttrs = (dom) => {
1837
+ var _a;
1838
+ const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
1839
+ if (attrs === false || !dom || !isElement(dom)) {
1840
+ return attrs != null ? attrs : null;
1841
+ }
1842
+ const value = parseDOM(dom);
1843
+ return {
1844
+ ...attrs,
1845
+ [attr]: value
1846
+ };
1847
+ };
1848
+ }
1849
+ }
1850
+ }
621
1851
  return { marks, nodes: {} };
622
1852
  },
623
- next: schemaSlot
1853
+ next: schemaFacet,
1854
+ singleton: true
624
1855
  });
625
1856
 
626
1857
  // src/extensions/node-view.ts
627
- import { Plugin as Plugin2 } from "@prosekit/pm/state";
628
- function addNodeView(options) {
1858
+ import { ProseMirrorPlugin as ProseMirrorPlugin4 } from "@prosekit/pm/state";
1859
+ import "@prosekit/pm/view";
1860
+ function defineNodeView(options) {
629
1861
  return nodeViewFacet.extension([options]);
630
1862
  }
631
1863
  var nodeViewFacet = Facet.define({
632
- combine: (inputs) => {
1864
+ convert: (inputs) => {
633
1865
  const nodeViews = {};
634
1866
  for (const input of inputs) {
635
1867
  if (!nodeViews[input.name]) {
636
1868
  nodeViews[input.name] = input.constructor;
637
1869
  }
638
1870
  }
639
- return () => [new Plugin2({ props: { nodeViews } })];
1871
+ return () => [new ProseMirrorPlugin4({ props: { nodeViews } })];
1872
+ },
1873
+ next: pluginFacet
1874
+ });
1875
+
1876
+ // src/extensions/node-view-effect.ts
1877
+ import { ProseMirrorPlugin as ProseMirrorPlugin5 } from "@prosekit/pm/state";
1878
+ import "@prosekit/pm/view";
1879
+ function defineNodeViewFactory(options) {
1880
+ return nodeViewFactoryFacet.extension([options]);
1881
+ }
1882
+ var nodeViewFactoryFacet = Facet.define({
1883
+ convert: (inputs) => {
1884
+ const nodeViews = {};
1885
+ const options = {};
1886
+ const factories = {};
1887
+ for (const input of inputs) {
1888
+ const group = input.group;
1889
+ if (input.name == null) {
1890
+ factories[group] = input.factory;
1891
+ } else {
1892
+ options[group] || (options[group] = []);
1893
+ options[group].push({
1894
+ name: input.name,
1895
+ args: input.args
1896
+ });
1897
+ }
1898
+ }
1899
+ for (const [group, factory] of Object.entries(factories)) {
1900
+ const groupOptions = options[group] || [];
1901
+ for (const { name, args } of groupOptions) {
1902
+ nodeViews[name] = factory(args);
1903
+ }
1904
+ }
1905
+ return () => [new ProseMirrorPlugin5({ props: { nodeViews } })];
640
1906
  },
641
1907
  next: pluginFacet
642
1908
  });
643
1909
 
644
1910
  // src/extensions/paragraph.ts
645
- function addParagraph() {
646
- return addNodeSpec({
1911
+ function defineParagraphSpec() {
1912
+ return defineNodeSpec({
647
1913
  name: "paragraph",
648
- spec: {
649
- content: "inline*",
650
- group: "block",
651
- parseDOM: [{ tag: "p" }],
652
- toDOM() {
653
- return ["p", 0];
654
- }
1914
+ content: "inline*",
1915
+ group: "block",
1916
+ parseDOM: [{ tag: "p" }],
1917
+ toDOM() {
1918
+ return ["p", 0];
655
1919
  }
656
1920
  });
657
1921
  }
1922
+ function defineParagraph() {
1923
+ return withPriority(defineParagraphSpec(), 0 /* highest */);
1924
+ }
658
1925
 
659
1926
  // src/extensions/text.ts
660
- function addText() {
661
- return addNodeSpec({
1927
+ function defineText() {
1928
+ return defineNodeSpec({
662
1929
  name: "text",
663
- spec: {
664
- group: "inline"
665
- }
1930
+ group: "inline"
666
1931
  });
667
1932
  }
668
1933
 
669
- // src/utils/get-node-type.ts
670
- function getNodeType(schema, type) {
671
- if (typeof type === "string") {
672
- const nodeType = schema.nodes[type];
673
- if (!nodeType) {
674
- throw new ProseKitError(`Cannot find ProseMirror node type "${type}"`);
675
- }
676
- return nodeType;
1934
+ // src/utils/clsx.ts
1935
+ import clsxLite from "clsx/lite";
1936
+ var clsx = clsxLite;
1937
+
1938
+ // src/utils/default-block-at.ts
1939
+ function defaultBlockAt(match) {
1940
+ for (let i = 0; i < match.edgeCount; i++) {
1941
+ const { type } = match.edge(i);
1942
+ if (type.isTextblock && !type.hasRequiredAttrs())
1943
+ return type;
677
1944
  }
678
- return type;
1945
+ return null;
1946
+ }
1947
+
1948
+ // src/utils/get-id.ts
1949
+ var id = 0;
1950
+ function getId() {
1951
+ id = (id + 1) % Number.MAX_SAFE_INTEGER;
1952
+ return `id:${id}`;
1953
+ }
1954
+
1955
+ // src/utils/is-in-code-block.ts
1956
+ function isCodeBlockType(type) {
1957
+ return type.spec.code && type.isBlock;
1958
+ }
1959
+ function isInCodeBlock(selection) {
1960
+ return isCodeBlockType(selection.$from.parent.type) || isCodeBlockType(selection.$to.parent.type);
1961
+ }
1962
+
1963
+ // src/utils/unicode.ts
1964
+ var OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
1965
+
1966
+ // src/utils/with-skip-code-block.ts
1967
+ function withSkipCodeBlock(command) {
1968
+ return (state, dispatch, view) => {
1969
+ if (isInCodeBlock(state.selection)) {
1970
+ return false;
1971
+ }
1972
+ return command(state, dispatch, view);
1973
+ };
679
1974
  }
680
1975
  export {
681
1976
  Editor,
1977
+ EditorNotFoundError,
682
1978
  Facet,
683
- FacetExtension,
1979
+ OBJECT_REPLACEMENT_CHARACTER,
684
1980
  Priority,
685
1981
  ProseKitError,
686
- addBaseCommands,
687
- addBaseKeymap,
688
- addCommands,
689
- addDoc,
690
- addInputRule,
691
- addKeymap,
692
- addMarkSpec,
693
- addNodeSpec,
694
- addNodeView,
695
- addParagraph,
696
- addPlugin,
697
- addText,
1982
+ getId as _getId,
1983
+ addMark,
1984
+ clsx,
698
1985
  createEditor,
699
- defineExtension,
1986
+ defaultBlockAt,
1987
+ defineBaseCommands,
1988
+ defineBaseKeymap,
1989
+ defineClickHandler,
1990
+ defineClickOnHandler,
1991
+ defineCommands,
1992
+ defineDOMEventHandler,
1993
+ defineDefaultState,
1994
+ defineDoc,
1995
+ defineDocChangeHandler,
1996
+ defineDoubleClickHandler,
1997
+ defineDoubleClickOnHandler,
1998
+ defineDropHandler,
1999
+ defineFocusChangeHandler,
2000
+ defineHistory,
2001
+ defineKeyDownHandler,
2002
+ defineKeyPressHandler,
2003
+ defineKeymap,
2004
+ defineMarkAttr,
2005
+ defineMarkSpec,
2006
+ defineMountHandler,
2007
+ defineNodeAttr,
2008
+ defineNodeSpec,
2009
+ defineNodeView,
2010
+ defineNodeViewFactory,
2011
+ defineParagraph,
2012
+ definePasteHandler,
2013
+ definePlugin,
2014
+ defineScrollToSelectionHandler,
2015
+ defineText,
2016
+ defineTextInputHandler,
2017
+ defineTripleClickHandler,
2018
+ defineTripleClickOnHandler,
2019
+ defineUnmountHandler,
2020
+ defineUpdateHandler,
2021
+ elementFromJSON,
2022
+ elementFromNode,
2023
+ expandMark,
700
2024
  getMarkType,
701
2025
  getNodeType,
2026
+ htmlFromJSON,
2027
+ htmlFromNode,
2028
+ insertNode,
2029
+ isAllSelection,
2030
+ isInCodeBlock,
2031
+ isMark,
2032
+ isNodeSelection,
2033
+ isProseMirrorNode,
2034
+ isTextSelection,
2035
+ jsonFromHTML,
2036
+ jsonFromNode,
2037
+ jsonFromState,
2038
+ keymapFacet,
2039
+ nodeFromElement,
2040
+ nodeFromHTML,
2041
+ nodeFromJSON,
2042
+ pluginFacet,
2043
+ removeMark,
2044
+ setBlockType,
2045
+ setNodeAttrs,
2046
+ stateFromJSON,
702
2047
  toggleMark,
703
- withPriority
2048
+ toggleNode,
2049
+ union,
2050
+ withPriority,
2051
+ withSkipCodeBlock
704
2052
  };