@prosekit/core 0.0.0-next-20230709090937 → 0.0.0-next-20231120040948

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,5 +1,9 @@
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 {
@@ -17,134 +21,299 @@ function getMarkType(schema, type) {
17
21
  return type;
18
22
  }
19
23
 
24
+ // src/commands/add-mark.ts
25
+ function addMark(options) {
26
+ return (state, dispatch) => {
27
+ var _a, _b;
28
+ const mark = getMarkType(state.schema, options.type).create(options.attrs);
29
+ const from = (_a = options.from) != null ? _a : state.selection.from;
30
+ const to = (_b = options.to) != null ? _b : state.selection.to;
31
+ if (from > to) {
32
+ return false;
33
+ }
34
+ dispatch == null ? void 0 : dispatch(state.tr.addMark(from, to, mark));
35
+ return true;
36
+ };
37
+ }
38
+
39
+ // src/commands/insert-node.ts
40
+ import { TextSelection } from "@prosekit/pm/state";
41
+ import { insertPoint } from "@prosekit/pm/transform";
42
+
43
+ // src/utils/get-node-type.ts
44
+ import "@prosekit/pm/model";
45
+ function getNodeType(schema, type) {
46
+ if (typeof type === "string") {
47
+ const nodeType = schema.nodes[type];
48
+ if (!nodeType) {
49
+ throw new ProseKitError(`Cannot find ProseMirror node type "${type}"`);
50
+ }
51
+ return nodeType;
52
+ }
53
+ return type;
54
+ }
55
+
56
+ // src/commands/insert-node.ts
57
+ function insertNode(options) {
58
+ return (state, dispatch) => {
59
+ var _a;
60
+ const node = options.node ? options.node : options.type ? getNodeType(state.schema, options.type).createChecked(options.attrs) : null;
61
+ if (!node) {
62
+ throw new ProseKitError("You must provide either a node or a type");
63
+ }
64
+ const insertPos = insertPoint(
65
+ state.doc,
66
+ (_a = options.pos) != null ? _a : state.selection.to,
67
+ node.type
68
+ );
69
+ if (insertPos == null)
70
+ return false;
71
+ if (dispatch) {
72
+ const tr = state.tr.insert(insertPos, node);
73
+ tr.setSelection(TextSelection.near(tr.doc.resolve(insertPos)));
74
+ dispatch(tr);
75
+ }
76
+ return true;
77
+ };
78
+ }
79
+
80
+ // src/commands/remove-mark.ts
81
+ import "@prosekit/pm/model";
82
+ import "@prosekit/pm/state";
83
+ function removeMark(options) {
84
+ return (state, dispatch) => {
85
+ var _a, _b;
86
+ const markType = getMarkType(state.schema, options.type);
87
+ const mark = options.attrs ? markType.create(options.attrs) : markType;
88
+ const from = (_a = options.from) != null ? _a : state.selection.from;
89
+ const to = (_b = options.to) != null ? _b : state.selection.to;
90
+ if (from > to) {
91
+ return false;
92
+ }
93
+ dispatch == null ? void 0 : dispatch(state.tr.removeMark(from, to, mark));
94
+ return true;
95
+ };
96
+ }
97
+
98
+ // src/commands/set-block-type.ts
99
+ import "@prosekit/pm/state";
100
+
101
+ // src/utils/get-custom-selection.ts
102
+ import { TextSelection as TextSelection2 } from "@prosekit/pm/state";
103
+ function getCustomSelection(state, from, to) {
104
+ const pos = from != null ? from : to;
105
+ if (pos != null) {
106
+ const $from = state.doc.resolve(from != null ? from : pos);
107
+ const $to = state.doc.resolve(to != null ? to : pos);
108
+ return TextSelection2.between($from, $to);
109
+ }
110
+ return state.selection;
111
+ }
112
+
113
+ // src/commands/set-block-type.ts
114
+ function setBlockType(options) {
115
+ return (state, dispatch) => {
116
+ const nodeType = getNodeType(state.schema, options.type);
117
+ const selection = getCustomSelection(state, options.from, options.to);
118
+ const attrs = options.attrs;
119
+ let applicable = false;
120
+ for (let i = 0; i < selection.ranges.length && !applicable; i++) {
121
+ const {
122
+ $from: { pos: from },
123
+ $to: { pos: to }
124
+ } = selection.ranges[i];
125
+ state.doc.nodesBetween(from, to, (node, pos) => {
126
+ if (applicable)
127
+ return false;
128
+ if (!node.isTextblock || node.hasMarkup(nodeType, attrs))
129
+ return;
130
+ if (node.type == nodeType) {
131
+ applicable = true;
132
+ } else {
133
+ const $pos = state.doc.resolve(pos), index = $pos.index();
134
+ applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType);
135
+ }
136
+ });
137
+ }
138
+ if (!applicable)
139
+ return false;
140
+ if (dispatch) {
141
+ const tr = state.tr;
142
+ for (const range of selection.ranges) {
143
+ const {
144
+ $from: { pos: from },
145
+ $to: { pos: to }
146
+ } = range;
147
+ tr.setBlockType(from, to, nodeType, attrs);
148
+ }
149
+ dispatch(tr.scrollIntoView());
150
+ }
151
+ return true;
152
+ };
153
+ }
154
+
20
155
  // src/commands/toggle-mark.ts
21
- function toggleMark(options) {
156
+ import { toggleMark as baseToggleMark } from "@prosekit/pm/commands";
157
+ import "@prosekit/pm/model";
158
+ import "@prosekit/pm/state";
159
+ function toggleMark({
160
+ type,
161
+ attrs
162
+ }) {
22
163
  return (state, dispatch, view) => {
23
- return baseToggleMark(
24
- getMarkType(state.schema, options.type),
25
- options.attrs
26
- )(state, dispatch, view);
164
+ return baseToggleMark(getMarkType(state.schema, type), attrs)(
165
+ state,
166
+ dispatch,
167
+ view
168
+ );
169
+ };
170
+ }
171
+
172
+ // src/commands/toggle-node.ts
173
+ import { setBlockType as setBlockType2 } from "@prosekit/pm/commands";
174
+ import "@prosekit/pm/model";
175
+ import "@prosekit/pm/state";
176
+
177
+ // src/utils/attrs-match.ts
178
+ function attrsMatch(nodeOrMark, attrs) {
179
+ const currentAttrs = nodeOrMark.attrs;
180
+ for (const [key, value] of Object.entries(attrs)) {
181
+ if (currentAttrs[key] !== value) {
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ }
187
+
188
+ // src/utils/is-node-active.ts
189
+ function isNodeActive(state, type, attrs) {
190
+ const $pos = state.selection.$from;
191
+ const nodeType = getNodeType(state.schema, type);
192
+ for (let depth = $pos.depth; depth >= 0; depth--) {
193
+ const node = $pos.node(depth);
194
+ if (node.type === nodeType && (!attrs || attrsMatch(node, attrs))) {
195
+ return true;
196
+ }
197
+ }
198
+ return false;
199
+ }
200
+
201
+ // src/commands/toggle-node.ts
202
+ function toggleNode({
203
+ type,
204
+ attrs
205
+ }) {
206
+ return (state, dispatch, view) => {
207
+ if (isNodeActive(state, type, attrs)) {
208
+ const defaultType = state.schema.topNodeType.contentMatch.defaultType;
209
+ if (!defaultType) {
210
+ return false;
211
+ }
212
+ return setBlockType2(defaultType)(state, dispatch, view);
213
+ } else {
214
+ const nodeType = getNodeType(state.schema, type);
215
+ return setBlockType2(nodeType, attrs)(state, dispatch, view);
216
+ }
27
217
  };
28
218
  }
29
219
 
30
220
  // src/editor/editor.ts
31
- import { Schema } from "@prosekit/pm/model";
32
- import { EditorState } from "@prosekit/pm/state";
221
+ import { Schema as Schema6 } from "@prosekit/pm/model";
222
+ import { EditorState as EditorState2 } from "@prosekit/pm/state";
33
223
  import { EditorView } from "@prosekit/pm/view";
34
224
 
35
- // src/types/void-function.ts
36
- function voidFunction() {
225
+ // src/extensions/default-state.ts
226
+ import { Selection } from "@prosekit/pm/state";
227
+
228
+ // src/utils/uniq-array.ts
229
+ function uniqPush(prev, next) {
230
+ const result = [...prev];
231
+ for (const item of next) {
232
+ if (!result.includes(item)) {
233
+ result.push(item);
234
+ }
235
+ }
236
+ return result;
237
+ }
238
+ function uniqRemove(prev, next) {
239
+ const result = [...prev];
240
+ for (const item of next) {
241
+ const index = result.indexOf(item);
242
+ if (index !== -1) {
243
+ result.splice(index, 1);
244
+ }
245
+ }
246
+ return result;
37
247
  }
38
248
 
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 || {});
249
+ // src/facets/base-extension.ts
250
+ import "@prosekit/pm/model";
251
+ var BaseExtension = class {
252
+ constructor() {
253
+ this.extension = [];
254
+ }
255
+ };
48
256
 
49
- // src/editor/facet.ts
50
- var nextIndex = 0;
257
+ // src/facets/facet.ts
258
+ var facetCount = 0;
259
+ function getFacetCount() {
260
+ return facetCount;
261
+ }
51
262
  var Facet = class _Facet {
52
- constructor(combine, next) {
53
- /** @internal */
54
- this.index = nextIndex++;
55
- this.combine = combine;
263
+ constructor(converter, next, singleton) {
264
+ /**
265
+ * @internal
266
+ */
267
+ this.index = facetCount++;
268
+ /**
269
+ * @internal
270
+ */
271
+ this.isSchema = false;
272
+ this.converter = converter;
56
273
  this.next = next;
274
+ this.singleton = singleton;
57
275
  }
58
- static define({ combine, next }) {
59
- return new _Facet(combine, next);
60
- }
61
- /** @internal */
62
- static defineSlot({
63
- combine
276
+ static define({
277
+ converter,
278
+ convert,
279
+ next,
280
+ singleton
64
281
  }) {
65
- return new _Facet(combine, null);
282
+ const converterFunction = converter ? converter : convert ? () => ({
283
+ create: convert,
284
+ update: convert
285
+ }) : null;
286
+ if (!converterFunction) {
287
+ throw new ProseKitError("Facet must have either 'convert' or 'converter'");
288
+ }
289
+ return new _Facet(converterFunction, next, singleton != null ? singleton : false);
66
290
  }
67
- extension(inputs) {
68
- return new FacetExtension(this, inputs);
291
+ /**
292
+ * @internal
293
+ */
294
+ static defineRootFacet(options) {
295
+ return _Facet.define(options);
296
+ }
297
+ extension(payloads) {
298
+ return new FacetExtensionImpl(this, payloads);
69
299
  }
70
300
  };
71
- var FacetExtension = class {
72
- constructor(facet, inputs) {
301
+ var FacetExtensionImpl = class extends BaseExtension {
302
+ constructor(facet, payloads) {
303
+ var _a;
304
+ super();
73
305
  this.facet = facet;
74
- this.inputs = inputs;
306
+ this.payloads = payloads;
307
+ this.schema = null;
308
+ this.hasSchema = !!(facet.isSchema || ((_a = facet.next) == null ? void 0 : _a.isSchema));
75
309
  }
76
310
  };
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;
87
- }
88
- if (inbounds[index] == null) {
89
- inbounds[index] = 0;
90
- }
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;
97
- }
98
- inbounds[nextIndex2] += 1;
99
- if (facetMap[nextIndex2] == null) {
100
- facets.push(facet.next);
101
- }
102
- }
103
- }
104
- const sortedFacets = [];
105
- const sortedIndexes = [];
106
- inbounds.forEach((inbound, index) => {
107
- if (inbound === 0) {
108
- sortedIndexes.push(index);
109
- }
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);
120
- }
121
- }
122
- if (facetCount !== sortedFacets.length) {
123
- throw new Error(`Facet has circular dependency`);
124
- }
125
- return sortedFacets;
126
- }
127
311
 
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;
140
- }
141
- return { nodes, marks, topNode };
142
- }
143
- });
144
- var stateSlot = Facet.defineSlot({
145
- combine: (callbacks) => {
312
+ // src/facets/state.ts
313
+ var stateFacet = Facet.defineRootFacet({
314
+ convert: (callbacks) => {
146
315
  return (ctx) => {
147
- var _a, _b, _c, _d, _e;
316
+ var _a, _b, _c, _d, _e, _f;
148
317
  const configs = callbacks.map((cb) => cb(ctx));
149
318
  const config = {
150
319
  schema: ctx.schema,
@@ -156,10 +325,12 @@ var stateSlot = Facet.defineSlot({
156
325
  config.doc = (_b = config.doc) != null ? _b : c.doc;
157
326
  config.selection = (_c = config.selection) != null ? _c : c.selection;
158
327
  config.storedMarks = [...config.storedMarks, ...(_d = c.storedMarks) != null ? _d : []];
159
- config.plugins = [...config.plugins, ...(_e = c.plugins) != null ? _e : []];
328
+ config.plugins = uniqPush((_e = config.plugins) != null ? _e : [], (_f = c.plugins) != null ? _f : []);
160
329
  }
161
330
  if (!config.doc && !config.schema) {
162
- throw new Error("Can't create state without a schema nor a document");
331
+ throw new ProseKitError(
332
+ "Can't create state without a schema nor a document"
333
+ );
163
334
  }
164
335
  if (config.doc) {
165
336
  config.schema = void 0;
@@ -168,35 +339,204 @@ var stateSlot = Facet.defineSlot({
168
339
  };
169
340
  }
170
341
  });
171
- var viewSlot = Facet.defineSlot({
172
- combine: (props) => {
173
- return Object.assign({}, ...props);
342
+
343
+ // src/utils/parse.ts
344
+ import { DOMParser } from "@prosekit/pm/model";
345
+ import { EditorState } from "@prosekit/pm/state";
346
+
347
+ // src/utils/get-dom-api.ts
348
+ function getGlobalBrowserDocument() {
349
+ if (typeof document !== "undefined") {
350
+ return document;
174
351
  }
175
- });
176
- var commandSlot = Facet.defineSlot({
177
- combine: (inputs) => {
352
+ if (typeof globalThis !== "undefined" && globalThis.document) {
353
+ return globalThis.document;
354
+ }
355
+ }
356
+ function getGlobalBrowserWindow() {
357
+ if (typeof window !== "undefined") {
358
+ return window;
359
+ }
360
+ if (typeof globalThis !== "undefined" && globalThis.window) {
361
+ return globalThis.window;
362
+ }
363
+ }
364
+ function getBrowserWindow() {
365
+ var _a;
366
+ const win = getGlobalBrowserWindow();
367
+ if (win) {
368
+ return win;
369
+ }
370
+ return (_a = getGlobalBrowserDocument()) == null ? void 0 : _a.defaultView;
371
+ }
372
+
373
+ // src/utils/parse.ts
374
+ function nodeFromElement(element, schema) {
375
+ return DOMParser.fromSchema(schema).parse(element);
376
+ }
377
+ function jsonFromElement(element, schema) {
378
+ return jsonFromNode(nodeFromElement(element, schema));
379
+ }
380
+ function nodeFromHTML(html, schema) {
381
+ return nodeFromElement(elementFromHTML(html), schema);
382
+ }
383
+ function jsonFromHTML(html, schema) {
384
+ return jsonFromElement(elementFromHTML(html), schema);
385
+ }
386
+ function elementFromHTML(html) {
387
+ const win = getBrowserWindow();
388
+ if (!win) {
389
+ throw new ProseKitError(
390
+ "No Browser Document Found. You can only parse a HTML string in the browser environment."
391
+ );
392
+ }
393
+ const parser = new win.DOMParser();
394
+ return parser.parseFromString(`<body>${html}</body>`, "text/html").body;
395
+ }
396
+ function jsonFromState(state) {
397
+ return state.toJSON();
398
+ }
399
+ function jsonFromNode(node) {
400
+ return node.toJSON();
401
+ }
402
+ function nodeFromJSON(json, schema) {
403
+ return schema.nodeFromJSON(json);
404
+ }
405
+ function stateFromJSON(json, schema) {
406
+ return EditorState.fromJSON({ schema }, json);
407
+ }
408
+
409
+ // src/extensions/default-state.ts
410
+ function defineDefaultState({
411
+ defaultDoc,
412
+ defaultHTML,
413
+ defaultSelection
414
+ }) {
415
+ if (defaultHTML && defaultDoc) {
416
+ throw new ProseKitError(
417
+ "Only one of defaultHTML and defaultDoc can be provided"
418
+ );
419
+ }
420
+ return stateFacet.extension([
421
+ ({ schema }) => {
422
+ const config = {};
423
+ if (defaultHTML) {
424
+ if (typeof defaultHTML === "string") {
425
+ defaultDoc = jsonFromHTML(defaultHTML, schema);
426
+ } else {
427
+ defaultDoc = jsonFromElement(defaultHTML, schema);
428
+ }
429
+ }
430
+ if (defaultDoc) {
431
+ config.doc = schema.nodeFromJSON(defaultDoc);
432
+ if (defaultSelection) {
433
+ config.selection = Selection.fromJSON(config.doc, defaultSelection);
434
+ }
435
+ }
436
+ return config;
437
+ }
438
+ ]);
439
+ }
440
+
441
+ // src/types/priority.ts
442
+ var Priority = /* @__PURE__ */ ((Priority2) => {
443
+ Priority2[Priority2["lowest"] = 4] = "lowest";
444
+ Priority2[Priority2["low"] = 3] = "low";
445
+ Priority2[Priority2["default"] = 2] = "default";
446
+ Priority2[Priority2["high"] = 1] = "high";
447
+ Priority2[Priority2["highest"] = 0] = "highest";
448
+ return Priority2;
449
+ })(Priority || {});
450
+
451
+ // src/facets/command.ts
452
+ var commandFacet = Facet.defineRootFacet({
453
+ convert: (inputs) => {
178
454
  return Object.assign({}, ...inputs);
179
455
  }
180
456
  });
181
457
 
182
- // src/editor/flatten.ts
183
- function flatten(root) {
458
+ // src/facets/schema.ts
459
+ import OrderedMap from "orderedmap";
460
+ var schemaFacet = Facet.defineRootFacet({
461
+ convert: (specs) => {
462
+ var _a;
463
+ let nodes = OrderedMap.from({});
464
+ let marks = OrderedMap.from({});
465
+ let topNode = void 0;
466
+ for (const spec of specs) {
467
+ nodes = nodes.append(spec.nodes);
468
+ marks = marks.append((_a = spec.marks) != null ? _a : {});
469
+ topNode = topNode != null ? topNode : spec.topNode;
470
+ }
471
+ return { nodes, marks, topNode };
472
+ }
473
+ });
474
+ schemaFacet.isSchema = true;
475
+
476
+ // src/facets/view.ts
477
+ var viewFacet = Facet.defineRootFacet({
478
+ convert: (props) => {
479
+ return Object.assign({}, ...props);
480
+ }
481
+ });
482
+
483
+ // src/facets/flatten.ts
484
+ function flattenInputTuple(inputTuple) {
485
+ return [
486
+ ...inputTuple[0],
487
+ ...inputTuple[1],
488
+ ...inputTuple[2],
489
+ ...inputTuple[3],
490
+ ...inputTuple[4]
491
+ ];
492
+ }
493
+ function mergeInputTuple(tupleA, tupleB) {
494
+ if (!tupleA)
495
+ return tupleB;
496
+ if (!tupleB)
497
+ return tupleA;
498
+ const [a0, a1, a2, a3, a4] = tupleA;
499
+ const [b0, b1, b2, b3, b4] = tupleB;
500
+ return [
501
+ uniqPush(a0, b0),
502
+ uniqPush(a1, b1),
503
+ uniqPush(a2, b2),
504
+ uniqPush(a3, b3),
505
+ uniqPush(a4, b4)
506
+ ];
507
+ }
508
+ function removeInputTuple(tupleA, tupleB) {
509
+ if (!tupleA)
510
+ return [[], [], [], [], []];
511
+ if (!tupleB)
512
+ return tupleA;
513
+ const [a0, a1, a2, a3, a4] = tupleA;
514
+ const [b0, b1, b2, b3, b4] = tupleB;
515
+ return [
516
+ uniqRemove(a0, b0),
517
+ uniqRemove(a1, b1),
518
+ uniqRemove(a2, b2),
519
+ uniqRemove(a3, b3),
520
+ uniqRemove(a4, b4)
521
+ ];
522
+ }
523
+ function extractFacets(root) {
184
524
  var _a;
185
525
  const extensions = [root];
186
526
  const priorities = [2 /* default */];
187
527
  const facets = [];
188
- const inputs = [];
528
+ const payloads = [];
189
529
  while (extensions.length > 0) {
190
530
  const ext = extensions.pop();
191
531
  const pri = priorities.pop();
192
- if (ext instanceof FacetExtension) {
532
+ if (ext instanceof FacetExtensionImpl) {
193
533
  const facet = ext.facet;
194
534
  if (!facets[facet.index]) {
195
535
  facets[facet.index] = facet;
196
- inputs[facet.index] = [[], [], [], [], []];
536
+ payloads[facet.index] = [[], [], [], [], []];
197
537
  }
198
- const facetInputs = ext.inputs;
199
- inputs[facet.index][pri].push(...facetInputs);
538
+ const facetPayloads = ext.payloads;
539
+ payloads[facet.index][pri].push(...facetPayloads);
200
540
  } else if (ext.extension) {
201
541
  const p = (_a = ext.priority) != null ? _a : pri;
202
542
  if (Array.isArray(ext.extension)) {
@@ -209,103 +549,377 @@ function flatten(root) {
209
549
  priorities.push(p);
210
550
  }
211
551
  } else {
212
- throw new Error("Invalid extension");
552
+ throw new ProseKitError("Invalid extension");
213
553
  }
214
554
  }
555
+ return [facets, payloads];
556
+ }
557
+ function updateExtension(prevInputs, prevConverters, extension, mode) {
558
+ var _a;
559
+ const modifyInputTuple = mode === "add" ? mergeInputTuple : removeInputTuple;
560
+ const [facets, inputs] = extractFacets(extension);
215
561
  let schemaInput = null;
216
562
  let stateInput = null;
217
563
  let viewInput = null;
218
564
  let commandInput = null;
219
- const sortedFacets = sortFacets(facets);
220
- for (const facet of sortedFacets) {
565
+ for (let index = getFacetCount(); index >= 0; index--) {
566
+ const facet = facets[index];
567
+ if (!facet) {
568
+ continue;
569
+ }
221
570
  const nextFacet = facet.next;
222
571
  if (nextFacet) {
572
+ facets[_a = nextFacet.index] || (facets[_a] = nextFacet);
573
+ }
574
+ if (!inputs[facet.index]) {
575
+ continue;
576
+ }
577
+ const inputTuple = modifyInputTuple(prevInputs[index], inputs[index]);
578
+ prevInputs[index] = inputTuple;
579
+ if (facet.next && !facet.singleton) {
580
+ let hasOutput = false;
581
+ const outputTuple = [[], [], [], [], []];
223
582
  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);
583
+ const inputArray = inputTuple[pri];
584
+ if (inputArray.length === 0) {
585
+ continue;
586
+ }
587
+ const converterTuple = prevConverters[index] || (prevConverters[index] = [
588
+ void 0,
589
+ void 0,
590
+ void 0,
591
+ void 0,
592
+ void 0
593
+ ]);
594
+ const prevConverter = converterTuple[pri];
595
+ const converter = prevConverter || facet.converter();
596
+ prevConverters[index][pri] = converter;
597
+ const output = prevConverter ? converter.update(inputArray) : converter.create(inputArray);
598
+ if (!output) {
599
+ continue;
231
600
  }
601
+ hasOutput = true;
602
+ outputTuple[pri].push(output);
232
603
  }
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");
604
+ if (!hasOutput) {
605
+ continue;
606
+ }
607
+ inputs[facet.next.index] = modifyInputTuple(
608
+ inputs[facet.next.index],
609
+ outputTuple
610
+ );
611
+ continue;
612
+ } else {
613
+ const inputArray = flattenInputTuple(inputTuple);
614
+ prevConverters[index] || (prevConverters[index] = [
615
+ void 0,
616
+ void 0,
617
+ void 0,
618
+ void 0,
619
+ void 0
620
+ ]);
621
+ const prevConverter = prevConverters[index][2 /* default */];
622
+ const converter = prevConverter || facet.converter();
623
+ prevConverters[index][2 /* default */] = converter;
624
+ const output = prevConverter ? converter.update(inputArray) : converter.create(inputArray);
625
+ if (!output) {
626
+ continue;
627
+ }
628
+ if (facet.next) {
629
+ const outputTuple = [[], [], [output], [], []];
630
+ inputs[facet.next.index] = modifyInputTuple(
631
+ inputs[facet.next.index],
632
+ outputTuple
633
+ );
634
+ } else {
635
+ switch (facet) {
636
+ case schemaFacet:
637
+ schemaInput = output;
638
+ break;
639
+ case stateFacet:
640
+ stateInput = output;
641
+ break;
642
+ case viewFacet:
643
+ viewInput = output;
644
+ break;
645
+ case commandFacet:
646
+ commandInput = output;
647
+ break;
648
+ default:
649
+ throw new ProseKitError("Invalid root facet");
650
+ }
252
651
  }
253
652
  }
254
653
  }
255
654
  return { schemaInput, stateInput, viewInput, commandInput };
256
655
  }
257
656
 
657
+ // src/utils/type-assertion.ts
658
+ import { Mark, ProseMirrorNode } from "@prosekit/pm/model";
659
+ import {
660
+ AllSelection,
661
+ NodeSelection,
662
+ TextSelection as TextSelection3
663
+ } from "@prosekit/pm/state";
664
+ function isProseMirrorNode(node) {
665
+ return node instanceof ProseMirrorNode;
666
+ }
667
+ function isMark(mark) {
668
+ return mark instanceof Mark;
669
+ }
670
+ function isTextSelection(sel) {
671
+ return sel instanceof TextSelection3;
672
+ }
673
+ function isNodeSelection(sel) {
674
+ return sel instanceof NodeSelection;
675
+ }
676
+ function isAllSelection(sel) {
677
+ return sel instanceof AllSelection;
678
+ }
679
+
680
+ // src/utils/is-mark-active.ts
681
+ function isMarkActive(state, type, attrs) {
682
+ const markType = getMarkType(state.schema, type);
683
+ const mark = attrs ? markType.create(attrs) : markType;
684
+ const { from, $from, to, empty } = state.selection;
685
+ if (empty) {
686
+ return hasMark(state.storedMarks || $from.marks(), mark);
687
+ } else {
688
+ return state.doc.rangeHasMark(from, to, mark);
689
+ }
690
+ }
691
+ function hasMark(marks, mark) {
692
+ if (marks.length === 0) {
693
+ return false;
694
+ }
695
+ if (isMark(mark)) {
696
+ return marks.some((m) => m.eq(mark));
697
+ } else {
698
+ return marks.some((m) => m.type === mark);
699
+ }
700
+ }
701
+
702
+ // src/editor/builder.ts
703
+ import "@prosekit/pm/model";
704
+ function createNodeBuilder(getState, type) {
705
+ const builder = (...args) => buildNode(type, args);
706
+ builder.isActive = (attrs) => {
707
+ const state = getState();
708
+ return state ? isNodeActive(state, type, attrs) : false;
709
+ };
710
+ return builder;
711
+ }
712
+ function createMarkBuilder(getState, type) {
713
+ const builder = (...args) => buildMark(type, args);
714
+ builder.isActive = (attrs) => {
715
+ const state = getState();
716
+ return state ? isMarkActive(state, type, attrs) : false;
717
+ };
718
+ return builder;
719
+ }
720
+ function buildMark(type, args) {
721
+ const [attrs, children] = normalizeArgs(args);
722
+ return flattenChildren(type.schema, children, type.create(attrs));
723
+ }
724
+ function buildNode(type, args) {
725
+ const [attrs, children] = normalizeArgs(args);
726
+ const node = type.createAndFill(attrs, flattenChildren(type.schema, children));
727
+ if (!node) {
728
+ throw new ProseKitError(`Couldn't create node ${type.name}`);
729
+ }
730
+ return node;
731
+ }
732
+ function flattenChildren(schema, children, mark) {
733
+ const nodes = [];
734
+ for (const child of children) {
735
+ if (typeof child === "string") {
736
+ if (child) {
737
+ nodes.push(schema.text(child, mark ? [mark] : null));
738
+ }
739
+ } else if (Array.isArray(child)) {
740
+ nodes.push(...flattenChildren(schema, child, mark));
741
+ } else if (isProseMirrorNode(child)) {
742
+ nodes.push(mark ? child.mark(mark.addToSet(child.marks)) : child);
743
+ } else {
744
+ throw new ProseKitError(`Invalid node child: ${typeof child}`);
745
+ }
746
+ }
747
+ return nodes;
748
+ }
749
+ function normalizeArgs(args) {
750
+ const [attrs, ...children] = args;
751
+ if (isNodeChild(attrs)) {
752
+ children.unshift(attrs);
753
+ return [null, children];
754
+ } else if (typeof attrs === "object") {
755
+ return [attrs, children];
756
+ } else {
757
+ return [null, children];
758
+ }
759
+ }
760
+ function isNodeChild(value) {
761
+ if (!value) {
762
+ return false;
763
+ }
764
+ return typeof value === "string" || Array.isArray(value) || isProseMirrorNode(value);
765
+ }
766
+
767
+ // src/facets/union-extension.ts
768
+ import { Schema as Schema5 } from "@prosekit/pm/model";
769
+ var UnionExtensionImpl = class extends BaseExtension {
770
+ constructor(extension = []) {
771
+ super();
772
+ this.extension = extension;
773
+ this._schema = void 0;
774
+ this.hasSchemaCount = 0;
775
+ for (const e of extension) {
776
+ if (e instanceof BaseExtension) {
777
+ this.hasSchemaCount += e.hasSchema ? 1 : 0;
778
+ } else {
779
+ throw new ProseKitError("Invalid extension");
780
+ }
781
+ }
782
+ }
783
+ get hasSchema() {
784
+ return this.hasSchemaCount > 0;
785
+ }
786
+ get schema() {
787
+ var _a;
788
+ if (this._schema !== void 0) {
789
+ return this._schema;
790
+ }
791
+ if (this.hasSchemaCount === 0) {
792
+ this._schema = null;
793
+ return this._schema;
794
+ }
795
+ if (this.hasSchemaCount === 1) {
796
+ const schema = (_a = this.extension.find((e) => e.hasSchema)) == null ? void 0 : _a.schema;
797
+ if (schema) {
798
+ this._schema = schema;
799
+ return this._schema;
800
+ }
801
+ }
802
+ const { schemaInput } = updateExtension([], [], this, "add");
803
+ this._schema = schemaInput ? new Schema5(schemaInput) : null;
804
+ return this._schema;
805
+ }
806
+ };
807
+
808
+ // src/editor/union.ts
809
+ function union(extension) {
810
+ const array = Array.isArray(extension) ? extension : [extension];
811
+ return new UnionExtensionImpl(
812
+ array
813
+ );
814
+ }
815
+
258
816
  // src/editor/editor.ts
259
817
  function createEditor({
260
- extension
818
+ extension,
819
+ defaultDoc,
820
+ defaultHTML,
821
+ defaultSelection
261
822
  }) {
262
- const { schemaInput, stateInput, viewInput, commandInput } = flatten(extension);
263
- if (!schemaInput) {
264
- throw new Error("Schema must be defined");
265
- }
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);
274
- }
823
+ if (defaultDoc || defaultHTML) {
824
+ extension = union([
825
+ extension,
826
+ defineDefaultState({
827
+ defaultDoc,
828
+ defaultHTML,
829
+ defaultSelection
830
+ })
831
+ ]);
275
832
  }
276
- return Editor.create(instance);
833
+ return Editor.create(new EditorInstance(extension));
277
834
  }
278
835
  var EditorInstance = class {
279
- constructor(directEditorProps) {
280
- this.directEditorProps = directEditorProps;
836
+ constructor(extension) {
281
837
  this.view = null;
282
- this.commandDispatchers = {};
838
+ this.commandAppliers = {};
839
+ this.payloads = [];
840
+ this.converters = [];
283
841
  this.mount = this.mount.bind(this);
284
842
  this.unmount = this.unmount.bind(this);
285
- this.schema = directEditorProps.state.schema;
843
+ const { schemaInput, stateInput, viewInput, commandInput } = updateExtension(this.payloads, this.converters, extension, "add");
844
+ if (!schemaInput) {
845
+ throw new ProseKitError("Schema must be defined");
846
+ }
847
+ const schema = new Schema6(schemaInput);
848
+ const stateConfig = stateInput ? stateInput({ schema }) : { schema };
849
+ const state = EditorState2.create(stateConfig);
850
+ if (commandInput) {
851
+ for (const [name, commandCreator] of Object.entries(commandInput)) {
852
+ this.defineCommand(name, commandCreator);
853
+ }
854
+ }
855
+ this.directEditorProps = { state, ...viewInput };
856
+ this.schema = this.directEditorProps.state.schema;
857
+ const getState = () => {
858
+ var _a;
859
+ return (_a = this.view) == null ? void 0 : _a.state;
860
+ };
861
+ this.nodeBuilders = Object.fromEntries(
862
+ Object.values(this.schema.nodes).map((type) => [
863
+ type.name,
864
+ createNodeBuilder(getState, type)
865
+ ])
866
+ );
867
+ this.markBuilders = Object.fromEntries(
868
+ Object.values(this.schema.marks).map((type) => [
869
+ type.name,
870
+ createMarkBuilder(getState, type)
871
+ ])
872
+ );
873
+ }
874
+ updateExtension(extension, mode) {
875
+ var _a;
876
+ const { schemaInput, stateInput, viewInput, commandInput } = updateExtension(this.payloads, this.converters, extension, mode);
877
+ if (schemaInput) {
878
+ throw new ProseKitError("Schema cannot be changed");
879
+ }
880
+ if (viewInput) {
881
+ throw new ProseKitError("View cannot be changed");
882
+ }
883
+ const plugins = (_a = stateInput == null ? void 0 : stateInput({ schema: this.schema })) == null ? void 0 : _a.plugins;
884
+ if (plugins && plugins.length > 0) {
885
+ if (!this.view) {
886
+ throw new ProseKitError(
887
+ "Unexpected inner state: EditorInstance.view is not defined"
888
+ );
889
+ }
890
+ const state = this.view.state.reconfigure({ plugins });
891
+ this.view.updateState(state);
892
+ }
893
+ if (commandInput) {
894
+ const names = Object.keys(commandInput);
895
+ for (const name of names) {
896
+ this.defineCommand(name, commandInput[name]);
897
+ }
898
+ }
286
899
  }
287
900
  mount(place) {
288
901
  if (this.view) {
289
- throw new Error("Editor is already mounted");
902
+ throw new ProseKitError("Editor is already mounted");
290
903
  }
291
904
  if (!place) {
292
- throw new Error("Can't mount editor without a place");
905
+ throw new ProseKitError("Can't mount editor without a place");
293
906
  }
294
907
  this.view = new EditorView({ mount: place }, this.directEditorProps);
295
908
  }
296
909
  unmount() {
297
910
  if (!this.view) {
298
- throw new Error("Editor is not mounted yet");
911
+ throw new ProseKitError("Editor is not mounted yet");
299
912
  }
300
913
  this.view.destroy();
301
914
  this.view = null;
302
915
  }
303
916
  get assertView() {
304
- if (!this.view)
305
- throw new Error("Editor is not mounted");
917
+ if (!this.view) {
918
+ throw new ProseKitError("Editor is not mounted");
919
+ }
306
920
  return this.view;
307
921
  }
308
- addPlugins(plugins) {
922
+ definePlugins(plugins) {
309
923
  const view = this.assertView;
310
924
  const state = view.state;
311
925
  const newPlugins = [...plugins, ...state.plugins];
@@ -321,16 +935,27 @@ var EditorInstance = class {
321
935
  const newState = state.reconfigure({ plugins: newPlugins });
322
936
  view.setProps({ state: newState });
323
937
  }
324
- addCommand(name, commandCreator) {
325
- const dispatcher = (...args) => {
326
- const view = this.assertView;
938
+ defineCommand(name, commandCreator) {
939
+ const applier = (...args) => {
940
+ const view = this.view;
941
+ if (!view) {
942
+ return false;
943
+ }
327
944
  const command = commandCreator(...args);
328
945
  return command(view.state, view.dispatch.bind(view), view);
329
946
  };
330
- this.commandDispatchers[name] = dispatcher;
947
+ applier.canApply = (...args) => {
948
+ const view = this.view;
949
+ if (!view) {
950
+ return false;
951
+ }
952
+ const command = commandCreator(...args);
953
+ return command(view.state, void 0, view);
954
+ };
955
+ this.commandAppliers[name] = applier;
331
956
  }
332
957
  removeCommand(name) {
333
- delete this.commandDispatchers[name];
958
+ delete this.commandAppliers[name];
334
959
  }
335
960
  };
336
961
  var Editor = class _Editor {
@@ -341,10 +966,12 @@ var Editor = class _Editor {
341
966
  this.unmount = this.unmount.bind(this);
342
967
  this.use = this.use.bind(this);
343
968
  }
344
- /** @internal */
969
+ /**
970
+ * @internal
971
+ */
345
972
  static create(instance) {
346
973
  if (!(instance instanceof EditorInstance)) {
347
- throw new TypeError("Editor's instance is not EditorInstance");
974
+ throw new TypeError("Invalid EditorInstance");
348
975
  }
349
976
  return new _Editor(instance);
350
977
  }
@@ -358,7 +985,7 @@ var Editor = class _Editor {
358
985
  return this.instance.schema;
359
986
  }
360
987
  get commands() {
361
- return this.instance.commandDispatchers;
988
+ return this.instance.commandAppliers;
362
989
  }
363
990
  mount(place) {
364
991
  if (!place) {
@@ -383,218 +1010,203 @@ var Editor = class _Editor {
383
1010
  lazyRemove == null ? void 0 : lazyRemove();
384
1011
  };
385
1012
  }
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;
1013
+ this.instance.updateExtension(extension, "add");
1014
+ return () => this.instance.updateExtension(extension, "remove");
413
1015
  }
414
- };
415
-
416
- // src/editor/type-utils.ts
417
- function defineExtension(extension) {
418
- if (extension && Array.isArray(extension)) {
419
- return { extension };
1016
+ /**
1017
+ * @deprecated
1018
+ */
1019
+ isNodeActive(nodeType, attrs) {
1020
+ return isNodeActive(this.view.state, nodeType, attrs);
420
1021
  }
421
- return extension;
422
- }
1022
+ /**
1023
+ * @deprecated
1024
+ */
1025
+ isMarkActive(markType, attrs) {
1026
+ return isMarkActive(this.view.state, markType, attrs);
1027
+ }
1028
+ get nodes() {
1029
+ return this.instance.nodeBuilders;
1030
+ }
1031
+ get marks() {
1032
+ return this.instance.markBuilders;
1033
+ }
1034
+ };
423
1035
 
424
1036
  // src/editor/with-priority.ts
425
1037
  function withPriority(extension, priority) {
426
- return { extension, priority };
1038
+ const result = union(extension);
1039
+ result.priority = priority;
1040
+ return result;
427
1041
  }
428
1042
 
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
- };
1043
+ // src/commands/insert-text.ts
1044
+ function insertText({
1045
+ text,
1046
+ from,
1047
+ to
1048
+ }) {
1049
+ return (state, dispatch) => {
1050
+ if (text) {
1051
+ dispatch == null ? void 0 : dispatch(state.tr.insertText(text, from, to));
501
1052
  }
1053
+ return true;
1054
+ };
1055
+ }
1056
+
1057
+ // src/commands/select-all.ts
1058
+ import { AllSelection as AllSelection2 } from "@prosekit/pm/state";
1059
+ function selectAll() {
1060
+ return (state, dispatch) => {
1061
+ dispatch == null ? void 0 : dispatch(state.tr.setSelection(new AllSelection2(state.doc)));
1062
+ return true;
1063
+ };
1064
+ }
1065
+
1066
+ // src/commands/wrap.ts
1067
+ import "@prosekit/pm/model";
1068
+ import "@prosekit/pm/state";
1069
+ import { findWrapping } from "@prosekit/pm/transform";
1070
+ function wrap({
1071
+ nodeType,
1072
+ attrs
1073
+ }) {
1074
+ return (state, dispatch) => {
1075
+ const { $from, $to } = state.selection;
1076
+ const range = $from.blockRange($to);
1077
+ if (!range)
1078
+ return false;
1079
+ const wrapping = findWrapping(range, nodeType, attrs);
1080
+ if (!wrapping)
1081
+ return false;
1082
+ dispatch == null ? void 0 : dispatch(state.tr.wrap(range, wrapping));
1083
+ return true;
1084
+ };
1085
+ }
1086
+
1087
+ // src/extensions/command.ts
1088
+ function defineCommands(commands) {
1089
+ return commandFacet.extension([commands]);
1090
+ }
1091
+ function defineBaseCommands() {
1092
+ return defineCommands({
1093
+ insertText,
1094
+ insertNode,
1095
+ wrap,
1096
+ setBlockType,
1097
+ selectAll,
1098
+ addMark,
1099
+ removeMark
502
1100
  });
503
1101
  }
504
1102
 
505
1103
  // src/extensions/node-spec.ts
506
- function addNodeSpec(options) {
1104
+ function defineNodeSpec(options) {
507
1105
  return nodeSpecFacet.extension([options]);
508
1106
  }
509
1107
  var nodeSpecFacet = Facet.define({
510
- combine: (options) => {
1108
+ convert: (options) => {
511
1109
  const nodes = {};
512
- let topNode = void 0;
513
- for (const { name, spec, topNode: isTopNode } of options) {
1110
+ let topNodeName = void 0;
1111
+ for (const { name, topNode, ...spec } of options) {
514
1112
  if (nodes[name]) {
515
- throw new Error(`Node type ${name} has already been defined`);
1113
+ throw new ProseKitError(`Node type ${name} has already been defined`);
516
1114
  }
517
- nodes[name] = spec;
518
- if (isTopNode && !topNode) {
519
- topNode = name;
1115
+ if (topNodeName && !topNode) {
1116
+ topNodeName = name;
520
1117
  }
1118
+ nodes[name] = spec;
521
1119
  }
522
- return { nodes, topNode };
1120
+ return { nodes, topNode: topNodeName };
523
1121
  },
524
- next: schemaSlot
1122
+ next: schemaFacet
525
1123
  });
526
1124
 
527
1125
  // src/extensions/doc.ts
528
- function addDoc() {
529
- return addNodeSpec({
1126
+ function defineDoc() {
1127
+ return defineNodeSpec({
530
1128
  name: "doc",
531
- spec: {
532
- content: "block+"
533
- }
1129
+ content: "block+",
1130
+ topNode: true
534
1131
  });
535
1132
  }
536
1133
 
537
- // src/extensions/input-rules.ts
538
- import { inputRules } from "@prosekit/pm/inputrules";
1134
+ // src/extensions/history.ts
1135
+ import { history, redo, undo } from "@prosekit/pm/history";
1136
+
1137
+ // src/utils/env.ts
1138
+ var isMac = typeof navigator !== "undefined" ? /Mac|iP(hone|[ao]d)/.test(navigator.platform) : false;
1139
+
1140
+ // src/extensions/keymap.ts
1141
+ import { baseKeymap, chainCommands } from "@prosekit/pm/commands";
1142
+ import { keydownHandler } from "@prosekit/pm/keymap";
1143
+ import { Plugin as Plugin3, PluginKey } from "@prosekit/pm/state";
539
1144
 
540
1145
  // 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");
1146
+ import "@prosekit/pm/model";
1147
+ import { Plugin as Plugin2 } from "@prosekit/pm/state";
1148
+ function definePlugin(plugin) {
1149
+ if (plugin instanceof Plugin2) {
1150
+ return pluginFacet.extension([() => [plugin]]);
548
1151
  }
1152
+ if (Array.isArray(plugin) && plugin.every((p) => p instanceof Plugin2)) {
1153
+ return pluginFacet.extension([() => plugin]);
1154
+ }
1155
+ if (typeof plugin === "function") {
1156
+ return pluginFacet.extension([plugin]);
1157
+ }
1158
+ throw new TypeError("Invalid plugin");
549
1159
  }
550
1160
  var pluginFacet = Facet.define({
551
- combine: (callbacks) => {
1161
+ convert: (callbacks) => {
552
1162
  return ({ schema }) => {
553
1163
  const plugins = callbacks.flatMap((func) => func({ schema }));
554
1164
  return { plugins };
555
1165
  };
556
1166
  },
557
- next: stateSlot
558
- });
559
-
560
- // src/extensions/input-rules.ts
561
- function addInputRule(rules) {
562
- return inputRuleFacet.extension([rules]);
563
- }
564
- var inputRuleFacet = Facet.define({
565
- combine: (inputs) => {
566
- return (context) => {
567
- const rules = inputs.flatMap((callback) => callback(context));
568
- return [inputRules({ rules })];
569
- };
570
- },
571
- next: pluginFacet
1167
+ next: stateFacet
572
1168
  });
573
1169
 
574
1170
  // src/extensions/keymap.ts
575
- import { baseKeymap, chainCommands } from "@prosekit/pm/commands";
576
- import { keymap as createKeymapPlugin } from "@prosekit/pm/keymap";
577
- function addKeymap(keymap) {
1171
+ function defineKeymap(keymap) {
578
1172
  return keymapFacet.extension([keymap]);
579
1173
  }
580
- function addBaseKeymap() {
581
- return addKeymap(baseKeymap);
1174
+ function defineBaseKeymap() {
1175
+ return defineKeymap(baseKeymap);
582
1176
  }
583
1177
  var keymapFacet = Facet.define({
584
- combine: (keymaps) => {
585
- const keymap = mergeKeymaps(keymaps);
586
- const plugin = createKeymapPlugin(keymap);
587
- return () => [plugin];
1178
+ converter: () => {
1179
+ let handler = null;
1180
+ const handlerWrapper = (view, event) => {
1181
+ if (handler)
1182
+ return handler(view, event);
1183
+ return false;
1184
+ };
1185
+ const plugin = new Plugin3({
1186
+ key: keymapPluginKey,
1187
+ props: { handleKeyDown: handlerWrapper }
1188
+ });
1189
+ const pluginFunc = () => [plugin];
1190
+ return {
1191
+ create: (keymaps) => {
1192
+ handler = keydownHandler(mergeKeymaps(keymaps));
1193
+ return pluginFunc;
1194
+ },
1195
+ update: (keymaps) => {
1196
+ handler = keydownHandler(mergeKeymaps(keymaps));
1197
+ return null;
1198
+ }
1199
+ };
588
1200
  },
589
- next: pluginFacet
1201
+ next: pluginFacet,
1202
+ singleton: true
590
1203
  });
591
1204
  function mergeKeymaps(keymaps) {
592
1205
  const bindings = {};
593
1206
  for (const keymap of keymaps) {
594
1207
  for (const [key, command] of Object.entries(keymap)) {
595
- if (!bindings[key])
596
- bindings[key] = [];
597
- bindings[key].push(command);
1208
+ const commands = bindings[key] || (bindings[key] = []);
1209
+ commands.push(command);
598
1210
  }
599
1211
  }
600
1212
  return Object.fromEntries(
@@ -604,101 +1216,234 @@ function mergeKeymaps(keymaps) {
604
1216
  ])
605
1217
  );
606
1218
  }
1219
+ var keymapPluginKey = new PluginKey("prosekit-keymap");
1220
+
1221
+ // src/extensions/history.ts
1222
+ function defineHistory() {
1223
+ const keymap = {
1224
+ "Mod-z": undo,
1225
+ "Shift-Mod-z": redo
1226
+ };
1227
+ if (!isMac) {
1228
+ keymap["Mod-y"] = redo;
1229
+ }
1230
+ return union([
1231
+ definePlugin(history()),
1232
+ defineKeymap(keymap),
1233
+ defineCommands({
1234
+ undo: () => undo,
1235
+ redo: () => redo
1236
+ })
1237
+ ]);
1238
+ }
1239
+
1240
+ // src/extensions/input-rules.ts
1241
+ import { InputRule, inputRules } from "@prosekit/pm/inputrules";
1242
+ import "@prosekit/pm/model";
1243
+ import "@prosekit/pm/state";
1244
+ function defineInputRule(rule) {
1245
+ if (rule instanceof InputRule) {
1246
+ return inputRuleFacet.extension([() => rule]);
1247
+ }
1248
+ if (Array.isArray(rule) && rule.every((r) => r instanceof InputRule)) {
1249
+ return inputRuleFacet.extension([() => rule]);
1250
+ }
1251
+ if (typeof rule === "function") {
1252
+ return inputRuleFacet.extension([rule]);
1253
+ }
1254
+ throw new TypeError("Invalid input rule");
1255
+ }
1256
+ var inputRuleFacet = Facet.define({
1257
+ convert: (inputs) => {
1258
+ return (context) => {
1259
+ const rules = inputs.flatMap((callback) => callback(context));
1260
+ return [inputRules({ rules })];
1261
+ };
1262
+ },
1263
+ next: pluginFacet
1264
+ });
607
1265
 
608
1266
  // src/extensions/mark-spec.ts
609
- function addMarkSpec(options) {
1267
+ function defineMarkSpec(options) {
610
1268
  return markSpecFacet.extension([options]);
611
1269
  }
612
1270
  var markSpecFacet = Facet.define({
613
- combine: (options) => {
1271
+ convert: (options) => {
614
1272
  const marks = {};
615
- for (const { name, spec } of options) {
1273
+ for (const { name, ...spec } of options) {
616
1274
  if (marks[name]) {
617
- throw new Error(`Mark type ${name} has already been defined`);
1275
+ throw new ProseKitError(`Mark type ${name} has already been defined`);
618
1276
  }
619
1277
  marks[name] = spec;
620
1278
  }
621
1279
  return { marks, nodes: {} };
622
1280
  },
623
- next: schemaSlot
1281
+ next: schemaFacet
624
1282
  });
625
1283
 
626
1284
  // src/extensions/node-view.ts
627
- import { Plugin as Plugin2 } from "@prosekit/pm/state";
628
- function addNodeView(options) {
1285
+ import { ProseMirrorPlugin } from "@prosekit/pm/state";
1286
+ import "@prosekit/pm/view";
1287
+ function defineNodeView(options) {
629
1288
  return nodeViewFacet.extension([options]);
630
1289
  }
631
1290
  var nodeViewFacet = Facet.define({
632
- combine: (inputs) => {
1291
+ convert: (inputs) => {
633
1292
  const nodeViews = {};
634
1293
  for (const input of inputs) {
635
1294
  if (!nodeViews[input.name]) {
636
1295
  nodeViews[input.name] = input.constructor;
637
1296
  }
638
1297
  }
639
- return () => [new Plugin2({ props: { nodeViews } })];
1298
+ return () => [new ProseMirrorPlugin({ props: { nodeViews } })];
1299
+ },
1300
+ next: pluginFacet
1301
+ });
1302
+
1303
+ // src/extensions/node-view-effect.ts
1304
+ import { ProseMirrorPlugin as ProseMirrorPlugin2 } from "@prosekit/pm/state";
1305
+ import "@prosekit/pm/view";
1306
+ function defineNodeViewEffect(options) {
1307
+ return nodeViewEffectFacet.extension([options]);
1308
+ }
1309
+ var nodeViewEffectFacet = Facet.define({
1310
+ convert: (inputs) => {
1311
+ const nodeViews = {};
1312
+ const options = {};
1313
+ const factories = {};
1314
+ for (const input of inputs) {
1315
+ const group = input.group;
1316
+ if (input.name == null) {
1317
+ factories[group] = input.factory;
1318
+ } else {
1319
+ options[group] || (options[group] = []);
1320
+ options[group].push({
1321
+ name: input.name,
1322
+ args: input.args
1323
+ });
1324
+ }
1325
+ }
1326
+ for (const [group, factory] of Object.entries(factories)) {
1327
+ const groupOptions = options[group] || [];
1328
+ for (const { name, args } of groupOptions) {
1329
+ nodeViews[name] = factory(args);
1330
+ }
1331
+ }
1332
+ return () => Object.keys(nodeViews).length > 0 ? [new ProseMirrorPlugin2({ props: { nodeViews } })] : [];
640
1333
  },
641
1334
  next: pluginFacet
642
1335
  });
643
1336
 
644
1337
  // src/extensions/paragraph.ts
645
- function addParagraph() {
646
- return addNodeSpec({
1338
+ function defineParagraphSpec() {
1339
+ return defineNodeSpec({
647
1340
  name: "paragraph",
648
- spec: {
649
- content: "inline*",
650
- group: "block",
651
- parseDOM: [{ tag: "p" }],
652
- toDOM() {
653
- return ["p", 0];
654
- }
1341
+ content: "inline*",
1342
+ group: "block",
1343
+ parseDOM: [{ tag: "p" }],
1344
+ toDOM() {
1345
+ return ["p", 0];
655
1346
  }
656
1347
  });
657
1348
  }
1349
+ function defineParagraph() {
1350
+ return withPriority(defineParagraphSpec(), 0 /* highest */);
1351
+ }
658
1352
 
659
1353
  // src/extensions/text.ts
660
- function addText() {
661
- return addNodeSpec({
1354
+ function defineText() {
1355
+ return defineNodeSpec({
662
1356
  name: "text",
663
- spec: {
664
- group: "inline"
665
- }
1357
+ group: "inline"
666
1358
  });
667
1359
  }
668
1360
 
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;
677
- }
678
- return type;
1361
+ // src/extensions/update-handler.ts
1362
+ import { PluginKey as PluginKey2, ProseMirrorPlugin as ProseMirrorPlugin3 } from "@prosekit/pm/state";
1363
+
1364
+ // src/utils/is-not-null.ts
1365
+ function isNotNull(value) {
1366
+ return value != null;
1367
+ }
1368
+
1369
+ // src/extensions/update-handler.ts
1370
+ function defineUpdateHandler(handler) {
1371
+ return updateHandlerFacet.extension([handler]);
679
1372
  }
1373
+ var updateHandlerFacet = Facet.define({
1374
+ converter: () => {
1375
+ let updateHandlers = [];
1376
+ const plugin = new ProseMirrorPlugin3({
1377
+ key: pluginKey,
1378
+ view: (view) => {
1379
+ updateHandlers.forEach((fn) => fn({ view }));
1380
+ return {
1381
+ update: (view2, prevState) => {
1382
+ updateHandlers.forEach((fn) => fn({ view: view2, prevState }));
1383
+ }
1384
+ };
1385
+ }
1386
+ });
1387
+ const pluginFunc = () => [plugin];
1388
+ return {
1389
+ create: (handlers) => {
1390
+ updateHandlers = handlers.filter(isNotNull);
1391
+ return pluginFunc;
1392
+ },
1393
+ update: (handlers) => {
1394
+ updateHandlers = handlers.filter(isNotNull);
1395
+ return null;
1396
+ }
1397
+ };
1398
+ },
1399
+ next: pluginFacet,
1400
+ singleton: true
1401
+ });
1402
+ var pluginKey = new PluginKey2("prosekit-event-handler");
680
1403
  export {
681
1404
  Editor,
682
1405
  Facet,
683
- FacetExtension,
684
1406
  Priority,
685
1407
  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,
1408
+ addMark,
698
1409
  createEditor,
699
- defineExtension,
1410
+ defineBaseCommands,
1411
+ defineBaseKeymap,
1412
+ defineCommands,
1413
+ defineDefaultState,
1414
+ defineDoc,
1415
+ defineHistory,
1416
+ defineInputRule,
1417
+ defineKeymap,
1418
+ defineMarkSpec,
1419
+ defineNodeSpec,
1420
+ defineNodeView,
1421
+ defineNodeViewEffect,
1422
+ defineParagraph,
1423
+ definePlugin,
1424
+ defineText,
1425
+ defineUpdateHandler,
700
1426
  getMarkType,
701
1427
  getNodeType,
1428
+ insertNode,
1429
+ isAllSelection,
1430
+ isMark,
1431
+ isNodeSelection,
1432
+ isProseMirrorNode,
1433
+ isTextSelection,
1434
+ jsonFromElement,
1435
+ jsonFromHTML,
1436
+ jsonFromNode,
1437
+ jsonFromState,
1438
+ nodeFromElement,
1439
+ nodeFromHTML,
1440
+ nodeFromJSON,
1441
+ pluginFacet,
1442
+ removeMark,
1443
+ setBlockType,
1444
+ stateFromJSON,
702
1445
  toggleMark,
1446
+ toggleNode,
1447
+ union,
703
1448
  withPriority
704
1449
  };