@prosekit/core 0.7.6 → 0.7.8

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.
@@ -15,13 +15,17 @@ import {
15
15
  htmlFromJSON,
16
16
  htmlFromNode,
17
17
  isAllSelection,
18
+ isElement,
19
+ isFragment,
18
20
  isMark,
19
21
  isMarkAbsent,
20
22
  isMarkActive,
21
23
  isNodeActive,
22
24
  isNodeSelection,
23
- isNotNull,
25
+ isNotNullish,
24
26
  isProseMirrorNode,
27
+ isSelection,
28
+ isSlice,
25
29
  isTextSelection,
26
30
  jsonFromHTML,
27
31
  jsonFromNode,
@@ -35,7 +39,7 @@ import {
35
39
  stateFromJSON,
36
40
  toReversed,
37
41
  union
38
- } from "./chunk-MOSGJZHV.js";
42
+ } from "./chunk-UKHJHMFE.js";
39
43
 
40
44
  // src/commands/add-mark.ts
41
45
  import "@prosekit/pm/model";
@@ -157,34 +161,31 @@ function removeMark(options) {
157
161
  }
158
162
 
159
163
  // src/utils/find-parent-node.ts
160
- function findParentNode(nodeType, $pos) {
161
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
164
+ function findParentNode(predicate, $pos) {
165
+ for (let depth = $pos.depth; depth >= 0; depth -= 1) {
162
166
  const node = $pos.node(depth);
163
- if (node.type === nodeType) {
164
- const from = $pos.before(depth);
165
- const to = $pos.after(depth);
166
- return {
167
- from,
168
- to
169
- };
167
+ if (predicate(node)) {
168
+ const pos = depth === 0 ? 0 : $pos.before(depth);
169
+ const start = $pos.start(depth);
170
+ return { node, pos, start, depth };
170
171
  }
171
172
  }
172
- return {
173
- from: null,
174
- to: null
175
- };
173
+ }
174
+
175
+ // src/utils/find-parent-node-of-type.ts
176
+ function findParentNodeOfType(type, $pos) {
177
+ const nodeType = getNodeType($pos.doc.type.schema, type);
178
+ return findParentNode((node) => node.type === nodeType, $pos);
176
179
  }
177
180
 
178
181
  // src/commands/remove-node.ts
179
182
  function removeNode(options) {
180
183
  return (state, dispatch) => {
181
- const nodeType = getNodeType(state.schema, options.type);
182
184
  const $pos = typeof options.pos === "number" ? state.doc.resolve(options.pos) : state.selection.$anchor;
183
- const { from, to } = findParentNode(nodeType, $pos);
184
- if (from == null || to == null || from > to) {
185
- return false;
186
- }
187
- dispatch == null ? void 0 : dispatch(state.tr.delete(from, to));
185
+ const found = findParentNodeOfType(options.type, $pos);
186
+ if (!found) return false;
187
+ const { pos, node } = found;
188
+ dispatch == null ? void 0 : dispatch(state.tr.delete(pos, pos + node.nodeSize));
188
189
  return true;
189
190
  };
190
191
  }
@@ -282,77 +283,18 @@ function setNodeAttrs(options) {
282
283
  }
283
284
 
284
285
  // src/commands/toggle-mark.ts
286
+ import { toggleMark as baseToggleMark } from "@prosekit/pm/commands";
285
287
  import "@prosekit/pm/model";
286
- import "@prosekit/pm/state";
287
- function markApplies(doc, ranges, type) {
288
- for (const { $from, $to } of ranges) {
289
- let can = $from.depth == 0 ? doc.inlineContent && doc.type.allowsMarkType(type) : false;
290
- doc.nodesBetween($from.pos, $to.pos, (node) => {
291
- if (can) return false;
292
- can = node.inlineContent && node.type.allowsMarkType(type);
293
- });
294
- if (can) return true;
295
- }
296
- return false;
297
- }
298
- function baseToggleMark(markType, attrs = null, options) {
299
- const removeWhenPresent = (options && options.removeWhenPresent) !== false;
300
- return function(state, dispatch) {
301
- const { empty, $cursor, ranges } = state.selection;
302
- if (empty && !$cursor || !markApplies(state.doc, ranges, markType))
303
- return false;
304
- if (dispatch) {
305
- if ($cursor) {
306
- if (markType.isInSet(state.storedMarks || $cursor.marks()))
307
- dispatch(state.tr.removeStoredMark(markType));
308
- else dispatch(state.tr.addStoredMark(markType.create(attrs)));
309
- } else {
310
- let add;
311
- const tr = state.tr;
312
- if (removeWhenPresent) {
313
- add = !ranges.some(
314
- (r) => state.doc.rangeHasMark(r.$from.pos, r.$to.pos, markType)
315
- );
316
- } else {
317
- add = !ranges.every((r) => {
318
- let missing = false;
319
- tr.doc.nodesBetween(r.$from.pos, r.$to.pos, (node, pos, parent) => {
320
- if (missing) return false;
321
- missing = !markType.isInSet(node.marks) && !!parent && parent.type.allowsMarkType(markType) && !(node.isText && /^\s*$/.test(
322
- node.textBetween(
323
- Math.max(0, r.$from.pos - pos),
324
- Math.min(node.nodeSize, r.$to.pos - pos)
325
- )
326
- ));
327
- });
328
- return !missing;
329
- });
330
- }
331
- for (const { $from, $to } of ranges) {
332
- if (!add) {
333
- tr.removeMark($from.pos, $to.pos, markType);
334
- } else {
335
- let from = $from.pos, to = $to.pos;
336
- const start = $from.nodeAfter, end = $to.nodeBefore;
337
- const spaceStart = start && start.isText ? /^\s*/.exec(start.text)[0].length : 0;
338
- const spaceEnd = end && end.isText ? /\s*$/.exec(end.text)[0].length : 0;
339
- if (from + spaceStart < to) {
340
- from += spaceStart;
341
- to -= spaceEnd;
342
- }
343
- tr.addMark(from, to, markType.create(attrs));
344
- }
345
- }
346
- dispatch(tr.scrollIntoView());
347
- }
348
- }
349
- return true;
350
- };
351
- }
352
- function toggleMark({ type, attrs }) {
288
+ function toggleMark({
289
+ type,
290
+ attrs,
291
+ removeWhenPresent = false,
292
+ enterInlineAtoms = true
293
+ }) {
353
294
  return (state, dispatch, view) => {
354
295
  return baseToggleMark(getMarkType(state.schema, type), attrs, {
355
- removeWhenPresent: false
296
+ removeWhenPresent,
297
+ enterInlineAtoms
356
298
  })(state, dispatch, view);
357
299
  };
358
300
  }
@@ -433,12 +375,13 @@ function unsetMark(options) {
433
375
  // src/commands/wrap.ts
434
376
  import "@prosekit/pm/model";
435
377
  import { findWrapping } from "@prosekit/pm/transform";
436
- function wrap({ nodeType, attrs }) {
378
+ function wrap(options) {
437
379
  return (state, dispatch) => {
438
380
  const { $from, $to } = state.selection;
439
381
  const range = $from.blockRange($to);
440
382
  if (!range) return false;
441
- const wrapping = findWrapping(range, nodeType, attrs);
383
+ const nodeType = getNodeType(state.schema, options.type || options.nodeType);
384
+ const wrapping = findWrapping(range, nodeType, options.attrs);
442
385
  if (!wrapping) return false;
443
386
  dispatch == null ? void 0 : dispatch(state.tr.wrap(range, wrapping));
444
387
  return true;
@@ -502,6 +445,7 @@ function defineBaseCommands() {
502
445
  }
503
446
 
504
447
  // src/extensions/node-spec.ts
448
+ import clone from "just-clone";
505
449
  import OrderedMap2 from "orderedmap";
506
450
 
507
451
  // src/facets/schema-spec.ts
@@ -524,10 +468,137 @@ var schemaSpecFacet = defineFacet({
524
468
  singleton: true
525
469
  });
526
470
 
527
- // src/utils/is-element.ts
528
- var hasElement = typeof Element !== "undefined";
529
- function isElement(value) {
530
- return hasElement && value instanceof Element;
471
+ // src/utils/array-grouping.ts
472
+ function groupBy(items, keySelector) {
473
+ const result = {};
474
+ for (const item of items) {
475
+ const key = keySelector(item);
476
+ const values = result[key] || (result[key] = []);
477
+ values.push(item);
478
+ }
479
+ return result;
480
+ }
481
+ function groupEntries(entries) {
482
+ const result = {};
483
+ for (const [key, value] of entries) {
484
+ const values = result[key] || (result[key] = []);
485
+ values.push(value);
486
+ }
487
+ return result;
488
+ }
489
+
490
+ // src/utils/remove-undefined-values.ts
491
+ function removeUndefinedValues(obj) {
492
+ const result = {};
493
+ for (const [key, value] of Object.entries(obj)) {
494
+ if (value !== void 0) {
495
+ result[key] = value;
496
+ }
497
+ }
498
+ return result;
499
+ }
500
+
501
+ // src/utils/merge-objects.ts
502
+ function mergeObjects(...objects) {
503
+ const filteredObjects = objects.filter(isNotNullish).map(removeUndefinedValues);
504
+ return Object.assign({}, ...filteredObjects);
505
+ }
506
+
507
+ // src/utils/merge-specs.ts
508
+ function mergeSpecs(a, b) {
509
+ var _a, _b, _c, _d, _e, _f;
510
+ const attrs = {};
511
+ const attrNames = /* @__PURE__ */ new Set([
512
+ ...Object.keys((_a = a.attrs) != null ? _a : {}),
513
+ ...Object.keys((_b = b.attrs) != null ? _b : {})
514
+ ]);
515
+ for (const name of attrNames) {
516
+ const attrSpecA = (_c = a.attrs) == null ? void 0 : _c[name];
517
+ const attrSpecB = (_d = b.attrs) == null ? void 0 : _d[name];
518
+ const attrSpecMerged = mergeObjects(attrSpecA, attrSpecB);
519
+ if (attrSpecMerged) {
520
+ attrs[name] = attrSpecMerged;
521
+ }
522
+ }
523
+ const parseDOM = [...(_e = a.parseDOM) != null ? _e : [], ...(_f = b.parseDOM) != null ? _f : []];
524
+ return mergeObjects(a, b, { attrs, parseDOM });
525
+ }
526
+
527
+ // src/utils/output-spec.ts
528
+ function wrapOutputSpecAttrs(toDOM, options) {
529
+ return (node, ...args) => {
530
+ const dom = toDOM(node, ...args);
531
+ const pairs = options.map((option) => {
532
+ var _a;
533
+ return (_a = option.toDOM) == null ? void 0 : _a.call(option, node.attrs[option.attr]);
534
+ }).filter(isNotNullish);
535
+ return insertOutputSpecAttrs(dom, pairs);
536
+ };
537
+ }
538
+ function wrapTagParseRuleAttrs(rule, options) {
539
+ const existingGetAttrs = rule.getAttrs;
540
+ const existingAttrs = rule.attrs;
541
+ return {
542
+ ...rule,
543
+ getAttrs: (dom) => {
544
+ var _a, _b;
545
+ const baseAttrs = (_b = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs) != null ? _b : {};
546
+ if (baseAttrs === false || !dom || !isElement(dom)) {
547
+ return baseAttrs != null ? baseAttrs : null;
548
+ }
549
+ const insertedAttrs = {};
550
+ for (const option of options) {
551
+ if (option.parseDOM) {
552
+ insertedAttrs[option.attr] = option.parseDOM(dom);
553
+ }
554
+ }
555
+ return { ...baseAttrs, ...insertedAttrs };
556
+ }
557
+ };
558
+ }
559
+ function insertOutputSpecAttrs(dom, attrs) {
560
+ if (!dom) {
561
+ return dom;
562
+ }
563
+ if (Array.isArray(dom)) {
564
+ const rest = dom.slice(1);
565
+ let oldAttrs;
566
+ if (rest.length > 0 && (rest[0] == null || typeof rest[0] === "object")) {
567
+ oldAttrs = rest.shift();
568
+ } else {
569
+ oldAttrs = {};
570
+ }
571
+ const newAttrs = setObjectAttributes(oldAttrs, attrs);
572
+ return [dom[0], newAttrs, ...rest];
573
+ }
574
+ if (isElement(dom)) {
575
+ return setElementAttributes(dom, attrs);
576
+ }
577
+ if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
578
+ return { ...dom, dom: setElementAttributes(dom.dom, attrs) };
579
+ }
580
+ return dom;
581
+ }
582
+ function setObjectAttributes(obj, attrs) {
583
+ obj = { ...obj };
584
+ for (const [key, value] of attrs) {
585
+ const oldValue = obj[key];
586
+ const newValue = key === "style" ? joinStyles(value, typeof oldValue === "string" ? oldValue : "") : value;
587
+ obj[key] = newValue;
588
+ }
589
+ return obj;
590
+ }
591
+ function setElementAttributes(element, attrs) {
592
+ element = element.cloneNode(true);
593
+ for (const [key, value] of attrs) {
594
+ const oldValue = element.getAttribute(key);
595
+ const newValue = key === "style" ? joinStyles(value, typeof oldValue === "string" ? oldValue : "") : value;
596
+ element.setAttribute(key, newValue);
597
+ }
598
+ return element;
599
+ }
600
+ function joinStyles(...styles) {
601
+ return styles.map((style) => style.trim().replace(/;$/, "")).filter(Boolean).join("; ");
531
602
  }
532
603
 
533
604
  // src/extensions/node-spec.ts
@@ -543,105 +614,50 @@ var nodeSpecFacet = defineFacet({
543
614
  reducer: (payloads) => {
544
615
  let specs = OrderedMap2.from({});
545
616
  let topNodeName = void 0;
546
- const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
547
- const attrPayloads = payloads.map((input) => input[1]).filter(isNotNull);
617
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNullish);
618
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNullish);
548
619
  for (const { name, topNode, ...spec } of specPayloads) {
549
- assert(!specs.get(name), `Node type ${name} can only be defined once`);
550
620
  if (topNode) {
551
621
  topNodeName = name;
552
622
  }
553
- specs = specs.addToStart(name, spec);
623
+ const prevSpec = specs.get(name);
624
+ if (prevSpec) {
625
+ specs = specs.update(name, mergeSpecs(prevSpec, spec));
626
+ } else {
627
+ specs = specs.addToStart(name, spec);
628
+ }
554
629
  }
555
- for (const {
556
- type,
557
- attr,
558
- default: defaultValue,
559
- splittable,
560
- toDOM,
561
- parseDOM
562
- } of attrPayloads) {
563
- const spec = specs.get(type);
564
- assert(spec, `Node type ${type} must be defined`);
630
+ const groupedAttrs = groupBy(attrPayloads, (payload) => payload.type);
631
+ for (const [type, attrs] of Object.entries(groupedAttrs)) {
632
+ if (!attrs) continue;
633
+ const maybeSpec = specs.get(type);
634
+ assert(maybeSpec, `Node type ${type} must be defined`);
635
+ const spec = clone(maybeSpec);
565
636
  if (!spec.attrs) {
566
637
  spec.attrs = {};
567
638
  }
568
- spec.attrs[attr] = {
569
- default: defaultValue,
570
- splittable
571
- };
572
- if (toDOM && spec.toDOM) {
573
- const existingToDom = spec.toDOM;
574
- spec.toDOM = (node) => {
575
- const dom = existingToDom(node);
576
- if (!dom) {
577
- return dom;
578
- }
579
- const attrDOM = toDOM(node.attrs[attr]);
580
- if (!attrDOM) {
581
- return dom;
582
- }
583
- const [key, value] = attrDOM;
584
- if (!key) {
585
- return dom;
586
- }
587
- if (Array.isArray(dom)) {
588
- if (typeof dom[1] === "object") {
589
- return [
590
- dom[0],
591
- setObjectAttribute(
592
- dom[1],
593
- key,
594
- value
595
- ),
596
- ...dom.slice(2)
597
- ];
598
- } else {
599
- return [dom[0], { [key]: value }, ...dom.slice(1)];
600
- }
601
- } else if (isElement(dom)) {
602
- setElementAttribute(dom, key, value);
603
- } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
604
- setElementAttribute(dom.dom, key, value);
605
- }
606
- return dom;
639
+ for (const attr of attrs) {
640
+ spec.attrs[attr.attr] = {
641
+ default: attr.default,
642
+ validate: attr.validate,
643
+ splittable: attr.splittable
607
644
  };
608
645
  }
609
- if (parseDOM && spec.parseDOM) {
610
- for (const rule of spec.parseDOM) {
611
- const existingGetAttrs = rule.getAttrs;
612
- const existingAttrs = rule.attrs;
613
- rule.getAttrs = (dom) => {
614
- var _a;
615
- const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
616
- if (attrs === false || !dom || !isElement(dom)) {
617
- return attrs != null ? attrs : null;
618
- }
619
- const value = parseDOM(dom);
620
- return {
621
- ...attrs,
622
- [attr]: value
623
- };
624
- };
625
- }
646
+ if (spec.toDOM) {
647
+ spec.toDOM = wrapOutputSpecAttrs(spec.toDOM, attrs);
648
+ }
649
+ if (spec.parseDOM) {
650
+ spec.parseDOM = spec.parseDOM.map(
651
+ (rule) => wrapTagParseRuleAttrs(rule, attrs)
652
+ );
626
653
  }
654
+ specs = specs.update(type, spec);
627
655
  }
628
656
  return { nodes: specs, topNode: topNodeName };
629
657
  },
630
658
  parent: schemaSpecFacet,
631
659
  singleton: true
632
660
  });
633
- function setObjectAttribute(obj, key, value) {
634
- if (key === "style") {
635
- value = `${value}${obj.style || ""}`;
636
- }
637
- return { ...obj, [key]: value };
638
- }
639
- function setElementAttribute(element, key, value) {
640
- if (key === "style") {
641
- value = `${value}${element.getAttribute("style") || ""}`;
642
- }
643
- element.setAttribute(key, value);
644
- }
645
661
 
646
662
  // src/extensions/doc.ts
647
663
  function defineDoc() {
@@ -781,20 +797,6 @@ function combineEventHandlers() {
781
797
  return [setHandlers, combinedEventHandler];
782
798
  }
783
799
 
784
- // src/utils/group-entries.ts
785
- function groupEntries(entries) {
786
- const map = {};
787
- for (const [key, value] of entries) {
788
- const values = map[key];
789
- if (!values) {
790
- map[key] = [value];
791
- } else {
792
- values.push(value);
793
- }
794
- }
795
- return map;
796
- }
797
-
798
800
  // src/extensions/events/dom-event.ts
799
801
  function defineDOMEventHandler(event, handler) {
800
802
  return defineFacetPayload(domEventFacet, [
@@ -959,6 +961,7 @@ var isApple = typeof navigator !== "undefined" ? /Mac|iP(hone|[ao]d)/.test(navig
959
961
  import { chainCommands } from "@prosekit/pm/commands";
960
962
  import { keydownHandler } from "@prosekit/pm/keymap";
961
963
  import { Plugin as Plugin2, PluginKey as PluginKey4 } from "@prosekit/pm/state";
964
+ import mapValues from "just-map-values";
962
965
  function defineKeymap(keymap2) {
963
966
  return defineFacetPayload(keymapFacet, [keymap2]);
964
967
  }
@@ -994,12 +997,10 @@ function mergeKeymaps(keymaps) {
994
997
  commands2.push(command);
995
998
  }
996
999
  }
997
- return Object.fromEntries(
998
- Object.entries(bindings).map(([key, commands2]) => [
999
- key,
1000
- chainCommands(...commands2)
1001
- ])
1002
- );
1000
+ return mapValues(bindings, mergeCommands);
1001
+ }
1002
+ function mergeCommands(commands2) {
1003
+ return chainCommands(...commands2);
1003
1004
  }
1004
1005
  var keymapPluginKey = new PluginKey4("prosekit-keymap");
1005
1006
 
@@ -1064,6 +1065,7 @@ function defineBaseKeymap(options) {
1064
1065
  }
1065
1066
 
1066
1067
  // src/extensions/mark-spec.ts
1068
+ import clone2 from "just-clone";
1067
1069
  import OrderedMap3 from "orderedmap";
1068
1070
  function defineMarkSpec(options) {
1069
1071
  const payload = [options, void 0];
@@ -1076,78 +1078,52 @@ function defineMarkAttr(options) {
1076
1078
  var markSpecFacet = defineFacet({
1077
1079
  reducer: (payloads) => {
1078
1080
  let specs = OrderedMap3.from({});
1079
- const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
1080
- const attrPayloads = payloads.map((input) => input[1]).filter(isNotNull);
1081
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNullish);
1082
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNullish);
1081
1083
  for (const { name, ...spec } of specPayloads) {
1082
- assert(!specs.get(name), `Mark type ${name} can only be defined once`);
1083
- specs = specs.addToStart(name, spec);
1084
+ const prevSpec = specs.get(name);
1085
+ if (prevSpec) {
1086
+ specs = specs.update(name, mergeSpecs(prevSpec, spec));
1087
+ } else {
1088
+ specs = specs.addToStart(name, spec);
1089
+ }
1084
1090
  }
1085
- for (const {
1086
- type,
1087
- attr,
1088
- default: defaultValue,
1089
- toDOM,
1090
- parseDOM
1091
- } of attrPayloads) {
1092
- const spec = specs.get(type);
1093
- assert(spec, `Mark type ${type} must be defined`);
1091
+ const groupedAttrs = groupBy(attrPayloads, (payload) => payload.type);
1092
+ for (const [type, attrs] of Object.entries(groupedAttrs)) {
1093
+ if (!attrs) continue;
1094
+ const maybeSpec = specs.get(type);
1095
+ assert(maybeSpec, `Mark type ${type} must be defined`);
1096
+ const spec = clone2(maybeSpec);
1094
1097
  if (!spec.attrs) {
1095
1098
  spec.attrs = {};
1096
1099
  }
1097
- spec.attrs[attr] = { default: defaultValue };
1098
- if (toDOM && spec.toDOM) {
1099
- const existingToDom = spec.toDOM;
1100
- spec.toDOM = (mark, inline) => {
1101
- const dom = existingToDom(mark, inline);
1102
- if (!dom) {
1103
- return dom;
1104
- }
1105
- const attrDOM = toDOM(mark.attrs[attr]);
1106
- if (!attrDOM) {
1107
- return dom;
1108
- }
1109
- const [key, value] = attrDOM;
1110
- if (!key) {
1111
- return dom;
1112
- }
1113
- if (Array.isArray(dom)) {
1114
- if (typeof dom[1] === "object") {
1115
- return [dom[0], { ...dom[1], [key]: value }, ...dom.slice(2)];
1116
- } else {
1117
- return [dom[0], { [key]: value }, ...dom.slice(1)];
1118
- }
1119
- } else if (isElement(dom)) {
1120
- dom.setAttribute(key, value);
1121
- } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
1122
- dom.dom.setAttribute(key, value);
1123
- }
1124
- return dom;
1100
+ for (const attr of attrs) {
1101
+ spec.attrs[attr.attr] = {
1102
+ default: attr.default,
1103
+ validate: attr.validate
1125
1104
  };
1126
1105
  }
1127
- if (parseDOM && spec.parseDOM) {
1128
- for (const rule of spec.parseDOM) {
1129
- const existingGetAttrs = rule.getAttrs;
1130
- const existingAttrs = rule.attrs;
1131
- rule.getAttrs = (dom) => {
1132
- var _a;
1133
- const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
1134
- if (attrs === false || !dom || !isElement(dom)) {
1135
- return attrs != null ? attrs : null;
1136
- }
1137
- const value = parseDOM(dom);
1138
- return {
1139
- ...attrs,
1140
- [attr]: value
1141
- };
1142
- };
1143
- }
1106
+ if (spec.toDOM) {
1107
+ spec.toDOM = wrapOutputSpecAttrs(spec.toDOM, attrs);
1108
+ }
1109
+ if (spec.parseDOM) {
1110
+ spec.parseDOM = spec.parseDOM.map(
1111
+ (rule) => wrapParseRuleAttrs(rule, attrs)
1112
+ );
1144
1113
  }
1114
+ specs = specs.update(type, spec);
1145
1115
  }
1146
1116
  return { marks: specs, nodes: {} };
1147
1117
  },
1148
1118
  parent: schemaSpecFacet,
1149
1119
  singleton: true
1150
1120
  });
1121
+ function wrapParseRuleAttrs(rule, attrs) {
1122
+ if (rule.tag) {
1123
+ return wrapTagParseRuleAttrs(rule, attrs);
1124
+ }
1125
+ return rule;
1126
+ }
1151
1127
 
1152
1128
  // src/extensions/node-view.ts
1153
1129
  import { PluginKey as PluginKey5, ProseMirrorPlugin as ProseMirrorPlugin5 } from "@prosekit/pm/state";
@@ -1187,8 +1163,8 @@ var nodeViewFactoryFacet = defineFacet({
1187
1163
  reducer: (inputs) => {
1188
1164
  if (isServer) return [];
1189
1165
  const nodeViews = {};
1190
- const factories = inputs.map((x) => x[0]).filter(isNotNull);
1191
- const options = inputs.map((x) => x[1]).filter(isNotNull);
1166
+ const factories = inputs.map((x) => x[0]).filter(isNotNullish);
1167
+ const options = inputs.map((x) => x[1]).filter(isNotNullish);
1192
1168
  for (const { group, name, args } of options) {
1193
1169
  const factory = factories.find((factory2) => factory2.group === group);
1194
1170
  if (!factory) continue;
@@ -1252,6 +1228,16 @@ var canUseRegexLookbehind = cache(() => {
1252
1228
  import clsxLite from "clsx/lite";
1253
1229
  var clsx = clsxLite;
1254
1230
 
1231
+ // src/utils/collect-children.ts
1232
+ import "@prosekit/pm/model";
1233
+ function collectChildren(parent) {
1234
+ const children = [];
1235
+ for (let i = 0; i < parent.childCount; i++) {
1236
+ children.push(parent.child(i));
1237
+ }
1238
+ return children;
1239
+ }
1240
+
1255
1241
  // src/utils/collect-nodes.ts
1256
1242
  import { ProseMirrorFragment, ProseMirrorNode as ProseMirrorNode2 } from "@prosekit/pm/model";
1257
1243
  function collectNodes(content) {
@@ -1341,6 +1327,7 @@ export {
1341
1327
  assert,
1342
1328
  canUseRegexLookbehind,
1343
1329
  clsx,
1330
+ collectChildren,
1344
1331
  collectNodes,
1345
1332
  containsInlineNode,
1346
1333
  createEditor,
@@ -1385,6 +1372,8 @@ export {
1385
1372
  elementFromJSON,
1386
1373
  elementFromNode,
1387
1374
  expandMark,
1375
+ findParentNode,
1376
+ findParentNodeOfType,
1388
1377
  getMarkType,
1389
1378
  getNodeType,
1390
1379
  htmlFromJSON,
@@ -1393,12 +1382,15 @@ export {
1393
1382
  isAllSelection,
1394
1383
  isApple,
1395
1384
  isAtBlockStart,
1385
+ isFragment,
1396
1386
  isInCodeBlock,
1397
1387
  isMark,
1398
1388
  isMarkAbsent,
1399
1389
  isMarkActive,
1400
1390
  isNodeSelection,
1401
1391
  isProseMirrorNode,
1392
+ isSelection,
1393
+ isSlice,
1402
1394
  isTextSelection,
1403
1395
  jsonFromHTML,
1404
1396
  jsonFromNode,