@prosekit/core 0.7.7 → 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.
@@ -5,11 +5,13 @@ import type { ContentMatch } from '@prosekit/pm/model';
5
5
  import { config as default_alias_1 } from '@prosekit/dev/config-vitest';
6
6
  import type { DirectEditorProps } from '@prosekit/pm/view';
7
7
  import type { DOMEventMap } from '@prosekit/pm/view';
8
+ import type { DOMOutputSpec } from '@prosekit/pm/model';
8
9
  import { DOMParser as DOMParser_2 } from '@prosekit/pm/model';
9
10
  import { DOMSerializer } from '@prosekit/pm/model';
10
11
  import { EditorState } from '@prosekit/pm/state';
11
12
  import type { EditorStateConfig } from '@prosekit/pm/state';
12
13
  import { EditorView } from '@prosekit/pm/view';
14
+ import { Fragment } from '@prosekit/pm/model';
13
15
  import type { IsEqual } from 'type-fest';
14
16
  import { Mark } from '@prosekit/pm/model';
15
17
  import type { MarkSpec } from '@prosekit/pm/model';
@@ -32,7 +34,8 @@ import { SchemaSpec } from '@prosekit/pm/model';
32
34
  import { Selection as Selection_2 } from '@prosekit/pm/state';
33
35
  import { Selection as Selection_3 } from 'prosemirror-state';
34
36
  import type { Simplify } from 'type-fest';
35
- import type { Slice } from '@prosekit/pm/model';
37
+ import { Slice } from '@prosekit/pm/model';
38
+ import type { TagParseRule } from '@prosekit/pm/model';
36
39
  import { TextSelection } from '@prosekit/pm/state';
37
40
  import { Transaction } from '@prosekit/pm/state';
38
41
  import type { UnionToIntersection } from 'type-fest';
@@ -120,6 +123,12 @@ export declare function assertTypeEqual<T, U>(_val: IsEqual<T, U>): void;
120
123
  */
121
124
  export declare function assertTypeEqual_alias_1<T, U>(_val: IsEqual<T, U>): void;
122
125
 
126
+ declare interface AttrOptions {
127
+ attr: string;
128
+ toDOM?: (value: unknown) => [key: string, value: string] | null | undefined;
129
+ parseDOM?: (node: HTMLElement) => unknown;
130
+ }
131
+
123
132
  export declare function attrsMatch(nodeOrMark: ProseMirrorNode | Mark, attrs: Attrs): boolean;
124
133
 
125
134
  /**
@@ -224,10 +233,6 @@ declare interface BaseNodeViewOptions {
224
233
  export { BaseNodeViewOptions }
225
234
  export { BaseNodeViewOptions as BaseNodeViewOptions_alias_1 }
226
235
 
227
- export declare function baseToggleMark(markType: MarkType, attrs?: Attrs | null, options?: {
228
- removeWhenPresent: boolean;
229
- }): Command;
230
-
231
236
  declare type BoldExtension = Extension<{
232
237
  Marks: {
233
238
  bold: Attrs;
@@ -269,9 +274,20 @@ declare type CodeBlockExtension = Extension<{
269
274
  };
270
275
  }>;
271
276
 
277
+ /**
278
+ * Collects all children of a node or a fragment, and returns them as an array.
279
+ *
280
+ * @public
281
+ */
282
+ declare function collectChildren(parent: ProseMirrorNode | Fragment): ProseMirrorNode[];
283
+ export { collectChildren }
284
+ export { collectChildren as collectChildren_alias_1 }
285
+
272
286
  /**
273
287
  * Collects all nodes from a given content.
274
288
  *
289
+ * @deprecated Use `collectChildren` instead.
290
+ *
275
291
  * @public
276
292
  */
277
293
  declare function collectNodes(content: NodeContent): ProseMirrorNode[];
@@ -389,7 +405,7 @@ declare interface DefaultStateOptions {
389
405
  defaultHTML?: string | HTMLElement;
390
406
  /**
391
407
  * A JSON object representing the starting selection to use when creating the
392
- * editor. It's only used when `defaultDoc` or `defaultHTML` is also provided.
408
+ * editor. It's only used when `defaultContent` is also provided.
393
409
  */
394
410
  defaultSelection?: SelectionJSON;
395
411
  }
@@ -450,9 +466,11 @@ export { defineCommands as defineCommands_alias_1 }
450
466
  /**
451
467
  * Define a default state for the editor.
452
468
  *
469
+ * @param options
470
+ *
453
471
  * @public
454
472
  */
455
- declare function defineDefaultState(options: DefaultStateOptions): PlainExtension;
473
+ declare function defineDefaultState({ defaultSelection, defaultContent, defaultDoc, defaultHTML, }: DefaultStateOptions): PlainExtension;
456
474
  export { defineDefaultState }
457
475
  export { defineDefaultState as defineDefaultState_alias_1 }
458
476
 
@@ -554,6 +572,8 @@ export { defineFocusChangeHandler as defineFocusChangeHandler_alias_1 }
554
572
  /**
555
573
  * Add undo/redo history to the editor.
556
574
  *
575
+ * @param options
576
+ *
557
577
  * @public
558
578
  */
559
579
  declare function defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtension;
@@ -1017,7 +1037,7 @@ declare interface EditorOptions<E extends Extension> {
1017
1037
  defaultHTML?: string | HTMLElement;
1018
1038
  /**
1019
1039
  * A JSON object representing the starting selection to use when creating the
1020
- * editor. It's only used when `defaultDoc` or `defaultHTML` is also provided.
1040
+ * editor. It's only used when `defaultContent` is also provided.
1021
1041
  */
1022
1042
  defaultSelection?: SelectionJSON;
1023
1043
  }
@@ -1252,10 +1272,63 @@ export declare function findBrowserWindow(options?: {
1252
1272
  document?: Document;
1253
1273
  }): (Window & typeof globalThis) | null | undefined;
1254
1274
 
1255
- export declare function findParentNode(nodeType: NodeType, $pos: ResolvedPos): {
1256
- from: number | null;
1257
- to: number | null;
1258
- };
1275
+ /**
1276
+ * Find the closest parent node that satisfies the predicate.
1277
+ *
1278
+ * @public
1279
+ */
1280
+ declare function findParentNode(
1281
+ /**
1282
+ * The predicate to test the parent node.
1283
+ */
1284
+ predicate: (node: ProseMirrorNode) => boolean,
1285
+ /**
1286
+ * The position to start searching from.
1287
+ */
1288
+ $pos: ResolvedPos): FindParentNodeResult | undefined;
1289
+ export { findParentNode }
1290
+ export { findParentNode as findParentNode_alias_1 }
1291
+
1292
+ /**
1293
+ * Finds the closest parent node that matches the given node type.
1294
+ *
1295
+ * @public
1296
+ */
1297
+ declare function findParentNodeOfType(
1298
+ /**
1299
+ * The type of the node to remove.
1300
+ */
1301
+ type: NodeType | string,
1302
+ /**
1303
+ * The position to start searching from.
1304
+ */
1305
+ $pos: ResolvedPos): FindParentNodeResult | undefined;
1306
+ export { findParentNodeOfType }
1307
+ export { findParentNodeOfType as findParentNodeOfType_alias_1 }
1308
+
1309
+ /**
1310
+ * @public
1311
+ */
1312
+ declare interface FindParentNodeResult {
1313
+ /**
1314
+ * The closest parent node that satisfies the predicate.
1315
+ */
1316
+ node: ProseMirrorNode;
1317
+ /**
1318
+ * The position directly before the node.
1319
+ */
1320
+ pos: number;
1321
+ /**
1322
+ * The position at the start of the node.
1323
+ */
1324
+ start: number;
1325
+ /**
1326
+ * The depth of the node.
1327
+ */
1328
+ depth: number;
1329
+ }
1330
+ export { FindParentNodeResult }
1331
+ export { FindParentNodeResult as FindParentNodeResult_alias_1 }
1259
1332
 
1260
1333
  /**
1261
1334
  * A function that is called when the editor gains or loses focus.
@@ -1316,12 +1389,12 @@ export declare function getNodeTypes(schema: Schema, types: string | NodeType |
1316
1389
 
1317
1390
  declare type GetStateFunction = () => EditorState | null | undefined;
1318
1391
 
1319
- export declare type GroupedEntries<T extends Record<string, any>> = {
1392
+ export declare function groupBy<K extends PropertyKey, T>(items: Iterable<T>, keySelector: (item: T) => K): Partial<Record<K, T[]>>;
1393
+
1394
+ export declare function groupEntries<T extends Record<string, any>>(entries: ObjectEntries<T>[]): {
1320
1395
  [K in keyof T]?: T[K][];
1321
1396
  };
1322
1397
 
1323
- export declare function groupEntries<T extends Record<string, any>>(entries: ObjectEntries<T>[]): GroupedEntries<T>;
1324
-
1325
1398
  declare type HeadingExtension = Extension<{
1326
1399
  Nodes: {
1327
1400
  heading: Attrs;
@@ -1429,6 +1502,8 @@ declare interface InsertNodeOptions {
1429
1502
  export { InsertNodeOptions }
1430
1503
  export { InsertNodeOptions as InsertNodeOptions_alias_1 }
1431
1504
 
1505
+ export declare function insertOutputSpecAttrs(dom: DOMOutputSpec, attrs: Array<[key: string, value: string]>): DOMOutputSpec;
1506
+
1432
1507
  /**
1433
1508
  * Returns a command that inserts the given text.
1434
1509
  *
@@ -1446,7 +1521,9 @@ export declare type InsertTextOptions = {
1446
1521
  };
1447
1522
 
1448
1523
  /**
1449
- * @internal
1524
+ * Checks if the given object is a `AllSelection` instance.
1525
+ *
1526
+ * @public
1450
1527
  */
1451
1528
  declare function isAllSelection(sel: Selection_2): sel is AllSelection;
1452
1529
  export { isAllSelection }
@@ -1470,6 +1547,15 @@ export { isAtBlockStart as isAtBlockStart_alias_1 }
1470
1547
 
1471
1548
  export declare function isElement(el: unknown): el is Element;
1472
1549
 
1550
+ /**
1551
+ * Checks if the given object is a `Fragment` instance.
1552
+ *
1553
+ * @public
1554
+ */
1555
+ declare function isFragment(fragment: unknown): fragment is Fragment;
1556
+ export { isFragment }
1557
+ export { isFragment as isFragment_alias_1 }
1558
+
1473
1559
  /**
1474
1560
  * Check if the selection is in a code block.
1475
1561
  *
@@ -1480,7 +1566,9 @@ export { isInCodeBlock }
1480
1566
  export { isInCodeBlock as isInCodeBlock_alias_1 }
1481
1567
 
1482
1568
  /**
1483
- * @internal
1569
+ * Checks if the given object is a `Mark` instance.
1570
+ *
1571
+ * @public
1484
1572
  */
1485
1573
  declare function isMark(mark: unknown): mark is Mark;
1486
1574
  export { isMark }
@@ -1507,30 +1595,46 @@ export { isMarkActive as isMarkActive_alias_1 }
1507
1595
  export declare function isNodeActive(state: EditorState, type: string | NodeType, attrs?: Attrs | null): boolean;
1508
1596
 
1509
1597
  /**
1510
- * @internal
1598
+ * Checks if the given object is a `NodeSelection` instance.
1599
+ *
1600
+ * @public
1511
1601
  */
1512
1602
  declare function isNodeSelection(sel: Selection_2): sel is NodeSelection;
1513
1603
  export { isNodeSelection }
1514
1604
  export { isNodeSelection as isNodeSelection_alias_1 }
1515
1605
 
1516
- export declare function isNotNull<T>(value: T | null | undefined): value is T;
1606
+ /**
1607
+ * @internal
1608
+ */
1609
+ export declare function isNotNullish<T>(value: T | null | undefined | void): value is T;
1517
1610
 
1518
1611
  export declare function isObject(v: unknown): v is Record<string, unknown>;
1519
1612
 
1520
1613
  /**
1521
- * @internal
1614
+ * Checks if the given object is a `ProseMirrorNode` instance.
1522
1615
  */
1523
1616
  declare function isProseMirrorNode(node: unknown): node is ProseMirrorNode;
1524
1617
  export { isProseMirrorNode }
1525
1618
  export { isProseMirrorNode as isProseMirrorNode_alias_1 }
1526
1619
 
1527
1620
  /**
1528
- * @internal
1621
+ * Checks if the given object is a `Selection` instance.
1622
+ *
1623
+ * @public
1529
1624
  */
1530
1625
  declare function isSelection(sel: unknown): sel is Selection_2;
1531
1626
  export { isSelection }
1532
1627
  export { isSelection as isSelection_alias_1 }
1533
1628
 
1629
+ /**
1630
+ * Checks if the given object is a `Slice` instance.
1631
+ *
1632
+ * @public
1633
+ */
1634
+ declare function isSlice(slice: unknown): slice is Slice;
1635
+ export { isSlice }
1636
+ export { isSlice as isSlice_alias_1 }
1637
+
1534
1638
  /**
1535
1639
  * Check if `subset` is a subset of `superset`.
1536
1640
  *
@@ -1539,7 +1643,9 @@ export { isSelection as isSelection_alias_1 }
1539
1643
  export declare function isSubset(subset: Record<string, unknown>, superset: Record<string, unknown>): boolean;
1540
1644
 
1541
1645
  /**
1542
- * @internal
1646
+ * Checks if the given object is a `TextSelection` instance.
1647
+ *
1648
+ * @public
1543
1649
  */
1544
1650
  declare function isTextSelection(sel: Selection_2): sel is TextSelection;
1545
1651
  export { isTextSelection }
@@ -1668,13 +1774,18 @@ declare interface MarkAttrOptions<MarkName extends string = string, AttrName ext
1668
1774
  */
1669
1775
  attr: AttrName;
1670
1776
  /**
1671
- * Returns the attribute key and value to be set on the DOM node.
1777
+ * Returns the attribute key and value to be set on the HTML element.
1778
+ *
1779
+ * If the returned `key` is `"style"`, the value is a string of CSS properties and will
1780
+ * be prepended to the existing `style` attribute on the DOM node.
1781
+ *
1782
+ * @param value - The value of the attribute of current ProseMirror node.
1672
1783
  */
1673
- toDOM?: (value: any) => [key: string, value: string] | null | void;
1784
+ toDOM?: (value: AttrType) => [key: string, value: string] | null | undefined;
1674
1785
  /**
1675
1786
  * Parses the attribute value from the DOM.
1676
1787
  */
1677
- parseDOM?: (node: HTMLElement) => any;
1788
+ parseDOM?: (node: HTMLElement) => AttrType;
1678
1789
  }
1679
1790
  export { MarkAttrOptions }
1680
1791
  export { MarkAttrOptions as MarkAttrOptions_alias_1 }
@@ -1720,6 +1831,12 @@ declare function maybeRun<T, R = T extends (...args: any[]) => void ? ReturnType
1720
1831
  export { maybeRun }
1721
1832
  export { maybeRun as maybeRun_alias_1 }
1722
1833
 
1834
+ export declare function mergeObjects<T extends object>(...objects: Array<Partial<T> | null | undefined>): Partial<T>;
1835
+
1836
+ export declare function mergeSpecs(a: NodeSpec, b: NodeSpec): NodeSpec;
1837
+
1838
+ export declare function mergeSpecs(a: MarkSpec, b: MarkSpec): MarkSpec;
1839
+
1723
1840
  /**
1724
1841
  * A function that is called when the editor view is mounted.
1725
1842
  *
@@ -1774,16 +1891,18 @@ declare interface NodeAttrOptions<NodeName extends string = string, AttrName ext
1774
1891
  */
1775
1892
  splittable?: boolean;
1776
1893
  /**
1777
- * Returns the attribute key and value to be set on the DOM node.
1894
+ * Returns the attribute key and value to be set on the HTML element.
1778
1895
  *
1779
- * If the `key` is `"style"`, the value is a string of CSS properties and will
1896
+ * If the returned `key` is `"style"`, the value is a string of CSS properties and will
1780
1897
  * be prepended to the existing `style` attribute on the DOM node.
1898
+ *
1899
+ * @param value - The value of the attribute of current ProseMirror node.
1781
1900
  */
1782
- toDOM?: (value: any) => [key: string, value: string] | null | void;
1901
+ toDOM?: (value: AttrType) => [key: string, value: string] | null | undefined;
1783
1902
  /**
1784
1903
  * Parses the attribute value from the DOM.
1785
1904
  */
1786
- parseDOM?: (node: HTMLElement) => any;
1905
+ parseDOM?: (node: HTMLElement) => AttrType;
1787
1906
  }
1788
1907
  export { NodeAttrOptions }
1789
1908
  export { NodeAttrOptions as NodeAttrOptions_alias_1 }
@@ -1806,6 +1925,8 @@ export { NodeChild as NodeChild_alias_1 }
1806
1925
 
1807
1926
  /**
1808
1927
  * @public
1928
+ *
1929
+ * @deprecated
1809
1930
  */
1810
1931
  declare type NodeContent = ProseMirrorNode | ProseMirrorFragment | NodeContent[];
1811
1932
  export { NodeContent }
@@ -2082,13 +2203,16 @@ declare interface RemoveNodeOptions {
2082
2203
  */
2083
2204
  type: string | NodeType;
2084
2205
  /**
2085
- * The document position to start searching node. By default it will be the anchor position of current selection.
2206
+ * The document position to start searching node. By default it will be the
2207
+ * anchor position of current selection.
2086
2208
  */
2087
2209
  pos?: number;
2088
2210
  }
2089
2211
  export { RemoveNodeOptions }
2090
2212
  export { RemoveNodeOptions as RemoveNodeOptions_alias_1 }
2091
2213
 
2214
+ export declare function removeUndefinedValues<T extends object>(obj: T): T;
2215
+
2092
2216
  export declare const rootFacet: Facet<RootPayload, RootOutput>;
2093
2217
 
2094
2218
  export declare type RootOutput = {
@@ -2383,9 +2507,11 @@ export declare type ToCommandCreators<T extends CommandTyping> = {
2383
2507
  /**
2384
2508
  * Returns a command that toggles the given mark with the given attributes.
2385
2509
  *
2510
+ * @param options
2511
+ *
2386
2512
  * @public
2387
2513
  */
2388
- declare function toggleMark({ type, attrs }: ToggleMarkOptions): Command;
2514
+ declare function toggleMark({ type, attrs, removeWhenPresent, enterInlineAtoms, }: ToggleMarkOptions): Command;
2389
2515
  export { toggleMark }
2390
2516
  export { toggleMark as toggleMark_alias_1 }
2391
2517
 
@@ -2393,8 +2519,30 @@ export { toggleMark as toggleMark_alias_1 }
2393
2519
  * @public
2394
2520
  */
2395
2521
  declare interface ToggleMarkOptions {
2522
+ /**
2523
+ * The mark type to toggle.
2524
+ */
2396
2525
  type: string | MarkType;
2526
+ /**
2527
+ * The optional attributes to set on the mark.
2528
+ */
2397
2529
  attrs?: Attrs | null;
2530
+ /**
2531
+ * Controls whether, when part of the selected range has the mark
2532
+ * already and part doesn't, the mark is removed (`true`) or added
2533
+ * (`false`).
2534
+ *
2535
+ * @default false
2536
+ */
2537
+ removeWhenPresent?: boolean;
2538
+ /**
2539
+ * Whether the command should act on the content of inline nodes marked as
2540
+ * [atoms](https://prosemirror.net/docs/ref/#model.NodeSpec.atom) that are
2541
+ * completely covered by a selection range.
2542
+ *
2543
+ * @default true
2544
+ */
2545
+ enterInlineAtoms?: boolean;
2398
2546
  }
2399
2547
  export { ToggleMarkOptions }
2400
2548
  export { ToggleMarkOptions as ToggleMarkOptions_alias_1 }
@@ -2403,6 +2551,8 @@ export { ToggleMarkOptions as ToggleMarkOptions_alias_1 }
2403
2551
  * Returns a command that set the selected textblocks to the given node type
2404
2552
  * with the given attributes.
2405
2553
  *
2554
+ * @param options
2555
+ *
2406
2556
  * @public
2407
2557
  */
2408
2558
  declare function toggleNode({ type, attrs }: ToggleNodeOptions): Command;
@@ -2633,12 +2783,13 @@ export { withSkipCodeBlock }
2633
2783
  export { withSkipCodeBlock as withSkipCodeBlock_alias_1 }
2634
2784
 
2635
2785
  /**
2636
- * Returns a command that wraps the selected textblock with the given node type
2637
- * with the given attributes.
2786
+ * Returns a command that wraps the selected textblock with the given node type.
2787
+ *
2788
+ * @param options
2638
2789
  *
2639
2790
  * @public
2640
2791
  */
2641
- declare function wrap({ nodeType, attrs }: WrapOptions): Command;
2792
+ declare function wrap(options: WrapOptions): Command;
2642
2793
  export { wrap }
2643
2794
  export { wrap as wrap_alias_1 }
2644
2795
 
@@ -2646,12 +2797,26 @@ export { wrap as wrap_alias_1 }
2646
2797
  * @public
2647
2798
  */
2648
2799
  declare interface WrapOptions {
2800
+ /**
2801
+ * The node type to wrap the selected textblock with.
2802
+ */
2803
+ type: NodeType | string;
2804
+ /**
2805
+ * @deprecated Use `nodeSpec` instead.
2806
+ */
2649
2807
  nodeType: NodeType;
2808
+ /**
2809
+ * Optional attributes to apply to the node.
2810
+ */
2650
2811
  attrs?: Attrs | null;
2651
2812
  }
2652
2813
  export { WrapOptions }
2653
2814
  export { WrapOptions as WrapOptions_alias_1 }
2654
2815
 
2816
+ export declare function wrapOutputSpecAttrs<T extends ProseMirrorNode | Mark, Args extends readonly unknown[]>(toDOM: (node: T, ...args: Args) => DOMOutputSpec, options: AttrOptions[]): (node: T, ...args: Args) => DOMOutputSpec;
2817
+
2818
+ export declare function wrapTagParseRuleAttrs(rule: TagParseRule, options: AttrOptions[]): TagParseRule;
2819
+
2655
2820
  export declare function zip<T, P>(a: T[], b: P[]): [T, P][];
2656
2821
 
2657
2822
  export { }
@@ -59,6 +59,42 @@ var Priority = /* @__PURE__ */ ((Priority2) => {
59
59
  return Priority2;
60
60
  })(Priority || {});
61
61
 
62
+ // src/utils/type-assertion.ts
63
+ import { Fragment, Mark, ProseMirrorNode, Slice } from "@prosekit/pm/model";
64
+ import {
65
+ AllSelection,
66
+ NodeSelection,
67
+ Selection,
68
+ TextSelection
69
+ } from "@prosekit/pm/state";
70
+ function isProseMirrorNode(node) {
71
+ return node instanceof ProseMirrorNode;
72
+ }
73
+ function isMark(mark) {
74
+ return mark instanceof Mark;
75
+ }
76
+ function isFragment(fragment) {
77
+ return fragment instanceof Fragment;
78
+ }
79
+ function isSlice(slice) {
80
+ return slice instanceof Slice;
81
+ }
82
+ function isSelection(sel) {
83
+ return sel instanceof Selection;
84
+ }
85
+ function isTextSelection(sel) {
86
+ return sel instanceof TextSelection;
87
+ }
88
+ function isNodeSelection(sel) {
89
+ return sel instanceof NodeSelection;
90
+ }
91
+ function isAllSelection(sel) {
92
+ return sel instanceof AllSelection;
93
+ }
94
+ function isNotNullish(value) {
95
+ return value != null;
96
+ }
97
+
62
98
  // src/facets/facet.ts
63
99
  var facetCount = 0;
64
100
  var Facet = class {
@@ -113,11 +149,6 @@ function toReversed(arr) {
113
149
  return (_b = (_a = arr.toReversed) == null ? void 0 : _a.call(arr)) != null ? _b : [...arr].reverse();
114
150
  }
115
151
 
116
- // src/utils/is-not-null.ts
117
- function isNotNull(value) {
118
- return value != null;
119
- }
120
-
121
152
  // src/facets/facet-node.ts
122
153
  function zip5(a, b, mapper) {
123
154
  return [
@@ -208,7 +239,7 @@ var FacetNode = class {
208
239
  }
209
240
  if (this.facet.singleton) {
210
241
  const reducer = (_a = this.reducers)[_b = 2 /* default */] || (_a[_b] = this.facet.reducer);
211
- const input = inputs.filter(isNotNull).flat();
242
+ const input = inputs.filter(isNotNullish).flat();
212
243
  output[2 /* default */] = reducer(input);
213
244
  } else {
214
245
  for (let pri = 0; pri < 5; pri++) {
@@ -440,33 +471,6 @@ function htmlFromJSON(json, options) {
440
471
  return htmlFromElement(elementFromJSON(json, options));
441
472
  }
442
473
 
443
- // src/utils/type-assertion.ts
444
- import { Mark, ProseMirrorNode } from "@prosekit/pm/model";
445
- import {
446
- AllSelection,
447
- NodeSelection,
448
- TextSelection,
449
- Selection
450
- } from "@prosekit/pm/state";
451
- function isProseMirrorNode(node) {
452
- return node instanceof ProseMirrorNode;
453
- }
454
- function isMark(mark) {
455
- return mark instanceof Mark;
456
- }
457
- function isSelection(sel) {
458
- return sel instanceof Selection;
459
- }
460
- function isTextSelection(sel) {
461
- return sel instanceof TextSelection;
462
- }
463
- function isNodeSelection(sel) {
464
- return sel instanceof NodeSelection;
465
- }
466
- function isAllSelection(sel) {
467
- return sel instanceof AllSelection;
468
- }
469
-
470
474
  // src/extensions/default-state.ts
471
475
  import { Selection as Selection3 } from "@prosekit/pm/state";
472
476
 
@@ -564,8 +568,12 @@ function getEditorSelection(doc, selection) {
564
568
  }
565
569
 
566
570
  // src/extensions/default-state.ts
567
- function defineDefaultState(options) {
568
- const { defaultSelection, defaultContent, defaultDoc, defaultHTML } = options;
571
+ function defineDefaultState({
572
+ defaultSelection,
573
+ defaultContent,
574
+ defaultDoc,
575
+ defaultHTML
576
+ }) {
569
577
  const defaultDocContent = defaultContent || defaultDoc || defaultHTML;
570
578
  return defineFacetPayload(stateFacet, [
571
579
  ({ schema }) => {
@@ -1105,7 +1113,15 @@ export {
1105
1113
  isNodeActive,
1106
1114
  Priority,
1107
1115
  toReversed,
1108
- isNotNull,
1116
+ isProseMirrorNode,
1117
+ isMark,
1118
+ isFragment,
1119
+ isSlice,
1120
+ isSelection,
1121
+ isTextSelection,
1122
+ isNodeSelection,
1123
+ isAllSelection,
1124
+ isNotNullish,
1109
1125
  defineFacet,
1110
1126
  rootFacet,
1111
1127
  schemaFacet,
@@ -1123,12 +1139,6 @@ export {
1123
1139
  elementFromJSON,
1124
1140
  jsonFromHTML,
1125
1141
  htmlFromJSON,
1126
- isProseMirrorNode,
1127
- isMark,
1128
- isSelection,
1129
- isTextSelection,
1130
- isNodeSelection,
1131
- isAllSelection,
1132
1142
  defineDefaultState,
1133
1143
  isMarkAbsent,
1134
1144
  isMarkActive,
@@ -6,7 +6,7 @@ import {
6
6
  createNodeActions,
7
7
  isProseMirrorNode,
8
8
  setupEditorExtension
9
- } from "./chunk-MDJ2B4IL.js";
9
+ } from "./chunk-UKHJHMFE.js";
10
10
 
11
11
  // src/test/test-editor.ts
12
12
  import { NodeSelection, TextSelection } from "@prosekit/pm/state";
@@ -142,11 +142,15 @@ export { SimplifyUnion } from './_tsup-dts-rollup';
142
142
  export { assert } from './_tsup-dts-rollup';
143
143
  export { canUseRegexLookbehind } from './_tsup-dts-rollup';
144
144
  export { clsx } from './_tsup-dts-rollup';
145
+ export { collectChildren } from './_tsup-dts-rollup';
145
146
  export { collectNodes } from './_tsup-dts-rollup';
146
147
  export { NodeContent } from './_tsup-dts-rollup';
147
148
  export { containsInlineNode } from './_tsup-dts-rollup';
148
149
  export { defaultBlockAt } from './_tsup-dts-rollup';
149
150
  export { isApple } from './_tsup-dts-rollup';
151
+ export { findParentNode } from './_tsup-dts-rollup';
152
+ export { FindParentNodeResult } from './_tsup-dts-rollup';
153
+ export { findParentNodeOfType } from './_tsup-dts-rollup';
150
154
  export { _getId } from './_tsup-dts-rollup';
151
155
  export { getMarkType } from './_tsup-dts-rollup';
152
156
  export { getNodeType } from './_tsup-dts-rollup';
@@ -171,10 +175,12 @@ export { DOMParserOptions } from './_tsup-dts-rollup';
171
175
  export { DOMSerializerOptions } from './_tsup-dts-rollup';
172
176
  export { JSONParserOptions } from './_tsup-dts-rollup';
173
177
  export { isAllSelection } from './_tsup-dts-rollup';
178
+ export { isFragment } from './_tsup-dts-rollup';
174
179
  export { isMark } from './_tsup-dts-rollup';
175
180
  export { isNodeSelection } from './_tsup-dts-rollup';
176
181
  export { isProseMirrorNode } from './_tsup-dts-rollup';
177
182
  export { isSelection } from './_tsup-dts-rollup';
183
+ export { isSlice } from './_tsup-dts-rollup';
178
184
  export { isTextSelection } from './_tsup-dts-rollup';
179
185
  export { withSkipCodeBlock } from './_tsup-dts-rollup';
180
186
  export { OBJECT_REPLACEMENT_CHARACTER } from './_tsup-dts-rollup';
@@ -16,14 +16,16 @@ import {
16
16
  htmlFromNode,
17
17
  isAllSelection,
18
18
  isElement,
19
+ isFragment,
19
20
  isMark,
20
21
  isMarkAbsent,
21
22
  isMarkActive,
22
23
  isNodeActive,
23
24
  isNodeSelection,
24
- isNotNull,
25
+ isNotNullish,
25
26
  isProseMirrorNode,
26
27
  isSelection,
28
+ isSlice,
27
29
  isTextSelection,
28
30
  jsonFromHTML,
29
31
  jsonFromNode,
@@ -37,7 +39,7 @@ import {
37
39
  stateFromJSON,
38
40
  toReversed,
39
41
  union
40
- } from "./chunk-MDJ2B4IL.js";
42
+ } from "./chunk-UKHJHMFE.js";
41
43
 
42
44
  // src/commands/add-mark.ts
43
45
  import "@prosekit/pm/model";
@@ -159,34 +161,31 @@ function removeMark(options) {
159
161
  }
160
162
 
161
163
  // src/utils/find-parent-node.ts
162
- function findParentNode(nodeType, $pos) {
163
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
164
+ function findParentNode(predicate, $pos) {
165
+ for (let depth = $pos.depth; depth >= 0; depth -= 1) {
164
166
  const node = $pos.node(depth);
165
- if (node.type === nodeType) {
166
- const from = $pos.before(depth);
167
- const to = $pos.after(depth);
168
- return {
169
- from,
170
- to
171
- };
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 };
172
171
  }
173
172
  }
174
- return {
175
- from: null,
176
- to: null
177
- };
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);
178
179
  }
179
180
 
180
181
  // src/commands/remove-node.ts
181
182
  function removeNode(options) {
182
183
  return (state, dispatch) => {
183
- const nodeType = getNodeType(state.schema, options.type);
184
184
  const $pos = typeof options.pos === "number" ? state.doc.resolve(options.pos) : state.selection.$anchor;
185
- const { from, to } = findParentNode(nodeType, $pos);
186
- if (from == null || to == null || from > to) {
187
- return false;
188
- }
189
- 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));
190
189
  return true;
191
190
  };
192
191
  }
@@ -284,77 +283,18 @@ function setNodeAttrs(options) {
284
283
  }
285
284
 
286
285
  // src/commands/toggle-mark.ts
286
+ import { toggleMark as baseToggleMark } from "@prosekit/pm/commands";
287
287
  import "@prosekit/pm/model";
288
- import "@prosekit/pm/state";
289
- function markApplies(doc, ranges, type) {
290
- for (const { $from, $to } of ranges) {
291
- let can = $from.depth == 0 ? doc.inlineContent && doc.type.allowsMarkType(type) : false;
292
- doc.nodesBetween($from.pos, $to.pos, (node) => {
293
- if (can) return false;
294
- can = node.inlineContent && node.type.allowsMarkType(type);
295
- });
296
- if (can) return true;
297
- }
298
- return false;
299
- }
300
- function baseToggleMark(markType, attrs = null, options) {
301
- const removeWhenPresent = (options && options.removeWhenPresent) !== false;
302
- return function(state, dispatch) {
303
- const { empty, $cursor, ranges } = state.selection;
304
- if (empty && !$cursor || !markApplies(state.doc, ranges, markType))
305
- return false;
306
- if (dispatch) {
307
- if ($cursor) {
308
- if (markType.isInSet(state.storedMarks || $cursor.marks()))
309
- dispatch(state.tr.removeStoredMark(markType));
310
- else dispatch(state.tr.addStoredMark(markType.create(attrs)));
311
- } else {
312
- let add;
313
- const tr = state.tr;
314
- if (removeWhenPresent) {
315
- add = !ranges.some(
316
- (r) => state.doc.rangeHasMark(r.$from.pos, r.$to.pos, markType)
317
- );
318
- } else {
319
- add = !ranges.every((r) => {
320
- let missing = false;
321
- tr.doc.nodesBetween(r.$from.pos, r.$to.pos, (node, pos, parent) => {
322
- if (missing) return false;
323
- missing = !markType.isInSet(node.marks) && !!parent && parent.type.allowsMarkType(markType) && !(node.isText && /^\s*$/.test(
324
- node.textBetween(
325
- Math.max(0, r.$from.pos - pos),
326
- Math.min(node.nodeSize, r.$to.pos - pos)
327
- )
328
- ));
329
- });
330
- return !missing;
331
- });
332
- }
333
- for (const { $from, $to } of ranges) {
334
- if (!add) {
335
- tr.removeMark($from.pos, $to.pos, markType);
336
- } else {
337
- let from = $from.pos, to = $to.pos;
338
- const start = $from.nodeAfter, end = $to.nodeBefore;
339
- const spaceStart = start && start.isText ? /^\s*/.exec(start.text)[0].length : 0;
340
- const spaceEnd = end && end.isText ? /\s*$/.exec(end.text)[0].length : 0;
341
- if (from + spaceStart < to) {
342
- from += spaceStart;
343
- to -= spaceEnd;
344
- }
345
- tr.addMark(from, to, markType.create(attrs));
346
- }
347
- }
348
- dispatch(tr.scrollIntoView());
349
- }
350
- }
351
- return true;
352
- };
353
- }
354
- function toggleMark({ type, attrs }) {
288
+ function toggleMark({
289
+ type,
290
+ attrs,
291
+ removeWhenPresent = false,
292
+ enterInlineAtoms = true
293
+ }) {
355
294
  return (state, dispatch, view) => {
356
295
  return baseToggleMark(getMarkType(state.schema, type), attrs, {
357
- removeWhenPresent: false
296
+ removeWhenPresent,
297
+ enterInlineAtoms
358
298
  })(state, dispatch, view);
359
299
  };
360
300
  }
@@ -435,12 +375,13 @@ function unsetMark(options) {
435
375
  // src/commands/wrap.ts
436
376
  import "@prosekit/pm/model";
437
377
  import { findWrapping } from "@prosekit/pm/transform";
438
- function wrap({ nodeType, attrs }) {
378
+ function wrap(options) {
439
379
  return (state, dispatch) => {
440
380
  const { $from, $to } = state.selection;
441
381
  const range = $from.blockRange($to);
442
382
  if (!range) return false;
443
- const wrapping = findWrapping(range, nodeType, attrs);
383
+ const nodeType = getNodeType(state.schema, options.type || options.nodeType);
384
+ const wrapping = findWrapping(range, nodeType, options.attrs);
444
385
  if (!wrapping) return false;
445
386
  dispatch == null ? void 0 : dispatch(state.tr.wrap(range, wrapping));
446
387
  return true;
@@ -504,6 +445,7 @@ function defineBaseCommands() {
504
445
  }
505
446
 
506
447
  // src/extensions/node-spec.ts
448
+ import clone from "just-clone";
507
449
  import OrderedMap2 from "orderedmap";
508
450
 
509
451
  // src/facets/schema-spec.ts
@@ -526,6 +468,139 @@ var schemaSpecFacet = defineFacet({
526
468
  singleton: true
527
469
  });
528
470
 
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("; ");
602
+ }
603
+
529
604
  // src/extensions/node-spec.ts
530
605
  function defineNodeSpec(options) {
531
606
  const payload = [options, void 0];
@@ -539,105 +614,50 @@ var nodeSpecFacet = defineFacet({
539
614
  reducer: (payloads) => {
540
615
  let specs = OrderedMap2.from({});
541
616
  let topNodeName = void 0;
542
- const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
543
- 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);
544
619
  for (const { name, topNode, ...spec } of specPayloads) {
545
- assert(!specs.get(name), `Node type ${name} can only be defined once`);
546
620
  if (topNode) {
547
621
  topNodeName = name;
548
622
  }
549
- 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
+ }
550
629
  }
551
- for (const {
552
- type,
553
- attr,
554
- default: defaultValue,
555
- splittable,
556
- toDOM,
557
- parseDOM
558
- } of attrPayloads) {
559
- const spec = specs.get(type);
560
- 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);
561
636
  if (!spec.attrs) {
562
637
  spec.attrs = {};
563
638
  }
564
- spec.attrs[attr] = {
565
- default: defaultValue,
566
- splittable
567
- };
568
- if (toDOM && spec.toDOM) {
569
- const existingToDom = spec.toDOM;
570
- spec.toDOM = (node) => {
571
- const dom = existingToDom(node);
572
- if (!dom) {
573
- return dom;
574
- }
575
- const attrDOM = toDOM(node.attrs[attr]);
576
- if (!attrDOM) {
577
- return dom;
578
- }
579
- const [key, value] = attrDOM;
580
- if (!key) {
581
- return dom;
582
- }
583
- if (Array.isArray(dom)) {
584
- if (typeof dom[1] === "object") {
585
- return [
586
- dom[0],
587
- setObjectAttribute(
588
- dom[1],
589
- key,
590
- value
591
- ),
592
- ...dom.slice(2)
593
- ];
594
- } else {
595
- return [dom[0], { [key]: value }, ...dom.slice(1)];
596
- }
597
- } else if (isElement(dom)) {
598
- setElementAttribute(dom, key, value);
599
- } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
600
- setElementAttribute(dom.dom, key, value);
601
- }
602
- 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
603
644
  };
604
645
  }
605
- if (parseDOM && spec.parseDOM) {
606
- for (const rule of spec.parseDOM) {
607
- const existingGetAttrs = rule.getAttrs;
608
- const existingAttrs = rule.attrs;
609
- rule.getAttrs = (dom) => {
610
- var _a;
611
- const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
612
- if (attrs === false || !dom || !isElement(dom)) {
613
- return attrs != null ? attrs : null;
614
- }
615
- const value = parseDOM(dom);
616
- return {
617
- ...attrs,
618
- [attr]: value
619
- };
620
- };
621
- }
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
+ );
622
653
  }
654
+ specs = specs.update(type, spec);
623
655
  }
624
656
  return { nodes: specs, topNode: topNodeName };
625
657
  },
626
658
  parent: schemaSpecFacet,
627
659
  singleton: true
628
660
  });
629
- function setObjectAttribute(obj, key, value) {
630
- if (key === "style") {
631
- value = `${value}${obj.style || ""}`;
632
- }
633
- return { ...obj, [key]: value };
634
- }
635
- function setElementAttribute(element, key, value) {
636
- if (key === "style") {
637
- value = `${value}${element.getAttribute("style") || ""}`;
638
- }
639
- element.setAttribute(key, value);
640
- }
641
661
 
642
662
  // src/extensions/doc.ts
643
663
  function defineDoc() {
@@ -777,20 +797,6 @@ function combineEventHandlers() {
777
797
  return [setHandlers, combinedEventHandler];
778
798
  }
779
799
 
780
- // src/utils/group-entries.ts
781
- function groupEntries(entries) {
782
- const map = {};
783
- for (const [key, value] of entries) {
784
- const values = map[key];
785
- if (!values) {
786
- map[key] = [value];
787
- } else {
788
- values.push(value);
789
- }
790
- }
791
- return map;
792
- }
793
-
794
800
  // src/extensions/events/dom-event.ts
795
801
  function defineDOMEventHandler(event, handler) {
796
802
  return defineFacetPayload(domEventFacet, [
@@ -1059,6 +1065,7 @@ function defineBaseKeymap(options) {
1059
1065
  }
1060
1066
 
1061
1067
  // src/extensions/mark-spec.ts
1068
+ import clone2 from "just-clone";
1062
1069
  import OrderedMap3 from "orderedmap";
1063
1070
  function defineMarkSpec(options) {
1064
1071
  const payload = [options, void 0];
@@ -1071,78 +1078,52 @@ function defineMarkAttr(options) {
1071
1078
  var markSpecFacet = defineFacet({
1072
1079
  reducer: (payloads) => {
1073
1080
  let specs = OrderedMap3.from({});
1074
- const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
1075
- 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);
1076
1083
  for (const { name, ...spec } of specPayloads) {
1077
- assert(!specs.get(name), `Mark type ${name} can only be defined once`);
1078
- 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
+ }
1079
1090
  }
1080
- for (const {
1081
- type,
1082
- attr,
1083
- default: defaultValue,
1084
- toDOM,
1085
- parseDOM
1086
- } of attrPayloads) {
1087
- const spec = specs.get(type);
1088
- 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);
1089
1097
  if (!spec.attrs) {
1090
1098
  spec.attrs = {};
1091
1099
  }
1092
- spec.attrs[attr] = { default: defaultValue };
1093
- if (toDOM && spec.toDOM) {
1094
- const existingToDom = spec.toDOM;
1095
- spec.toDOM = (mark, inline) => {
1096
- const dom = existingToDom(mark, inline);
1097
- if (!dom) {
1098
- return dom;
1099
- }
1100
- const attrDOM = toDOM(mark.attrs[attr]);
1101
- if (!attrDOM) {
1102
- return dom;
1103
- }
1104
- const [key, value] = attrDOM;
1105
- if (!key) {
1106
- return dom;
1107
- }
1108
- if (Array.isArray(dom)) {
1109
- if (typeof dom[1] === "object") {
1110
- return [dom[0], { ...dom[1], [key]: value }, ...dom.slice(2)];
1111
- } else {
1112
- return [dom[0], { [key]: value }, ...dom.slice(1)];
1113
- }
1114
- } else if (isElement(dom)) {
1115
- dom.setAttribute(key, value);
1116
- } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
1117
- dom.dom.setAttribute(key, value);
1118
- }
1119
- return dom;
1100
+ for (const attr of attrs) {
1101
+ spec.attrs[attr.attr] = {
1102
+ default: attr.default,
1103
+ validate: attr.validate
1120
1104
  };
1121
1105
  }
1122
- if (parseDOM && spec.parseDOM) {
1123
- for (const rule of spec.parseDOM) {
1124
- const existingGetAttrs = rule.getAttrs;
1125
- const existingAttrs = rule.attrs;
1126
- rule.getAttrs = (dom) => {
1127
- var _a;
1128
- const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
1129
- if (attrs === false || !dom || !isElement(dom)) {
1130
- return attrs != null ? attrs : null;
1131
- }
1132
- const value = parseDOM(dom);
1133
- return {
1134
- ...attrs,
1135
- [attr]: value
1136
- };
1137
- };
1138
- }
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
+ );
1139
1113
  }
1114
+ specs = specs.update(type, spec);
1140
1115
  }
1141
1116
  return { marks: specs, nodes: {} };
1142
1117
  },
1143
1118
  parent: schemaSpecFacet,
1144
1119
  singleton: true
1145
1120
  });
1121
+ function wrapParseRuleAttrs(rule, attrs) {
1122
+ if (rule.tag) {
1123
+ return wrapTagParseRuleAttrs(rule, attrs);
1124
+ }
1125
+ return rule;
1126
+ }
1146
1127
 
1147
1128
  // src/extensions/node-view.ts
1148
1129
  import { PluginKey as PluginKey5, ProseMirrorPlugin as ProseMirrorPlugin5 } from "@prosekit/pm/state";
@@ -1182,8 +1163,8 @@ var nodeViewFactoryFacet = defineFacet({
1182
1163
  reducer: (inputs) => {
1183
1164
  if (isServer) return [];
1184
1165
  const nodeViews = {};
1185
- const factories = inputs.map((x) => x[0]).filter(isNotNull);
1186
- 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);
1187
1168
  for (const { group, name, args } of options) {
1188
1169
  const factory = factories.find((factory2) => factory2.group === group);
1189
1170
  if (!factory) continue;
@@ -1247,6 +1228,16 @@ var canUseRegexLookbehind = cache(() => {
1247
1228
  import clsxLite from "clsx/lite";
1248
1229
  var clsx = clsxLite;
1249
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
+
1250
1241
  // src/utils/collect-nodes.ts
1251
1242
  import { ProseMirrorFragment, ProseMirrorNode as ProseMirrorNode2 } from "@prosekit/pm/model";
1252
1243
  function collectNodes(content) {
@@ -1336,6 +1327,7 @@ export {
1336
1327
  assert,
1337
1328
  canUseRegexLookbehind,
1338
1329
  clsx,
1330
+ collectChildren,
1339
1331
  collectNodes,
1340
1332
  containsInlineNode,
1341
1333
  createEditor,
@@ -1380,6 +1372,8 @@ export {
1380
1372
  elementFromJSON,
1381
1373
  elementFromNode,
1382
1374
  expandMark,
1375
+ findParentNode,
1376
+ findParentNodeOfType,
1383
1377
  getMarkType,
1384
1378
  getNodeType,
1385
1379
  htmlFromJSON,
@@ -1388,6 +1382,7 @@ export {
1388
1382
  isAllSelection,
1389
1383
  isApple,
1390
1384
  isAtBlockStart,
1385
+ isFragment,
1391
1386
  isInCodeBlock,
1392
1387
  isMark,
1393
1388
  isMarkAbsent,
@@ -1395,6 +1390,7 @@ export {
1395
1390
  isNodeSelection,
1396
1391
  isProseMirrorNode,
1397
1392
  isSelection,
1393
+ isSlice,
1398
1394
  isTextSelection,
1399
1395
  jsonFromHTML,
1400
1396
  jsonFromNode,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/core",
3
3
  "type": "module",
4
- "version": "0.7.7",
4
+ "version": "0.7.8",
5
5
  "private": false,
6
6
  "author": {
7
7
  "name": "ocavue",
@@ -41,14 +41,15 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "clsx": "^2.1.1",
44
+ "just-clone": "^6.2.0",
44
45
  "just-map-values": "^3.2.0",
45
46
  "orderedmap": "^2.1.1",
46
47
  "prosemirror-splittable": "^0.1.1",
47
48
  "type-fest": "^4.23.0",
48
- "@prosekit/pm": "^0.1.7"
49
+ "@prosekit/pm": "^0.1.8"
49
50
  },
50
51
  "devDependencies": {
51
- "tsup": "^8.2.2",
52
+ "tsup": "^8.2.3",
52
53
  "typescript": "^5.5.3",
53
54
  "vitest": "^2.0.4",
54
55
  "@prosekit/dev": "0.0.0"