@prosekit/core 0.8.6 → 0.9.0

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.
Files changed (57) hide show
  1. package/dist/{editor-M9OimMiI.d.ts → editor-4lgGc3CY.d.ts} +20 -60
  2. package/dist/editor-4lgGc3CY.d.ts.map +1 -0
  3. package/dist/{editor-D2iEkgO8.js → editor-DGNUXn-u.js} +99 -116
  4. package/dist/editor-DGNUXn-u.js.map +1 -0
  5. package/dist/prosekit-core-test.d.ts +1 -1
  6. package/dist/prosekit-core-test.js +1 -1
  7. package/dist/prosekit-core.d.ts +89 -180
  8. package/dist/prosekit-core.d.ts.map +1 -1
  9. package/dist/prosekit-core.js +322 -381
  10. package/dist/prosekit-core.js.map +1 -1
  11. package/package.json +7 -8
  12. package/src/commands/select-all.ts +3 -8
  13. package/src/commands/select-block.spec.ts +83 -0
  14. package/src/commands/select-block.ts +59 -0
  15. package/src/commands/wrap.ts +1 -6
  16. package/src/editor/action.ts +1 -11
  17. package/src/editor/editor.ts +20 -32
  18. package/src/extensions/command.ts +4 -0
  19. package/src/extensions/default-state.spec.ts +0 -4
  20. package/src/extensions/default-state.ts +4 -24
  21. package/src/extensions/events/dom-event.ts +1 -4
  22. package/src/extensions/events/editor-event.ts +1 -1
  23. package/src/extensions/history.ts +1 -1
  24. package/src/extensions/keymap-base.spec.ts +98 -0
  25. package/src/extensions/keymap-base.ts +37 -13
  26. package/src/extensions/keymap.spec.ts +74 -1
  27. package/src/extensions/keymap.ts +19 -31
  28. package/src/extensions/mark-spec.ts +32 -29
  29. package/src/extensions/node-spec.ts +28 -19
  30. package/src/extensions/plugin.ts +1 -2
  31. package/src/facets/command.ts +8 -2
  32. package/src/facets/state.spec.ts +6 -6
  33. package/src/facets/state.ts +1 -2
  34. package/src/index.ts +3 -23
  35. package/src/types/extension-command.ts +0 -7
  36. package/src/types/extension.ts +0 -16
  37. package/src/utils/array-grouping.spec.ts +1 -11
  38. package/src/utils/array-grouping.ts +1 -14
  39. package/src/utils/array.ts +0 -4
  40. package/src/utils/combine-event-handlers.ts +4 -6
  41. package/src/utils/editor-content.ts +3 -3
  42. package/src/utils/env.ts +2 -0
  43. package/src/utils/output-spec.ts +11 -0
  44. package/src/utils/parse.ts +9 -9
  45. package/dist/editor-D2iEkgO8.js.map +0 -1
  46. package/dist/editor-M9OimMiI.d.ts.map +0 -1
  47. package/src/extensions/doc.ts +0 -31
  48. package/src/extensions/paragraph.ts +0 -61
  49. package/src/extensions/text.ts +0 -34
  50. package/src/types/base-node-view-options.ts +0 -33
  51. package/src/types/object-entries.ts +0 -13
  52. package/src/utils/collect-children.ts +0 -21
  53. package/src/utils/collect-nodes.ts +0 -37
  54. package/src/utils/deep-equals.spec.ts +0 -26
  55. package/src/utils/deep-equals.ts +0 -29
  56. package/src/utils/get-id.spec.ts +0 -14
  57. package/src/utils/get-id.ts +0 -13
@@ -1,15 +1,13 @@
1
- import { A as isSelection, B as assert, C as defineFacetPayload, D as isNodeSelection, E as isMark, F as rootFacet, H as EditorNotFoundError, I as defineFacet, L as Priority, M as isTextSelection, N as toReversed, O as isNotNullish, P as schemaFacet, R as isNodeActive, S as stateFacet, T as isFragment, U as ProseKitError, V as getMarkType, _ as jsonFromState, a as union, b as nodeFromJSON, c as isMarkActive, d as elementFromJSON, f as elementFromNode, g as jsonFromNode, h as jsonFromHTML, j as isSlice, k as isProseMirrorNode, l as isMarkAbsent, m as htmlFromNode, p as htmlFromJSON, r as createEditor, t as Editor, u as defineDefaultState, v as nodeFromElement, w as isAllSelection, x as stateFromJSON, y as nodeFromHTML, z as getNodeType } from "./editor-D2iEkgO8.js";
2
- import { AllSelection, Plugin, PluginKey, ProseMirrorPlugin, TextSelection } from "@prosekit/pm/state";
1
+ import { A as isFragment, B as getMarkType, C as defineFacetPayload, D as Priority, E as defineFacet, F as isSelection, H as ProseKitError, I as isSlice, L as isTextSelection, M as isNodeSelection, N as isNotNullish, O as isNodeActive, P as isProseMirrorNode, R as getNodeType, S as stateFacet, T as rootFacet, V as EditorNotFoundError, _ as jsonFromState, a as union, b as nodeFromJSON, c as isMarkActive, d as elementFromJSON, f as elementFromNode, g as jsonFromNode, h as jsonFromHTML, j as isMark, k as isAllSelection, l as isMarkAbsent, m as htmlFromNode, p as htmlFromJSON, r as createEditor, t as Editor, u as defineDefaultState, v as nodeFromElement, w as schemaFacet, x as stateFromJSON, y as nodeFromHTML, z as assert } from "./editor-DGNUXn-u.js";
2
+ import { Plugin, PluginKey, ProseMirrorPlugin, TextSelection } from "@prosekit/pm/state";
3
3
  import { ReplaceAroundStep, findWrapping, insertPoint } from "@prosekit/pm/transform";
4
- import { baseKeymap, chainCommands, createParagraphNear, deleteSelection, joinTextblockBackward, lift, liftEmptyBlock, newlineInCode, selectNodeBackward, setBlockType as setBlockType$1, toggleMark as toggleMark$1 } from "@prosekit/pm/commands";
5
- import { DOMSerializer, Fragment, ProseMirrorFragment, ProseMirrorNode, Slice } from "@prosekit/pm/model";
6
- import { isElementLike, once } from "@ocavue/utils";
7
- import OrderedMap from "orderedmap";
8
- import mapValues from "just-map-values";
9
- import clone from "just-clone";
4
+ import { baseKeymap, chainCommands, createParagraphNear, deleteSelection, joinTextblockBackward, lift, liftEmptyBlock, newlineInCode, selectAll as selectAll$1, selectNodeBackward, setBlockType as setBlockType$1, toggleMark as toggleMark$1 } from "@prosekit/pm/commands";
5
+ import { DOMSerializer, Fragment, Slice } from "@prosekit/pm/model";
6
+ import { isElementLike, mapGroupBy, once } from "@ocavue/utils";
10
7
  import { history, redo, undo } from "@prosekit/pm/history";
11
8
  import { keydownHandler } from "@prosekit/pm/keymap";
12
9
  import { splitSplittableBlock } from "prosemirror-splittable";
10
+ import OrderedMap from "orderedmap";
13
11
  import clsxLite from "clsx/lite";
14
12
 
15
13
  //#region src/commands/add-mark.ts
@@ -210,6 +208,56 @@ function removeNode(options) {
210
208
  };
211
209
  }
212
210
 
211
+ //#endregion
212
+ //#region src/commands/select-all.ts
213
+ /**
214
+ * Returns a command that selects the whole document.
215
+ *
216
+ * @public
217
+ */
218
+ function selectAll() {
219
+ return selectAll$1;
220
+ }
221
+
222
+ //#endregion
223
+ //#region src/commands/select-block.ts
224
+ function getTextblockEndpoint(selection, side) {
225
+ const $pos = side < 0 ? selection.$from : selection.$to;
226
+ let depth = $pos.depth;
227
+ while ($pos.node(depth).isInline) {
228
+ if (!depth) return;
229
+ depth--;
230
+ }
231
+ if (!$pos.node(depth).isTextblock) return;
232
+ return side < 0 ? $pos.start(depth) : $pos.end(depth);
233
+ }
234
+ /**
235
+ * @internal
236
+ */
237
+ const selectBlockCommand = (state, dispatch) => {
238
+ const { selection } = state;
239
+ if (!isTextSelection(selection)) return false;
240
+ const expectedFrom = getTextblockEndpoint(selection, -1);
241
+ const expectedTo = getTextblockEndpoint(selection, 1);
242
+ if (expectedFrom == null || expectedTo == null) return false;
243
+ if (selection.from <= expectedFrom && selection.to >= expectedTo) return false;
244
+ if (dispatch) {
245
+ const newSelection = TextSelection.create(state.doc, expectedFrom, expectedTo);
246
+ dispatch(state.tr.setSelection(newSelection));
247
+ }
248
+ return true;
249
+ };
250
+ /**
251
+ * Returns a command to expand the text selection to cover the current block
252
+ * node. If the text selection spans multiple blocks, it will select all
253
+ * blocks in the selection.
254
+ *
255
+ * @public
256
+ */
257
+ function selectBlock() {
258
+ return selectBlockCommand;
259
+ }
260
+
213
261
  //#endregion
214
262
  //#region src/utils/get-custom-selection.ts
215
263
  function getCustomSelection(state, from, to) {
@@ -350,7 +398,7 @@ function wrap(options) {
350
398
  const { $from, $to } = state.selection;
351
399
  const range = $from.blockRange($to);
352
400
  if (!range) return false;
353
- const wrapping = findWrapping(range, getNodeType(state.schema, options.nodeType || options.type), options.attrs);
401
+ const wrapping = findWrapping(range, getNodeType(state.schema, options.type), options.attrs);
354
402
  if (!wrapping) return false;
355
403
  dispatch?.(state.tr.wrap(range, wrapping));
356
404
  return true;
@@ -480,7 +528,7 @@ const pluginFacet = defineFacet({
480
528
  else if (Array.isArray(payload) && payload.every((p) => p instanceof Plugin)) plugins.push(...payload);
481
529
  else if (typeof payload === "function") plugins.push(...[payload({ schema })].flat());
482
530
  else throw new ProseKitError("Invalid plugin");
483
- return { plugins: toReversed(plugins) };
531
+ return { plugins: [...plugins].reverse() };
484
532
  };
485
533
  },
486
534
  parent: stateFacet
@@ -554,25 +602,15 @@ function insertText({ text, from, to }) {
554
602
  };
555
603
  }
556
604
 
557
- //#endregion
558
- //#region src/commands/select-all.ts
559
- /**
560
- * Returns a command that selects the whole document.
561
- *
562
- * @public
563
- */
564
- function selectAll() {
565
- return (state, dispatch) => {
566
- dispatch?.(state.tr.setSelection(new AllSelection(state.doc)));
567
- return true;
568
- };
569
- }
570
-
571
605
  //#endregion
572
606
  //#region src/facets/command.ts
573
607
  const commandFacet = defineFacet({
574
608
  reducer: (inputs) => {
575
- return { commands: Object.assign({}, ...inputs) };
609
+ switch (inputs.length) {
610
+ case 0: return { commands: {} };
611
+ case 1: return { commands: inputs[0] };
612
+ default: return { commands: Object.assign({}, ...inputs) };
613
+ }
576
614
  },
577
615
  parent: rootFacet,
578
616
  singleton: true
@@ -599,6 +637,7 @@ function defineBaseCommands() {
599
637
  setNodeAttrs,
600
638
  insertDefaultBlock,
601
639
  selectAll,
640
+ selectBlock,
602
641
  addMark,
603
642
  removeMark,
604
643
  unsetBlockType,
@@ -606,217 +645,6 @@ function defineBaseCommands() {
606
645
  });
607
646
  }
608
647
 
609
- //#endregion
610
- //#region src/facets/schema-spec.ts
611
- const schemaSpecFacet = defineFacet({
612
- reducer: (specs) => {
613
- let nodes = OrderedMap.from({});
614
- let marks = OrderedMap.from({});
615
- let topNode = void 0;
616
- for (const spec of specs) {
617
- nodes = nodes.append(spec.nodes);
618
- marks = marks.append(spec.marks ?? {});
619
- topNode = topNode ?? spec.topNode;
620
- }
621
- return {
622
- nodes,
623
- marks,
624
- topNode
625
- };
626
- },
627
- parent: schemaFacet,
628
- singleton: true
629
- });
630
-
631
- //#endregion
632
- //#region src/utils/array-grouping.ts
633
- function groupBy(items, keySelector) {
634
- const result = {};
635
- for (const item of items) {
636
- const key = keySelector(item);
637
- (result[key] ||= []).push(item);
638
- }
639
- return result;
640
- }
641
- function groupEntries(entries) {
642
- const result = {};
643
- for (const [key, value] of entries) (result[key] ||= []).push(value);
644
- return result;
645
- }
646
-
647
- //#endregion
648
- //#region src/utils/remove-undefined-values.ts
649
- function removeUndefinedValues(obj) {
650
- const result = {};
651
- for (const [key, value] of Object.entries(obj)) if (value !== void 0) result[key] = value;
652
- return result;
653
- }
654
-
655
- //#endregion
656
- //#region src/utils/merge-objects.ts
657
- function mergeObjects(...objects) {
658
- const filteredObjects = objects.filter(isNotNullish).map(removeUndefinedValues);
659
- return Object.assign({}, ...filteredObjects);
660
- }
661
-
662
- //#endregion
663
- //#region src/utils/merge-specs.ts
664
- function mergeSpecs(a, b) {
665
- const attrs = {};
666
- const attrNames = new Set([...Object.keys(a.attrs ?? {}), ...Object.keys(b.attrs ?? {})]);
667
- for (const name of attrNames) {
668
- const attrSpecA = a.attrs?.[name];
669
- const attrSpecB = b.attrs?.[name];
670
- const attrSpecMerged = mergeObjects(attrSpecA, attrSpecB);
671
- if (attrSpecMerged) attrs[name] = attrSpecMerged;
672
- }
673
- return mergeObjects(a, b, {
674
- attrs,
675
- parseDOM: [...a.parseDOM ?? [], ...b.parseDOM ?? []]
676
- });
677
- }
678
-
679
- //#endregion
680
- //#region src/utils/output-spec.ts
681
- function wrapOutputSpecAttrs(toDOM, options) {
682
- return (node, ...args) => {
683
- return insertOutputSpecAttrs(toDOM(node, ...args), options.map((option) => option.toDOM?.(node.attrs[option.attr])).filter(isNotNullish));
684
- };
685
- }
686
- function wrapTagParseRuleAttrs(rule, options) {
687
- const existingGetAttrs = rule.getAttrs;
688
- const existingAttrs = rule.attrs;
689
- return {
690
- ...rule,
691
- getAttrs: (dom) => {
692
- const baseAttrs = existingGetAttrs?.(dom) ?? existingAttrs ?? {};
693
- if (baseAttrs === false || !dom || !isElementLike(dom)) return baseAttrs ?? null;
694
- const insertedAttrs = {};
695
- for (const option of options) if (option.parseDOM) insertedAttrs[option.attr] = option.parseDOM(dom);
696
- return {
697
- ...baseAttrs,
698
- ...insertedAttrs
699
- };
700
- }
701
- };
702
- }
703
- function insertOutputSpecAttrs(dom, attrs) {
704
- if (!dom) return dom;
705
- if (Array.isArray(dom)) {
706
- const rest = dom.slice(1);
707
- let oldAttrs;
708
- if (rest.length > 0 && (rest[0] == null || typeof rest[0] === "object")) oldAttrs = rest.shift();
709
- else oldAttrs = {};
710
- const newAttrs = setObjectAttributes(oldAttrs, attrs);
711
- return [
712
- dom[0],
713
- newAttrs,
714
- ...rest
715
- ];
716
- }
717
- if (isElementLike(dom)) return setElementAttributes(dom, attrs);
718
- if (typeof dom === "object" && "dom" in dom && isElementLike(dom.dom)) return {
719
- ...dom,
720
- dom: setElementAttributes(dom.dom, attrs)
721
- };
722
- return dom;
723
- }
724
- function setObjectAttributes(obj, attrs) {
725
- obj = { ...obj };
726
- for (const [key, value] of attrs) {
727
- const oldValue = obj[key];
728
- obj[key] = key === "style" ? joinStyles(value, typeof oldValue === "string" ? oldValue : "") : value;
729
- }
730
- return obj;
731
- }
732
- function setElementAttributes(element, attrs) {
733
- element = element.cloneNode(true);
734
- for (const [key, value] of attrs) {
735
- const oldValue = element.getAttribute(key);
736
- const newValue = key === "style" ? joinStyles(value, typeof oldValue === "string" ? oldValue : "") : value;
737
- element.setAttribute(key, newValue);
738
- }
739
- return element;
740
- }
741
- function joinStyles(...styles) {
742
- return styles.map((style) => style.trim().replace(/;$/, "")).filter(Boolean).join("; ");
743
- }
744
-
745
- //#endregion
746
- //#region src/extensions/node-spec.ts
747
- /**
748
- * Defines a node type.
749
- *
750
- * @public
751
- */
752
- function defineNodeSpec(options) {
753
- return defineFacetPayload(nodeSpecFacet, [[options, void 0]]);
754
- }
755
- /**
756
- * Defines an attribute for a node type.
757
- *
758
- * @public
759
- */
760
- function defineNodeAttr(options) {
761
- return defineFacetPayload(nodeSpecFacet, [[void 0, options]]);
762
- }
763
- const nodeSpecFacet = defineFacet({
764
- reducer: (payloads) => {
765
- let specs = OrderedMap.from({});
766
- let topNodeName = void 0;
767
- const specPayloads = payloads.map((input) => input[0]).filter(isNotNullish);
768
- const attrPayloads = payloads.map((input) => input[1]).filter(isNotNullish);
769
- for (const { name, topNode,...spec } of specPayloads) {
770
- if (topNode) topNodeName = name;
771
- const prevSpec = specs.get(name);
772
- if (prevSpec) specs = specs.update(name, mergeSpecs(prevSpec, spec));
773
- else specs = specs.addToStart(name, spec);
774
- }
775
- const groupedAttrs = groupBy(attrPayloads, (payload) => payload.type);
776
- for (const [type, attrs] of Object.entries(groupedAttrs)) {
777
- if (!attrs) continue;
778
- const maybeSpec = specs.get(type);
779
- assert(maybeSpec, `Node type ${type} must be defined`);
780
- const spec = clone(maybeSpec);
781
- if (!spec.attrs) spec.attrs = {};
782
- for (const attr of attrs) spec.attrs[attr.attr] = {
783
- default: attr.default,
784
- validate: attr.validate,
785
- splittable: attr.splittable
786
- };
787
- if (spec.toDOM) spec.toDOM = wrapOutputSpecAttrs(spec.toDOM, attrs);
788
- if (spec.parseDOM) spec.parseDOM = spec.parseDOM.map((rule) => wrapTagParseRuleAttrs(rule, attrs));
789
- specs = specs.update(type, spec);
790
- }
791
- return {
792
- nodes: specs,
793
- topNode: topNodeName
794
- };
795
- },
796
- parent: schemaSpecFacet,
797
- singleton: true
798
- });
799
-
800
- //#endregion
801
- //#region src/extensions/doc.ts
802
- /**
803
- * @public
804
- *
805
- * @deprecated Use the following import instead:
806
- *
807
- * ```ts
808
- * import { defineDoc } from 'prosekit/extensions/doc'
809
- * ```
810
- */
811
- function defineDoc() {
812
- console.warn("[prosekit] The `defineDoc` function from `prosekit/core` is deprecated. Use the following import instead: `import { defineDoc } from \"prosekit/extensions/doc\"`.");
813
- return defineNodeSpec({
814
- name: "doc",
815
- content: "block+",
816
- topNode: true
817
- });
818
- }
819
-
820
648
  //#endregion
821
649
  //#region src/extensions/events/plugin-view.ts
822
650
  /**
@@ -904,15 +732,23 @@ function defineDocChangeHandler(handler) {
904
732
  });
905
733
  }
906
734
 
735
+ //#endregion
736
+ //#region src/utils/array-grouping.ts
737
+ function groupEntries(entries) {
738
+ const result = {};
739
+ for (const [key, value] of entries) (result[key] ||= []).push(value);
740
+ return result;
741
+ }
742
+
907
743
  //#endregion
908
744
  //#region src/utils/combine-event-handlers.ts
909
745
  function combineEventHandlers() {
910
746
  let handlers = [];
911
747
  function setHandlers(eventHandlers) {
912
- handlers = toReversed(eventHandlers);
748
+ handlers = eventHandlers;
913
749
  }
914
750
  function combinedEventHandler(...args) {
915
- for (const handler of handlers) if (handler(...args)) return true;
751
+ for (let i = handlers.length - 1; i >= 0; i--) if (handlers[i](...args)) return true;
916
752
  return false;
917
753
  }
918
754
  return [setHandlers, combinedEventHandler];
@@ -948,10 +784,7 @@ const domEventFacet = defineFacet({
948
784
  hasNewEvent = true;
949
785
  const [setHandlers, combinedHandler] = combineEventHandlers();
950
786
  setHandlersMap[event] = setHandlers;
951
- const e = (view, eventObject) => {
952
- return combinedHandler(view, eventObject);
953
- };
954
- combinedHandlerMap[event] = e;
787
+ combinedHandlerMap[event] = combinedHandler;
955
788
  }
956
789
  const map = groupEntries(payloads);
957
790
  for (const [event, setHandlers] of Object.entries(setHandlersMap)) setHandlers(map[event] ?? []);
@@ -1147,6 +980,8 @@ function defineFocusChangeHandler(handler) {
1147
980
  //#endregion
1148
981
  //#region src/utils/env.ts
1149
982
  /**
983
+ * https://github.com/ProseMirror/prosemirror-keymap/blob/1.2.3/src/keymap.ts#L5
984
+ *
1150
985
  * @internal
1151
986
  */
1152
987
  const isApple = typeof navigator !== "undefined" ? /Mac|iP(hone|[ao]d)/.test(navigator.platform) : false;
@@ -1154,6 +989,9 @@ const isApple = typeof navigator !== "undefined" ? /Mac|iP(hone|[ao]d)/.test(nav
1154
989
  //#endregion
1155
990
  //#region src/extensions/keymap.ts
1156
991
  /**
992
+ * Adds a set of keybindings to the editor. Please read the
993
+ * [documentation](https://prosemirror.net/docs/ref/#keymap) for more details.
994
+ *
1157
995
  * @public
1158
996
  */
1159
997
  function defineKeymap(keymap$1) {
@@ -1164,38 +1002,30 @@ function defineKeymap(keymap$1) {
1164
1002
  */
1165
1003
  const keymapFacet = defineFacet({
1166
1004
  reduce: () => {
1167
- let handler;
1168
- const handlerWrapper = (view, event) => {
1169
- if (handler) return handler(view, event);
1005
+ let subHandlers = [];
1006
+ const rootHandler = (view, event) => {
1007
+ for (const handler of subHandlers) if (handler(view, event)) return true;
1170
1008
  return false;
1171
1009
  };
1172
1010
  const plugin = new Plugin({
1173
1011
  key: keymapPluginKey,
1174
- props: { handleKeyDown: handlerWrapper }
1012
+ props: { handleKeyDown: rootHandler }
1175
1013
  });
1176
1014
  return (keymaps) => {
1177
- handler = keydownHandler(mergeKeymaps(toReversed(keymaps)));
1015
+ subHandlers = keymaps.map(keydownHandler).reverse();
1178
1016
  return plugin;
1179
1017
  };
1180
1018
  },
1181
1019
  parent: pluginFacet,
1182
1020
  singleton: true
1183
1021
  });
1184
- function mergeKeymaps(keymaps) {
1185
- const bindings = {};
1186
- for (const keymap$1 of keymaps) for (const [key, command] of Object.entries(keymap$1)) (bindings[key] || (bindings[key] = [])).push(command);
1187
- return mapValues(bindings, mergeCommands);
1188
- }
1189
- function mergeCommands(commands$1) {
1190
- return chainCommands(...commands$1);
1191
- }
1192
1022
  const keymapPluginKey = new PluginKey("prosekit-keymap");
1193
1023
 
1194
1024
  //#endregion
1195
1025
  //#region src/extensions/history.ts
1196
1026
  const keymap = {
1197
1027
  "Mod-z": undo,
1198
- "Shift-Mod-z": redo
1028
+ "Mod-Z": redo
1199
1029
  };
1200
1030
  if (!isApple) keymap["Mod-y"] = redo;
1201
1031
  const commands = {
@@ -1220,25 +1050,168 @@ function defineHistory({ depth = 200, newGroupDelay = 250 } = {}) {
1220
1050
  //#region src/extensions/keymap-base.ts
1221
1051
  const customEnter = chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitSplittableBlock);
1222
1052
  const customBackspace = chainCommands(deleteSelection, joinTextblockBackward, selectNodeBackward);
1223
- const customBaseKeymap = {
1224
- ...baseKeymap,
1225
- Enter: customEnter,
1226
- Backspace: customBackspace
1227
- };
1228
1053
  /**
1229
1054
  * Defines some basic key bindings.
1230
1055
  *
1056
+ * @param options
1057
+ *
1231
1058
  * @public
1232
1059
  */
1233
- function defineBaseKeymap(options) {
1234
- const priority = options?.priority ?? Priority.low;
1235
- return withPriority(defineKeymap(customBaseKeymap), priority);
1060
+ function defineBaseKeymap({ priority = Priority.low, preferBlockSelection = true } = {}) {
1061
+ return withPriority(defineKeymap({
1062
+ ...baseKeymap,
1063
+ "Mod-a": preferBlockSelection ? chainCommands(selectBlockCommand, selectAll$1) : selectAll$1,
1064
+ "Enter": customEnter,
1065
+ "Backspace": customBackspace
1066
+ }), priority);
1067
+ }
1068
+
1069
+ //#endregion
1070
+ //#region src/facets/schema-spec.ts
1071
+ const schemaSpecFacet = defineFacet({
1072
+ reducer: (specs) => {
1073
+ let nodes = OrderedMap.from({});
1074
+ let marks = OrderedMap.from({});
1075
+ let topNode = void 0;
1076
+ for (const spec of specs) {
1077
+ nodes = nodes.append(spec.nodes);
1078
+ marks = marks.append(spec.marks ?? {});
1079
+ topNode = topNode ?? spec.topNode;
1080
+ }
1081
+ return {
1082
+ nodes,
1083
+ marks,
1084
+ topNode
1085
+ };
1086
+ },
1087
+ parent: schemaFacet,
1088
+ singleton: true
1089
+ });
1090
+
1091
+ //#endregion
1092
+ //#region src/utils/remove-undefined-values.ts
1093
+ function removeUndefinedValues(obj) {
1094
+ const result = {};
1095
+ for (const [key, value] of Object.entries(obj)) if (value !== void 0) result[key] = value;
1096
+ return result;
1097
+ }
1098
+
1099
+ //#endregion
1100
+ //#region src/utils/merge-objects.ts
1101
+ function mergeObjects(...objects) {
1102
+ const filteredObjects = objects.filter(isNotNullish).map(removeUndefinedValues);
1103
+ return Object.assign({}, ...filteredObjects);
1104
+ }
1105
+
1106
+ //#endregion
1107
+ //#region src/utils/merge-specs.ts
1108
+ function mergeSpecs(a, b) {
1109
+ const attrs = {};
1110
+ const attrNames = new Set([...Object.keys(a.attrs ?? {}), ...Object.keys(b.attrs ?? {})]);
1111
+ for (const name of attrNames) {
1112
+ const attrSpecA = a.attrs?.[name];
1113
+ const attrSpecB = b.attrs?.[name];
1114
+ const attrSpecMerged = mergeObjects(attrSpecA, attrSpecB);
1115
+ if (attrSpecMerged) attrs[name] = attrSpecMerged;
1116
+ }
1117
+ return mergeObjects(a, b, {
1118
+ attrs,
1119
+ parseDOM: [...a.parseDOM ?? [], ...b.parseDOM ?? []]
1120
+ });
1121
+ }
1122
+
1123
+ //#endregion
1124
+ //#region src/utils/output-spec.ts
1125
+ function wrapOutputSpecAttrs(toDOM, options) {
1126
+ return (node, ...args) => {
1127
+ return insertOutputSpecAttrs(toDOM(node, ...args), options.map((option) => option.toDOM?.(node.attrs[option.attr])).filter(isNotNullish));
1128
+ };
1129
+ }
1130
+ function wrapTagParseRuleAttrs(rule, options) {
1131
+ const existingGetAttrs = rule.getAttrs;
1132
+ const existingAttrs = rule.attrs;
1133
+ return {
1134
+ ...rule,
1135
+ getAttrs: (dom) => {
1136
+ const baseAttrs = existingGetAttrs?.(dom) ?? existingAttrs ?? {};
1137
+ if (baseAttrs === false || !dom || !isElementLike(dom)) return baseAttrs ?? null;
1138
+ const insertedAttrs = {};
1139
+ for (const option of options) if (option.parseDOM) insertedAttrs[option.attr] = option.parseDOM(dom);
1140
+ return {
1141
+ ...baseAttrs,
1142
+ ...insertedAttrs
1143
+ };
1144
+ }
1145
+ };
1146
+ }
1147
+ function wrapParseRuleAttrs(rule, attrs) {
1148
+ if (rule.tag) return wrapTagParseRuleAttrs(rule, attrs);
1149
+ return rule;
1150
+ }
1151
+ function insertOutputSpecAttrs(dom, attrs) {
1152
+ if (!dom) return dom;
1153
+ if (Array.isArray(dom)) {
1154
+ const rest = dom.slice(1);
1155
+ let oldAttrs;
1156
+ if (rest.length > 0 && (rest[0] == null || typeof rest[0] === "object")) oldAttrs = rest.shift();
1157
+ else oldAttrs = {};
1158
+ const newAttrs = setObjectAttributes(oldAttrs, attrs);
1159
+ return [
1160
+ dom[0],
1161
+ newAttrs,
1162
+ ...rest
1163
+ ];
1164
+ }
1165
+ if (isElementLike(dom)) return setElementAttributes(dom, attrs);
1166
+ if (typeof dom === "object" && "dom" in dom && isElementLike(dom.dom)) return {
1167
+ ...dom,
1168
+ dom: setElementAttributes(dom.dom, attrs)
1169
+ };
1170
+ return dom;
1171
+ }
1172
+ function setObjectAttributes(obj, attrs) {
1173
+ obj = { ...obj };
1174
+ for (const [key, value] of attrs) {
1175
+ const oldValue = obj[key];
1176
+ const newValue = key === "style" ? joinStyles(value, typeof oldValue === "string" ? oldValue : "") : value;
1177
+ obj[key] = newValue;
1178
+ }
1179
+ return obj;
1180
+ }
1181
+ function setElementAttributes(element, attrs) {
1182
+ element = element.cloneNode(true);
1183
+ for (const [key, value] of attrs) {
1184
+ const oldValue = element.getAttribute(key);
1185
+ const newValue = key === "style" ? joinStyles(value, typeof oldValue === "string" ? oldValue : "") : value;
1186
+ element.setAttribute(key, newValue);
1187
+ }
1188
+ return element;
1189
+ }
1190
+ function joinStyles(...styles) {
1191
+ return styles.map((style) => style.trim().replace(/;$/, "")).filter(Boolean).join("; ");
1236
1192
  }
1237
1193
 
1238
1194
  //#endregion
1239
1195
  //#region src/extensions/mark-spec.ts
1240
1196
  /**
1197
+ * Defines a mark type into the editor schema.
1198
+ *
1241
1199
  * @public
1200
+ *
1201
+ * @example
1202
+ *
1203
+ * ```ts
1204
+ * const extension = defineMarkSpec({
1205
+ * name: 'bold',
1206
+ * parseDOM: [
1207
+ * { tag: 'strong' },
1208
+ * { tag: 'b' },
1209
+ * ],
1210
+ * toDOM() {
1211
+ * return ['strong', 0]
1212
+ * },
1213
+ * })
1214
+ * ```
1242
1215
  */
1243
1216
  function defineMarkSpec(options) {
1244
1217
  return defineFacetPayload(markSpecFacet, [[options, void 0]]);
@@ -1254,25 +1227,27 @@ const markSpecFacet = defineFacet({
1254
1227
  let specs = OrderedMap.from({});
1255
1228
  const specPayloads = payloads.map((input) => input[0]).filter(isNotNullish);
1256
1229
  const attrPayloads = payloads.map((input) => input[1]).filter(isNotNullish);
1257
- for (const { name,...spec } of specPayloads) {
1230
+ for (const { name, ...spec } of specPayloads) {
1258
1231
  const prevSpec = specs.get(name);
1259
1232
  if (prevSpec) specs = specs.update(name, mergeSpecs(prevSpec, spec));
1260
1233
  else specs = specs.addToStart(name, spec);
1261
1234
  }
1262
- const groupedAttrs = groupBy(attrPayloads, (payload) => payload.type);
1263
- for (const [type, attrs] of Object.entries(groupedAttrs)) {
1235
+ const groupedAttrs = mapGroupBy(attrPayloads, (payload) => payload.type);
1236
+ for (const [type, attrs] of groupedAttrs.entries()) {
1264
1237
  if (!attrs) continue;
1265
- const maybeSpec = specs.get(type);
1266
- assert(maybeSpec, `Mark type ${type} must be defined`);
1267
- const spec = clone(maybeSpec);
1268
- if (!spec.attrs) spec.attrs = {};
1269
- for (const attr of attrs) spec.attrs[attr.attr] = {
1238
+ const oldSpec = specs.get(type);
1239
+ assert(oldSpec, `Mark type ${type} must be defined`);
1240
+ const newSpec = {
1241
+ ...oldSpec,
1242
+ attrs: { ...oldSpec.attrs }
1243
+ };
1244
+ for (const attr of attrs) newSpec.attrs[attr.attr] = {
1270
1245
  default: attr.default,
1271
1246
  validate: attr.validate
1272
1247
  };
1273
- if (spec.toDOM) spec.toDOM = wrapOutputSpecAttrs(spec.toDOM, attrs);
1274
- if (spec.parseDOM) spec.parseDOM = spec.parseDOM.map((rule) => wrapParseRuleAttrs(rule, attrs));
1275
- specs = specs.update(type, spec);
1248
+ if (oldSpec.toDOM) newSpec.toDOM = wrapOutputSpecAttrs(oldSpec.toDOM, attrs);
1249
+ if (oldSpec.parseDOM) newSpec.parseDOM = oldSpec.parseDOM.map((rule) => wrapParseRuleAttrs(rule, attrs));
1250
+ specs = specs.update(type, newSpec);
1276
1251
  }
1277
1252
  return {
1278
1253
  marks: specs,
@@ -1282,10 +1257,6 @@ const markSpecFacet = defineFacet({
1282
1257
  parent: schemaSpecFacet,
1283
1258
  singleton: true
1284
1259
  });
1285
- function wrapParseRuleAttrs(rule, attrs) {
1286
- if (rule.tag) return wrapTagParseRuleAttrs(rule, attrs);
1287
- return rule;
1288
- }
1289
1260
 
1290
1261
  //#endregion
1291
1262
  //#region src/extensions/mark-view.ts
@@ -1338,6 +1309,77 @@ const markViewFactoryFacet = defineFacet({
1338
1309
  parent: pluginFacet
1339
1310
  });
1340
1311
 
1312
+ //#endregion
1313
+ //#region src/extensions/node-spec.ts
1314
+ /**
1315
+ * Defines a node type into the editor schema.
1316
+ *
1317
+ * @public
1318
+ *
1319
+ * @example
1320
+ *
1321
+ * ```ts
1322
+ * const extension = defineNodeSpec({
1323
+ * name: 'fancyParagraph',
1324
+ * content: 'inline*',
1325
+ * group: 'block',
1326
+ * parseDOM: [{ tag: 'p.fancy' }],
1327
+ * toDOM() {
1328
+ * return ['p', { 'class': 'fancy' }, 0]
1329
+ * },
1330
+ * })
1331
+ * ```
1332
+ */
1333
+ function defineNodeSpec(options) {
1334
+ return defineFacetPayload(nodeSpecFacet, [[options, void 0]]);
1335
+ }
1336
+ /**
1337
+ * Defines an attribute for a node type.
1338
+ *
1339
+ * @public
1340
+ */
1341
+ function defineNodeAttr(options) {
1342
+ return defineFacetPayload(nodeSpecFacet, [[void 0, options]]);
1343
+ }
1344
+ const nodeSpecFacet = defineFacet({
1345
+ reducer: (payloads) => {
1346
+ let specs = OrderedMap.from({});
1347
+ let topNodeName = void 0;
1348
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNullish);
1349
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNullish);
1350
+ for (const { name, topNode, ...spec } of specPayloads) {
1351
+ if (topNode) topNodeName = name;
1352
+ const prevSpec = specs.get(name);
1353
+ if (prevSpec) specs = specs.update(name, mergeSpecs(prevSpec, spec));
1354
+ else specs = specs.addToStart(name, spec);
1355
+ }
1356
+ const groupedAttrs = mapGroupBy(attrPayloads, (payload) => payload.type);
1357
+ for (const [type, attrs] of groupedAttrs.entries()) {
1358
+ if (!attrs) continue;
1359
+ const oldSpec = specs.get(type);
1360
+ assert(oldSpec, `Node type ${type} must be defined`);
1361
+ const newSpec = {
1362
+ ...oldSpec,
1363
+ attrs: { ...oldSpec.attrs }
1364
+ };
1365
+ for (const attr of attrs) newSpec.attrs[attr.attr] = {
1366
+ default: attr.default,
1367
+ validate: attr.validate,
1368
+ splittable: attr.splittable
1369
+ };
1370
+ if (oldSpec.toDOM) newSpec.toDOM = wrapOutputSpecAttrs(oldSpec.toDOM, attrs);
1371
+ if (oldSpec.parseDOM) newSpec.parseDOM = oldSpec.parseDOM.map((rule) => wrapTagParseRuleAttrs(rule, attrs));
1372
+ specs = specs.update(type, newSpec);
1373
+ }
1374
+ return {
1375
+ nodes: specs,
1376
+ topNode: topNodeName
1377
+ };
1378
+ },
1379
+ parent: schemaSpecFacet,
1380
+ singleton: true
1381
+ });
1382
+
1341
1383
  //#endregion
1342
1384
  //#region src/extensions/node-view.ts
1343
1385
  function defineNodeView(options) {
@@ -1389,57 +1431,6 @@ const nodeViewFactoryFacet = defineFacet({
1389
1431
  parent: pluginFacet
1390
1432
  });
1391
1433
 
1392
- //#endregion
1393
- //#region src/extensions/paragraph.ts
1394
- /**
1395
- * Defines a paragraph node spec.
1396
- */
1397
- function defineParagraphSpec() {
1398
- return defineNodeSpec({
1399
- name: "paragraph",
1400
- content: "inline*",
1401
- group: "block",
1402
- parseDOM: [{ tag: "p" }],
1403
- toDOM() {
1404
- return ["p", 0];
1405
- }
1406
- });
1407
- }
1408
- /**
1409
- * @public
1410
- *
1411
- * Defines a paragraph node spec as the highest priority, because it should be the default block node for most cases.
1412
- *
1413
- * @deprecated Use the following import instead:
1414
- *
1415
- * ```ts
1416
- * import { defineParagraph } from 'prosekit/extensions/paragraph'
1417
- * ```
1418
- */
1419
- function defineParagraph() {
1420
- console.warn("[prosekit] The `defineParagraph` function from `prosekit/core` is deprecated. Use the following import instead: `import { defineParagraph } from \"prosekit/extensions/paragraph\"`.");
1421
- return withPriority(defineParagraphSpec(), Priority.highest);
1422
- }
1423
-
1424
- //#endregion
1425
- //#region src/extensions/text.ts
1426
- /**
1427
- * @public
1428
- *
1429
- * @deprecated Use the following import instead:
1430
- *
1431
- * ```ts
1432
- * import { defineText } from 'prosekit/extensions/text'
1433
- * ```
1434
- */
1435
- function defineText() {
1436
- console.warn("[prosekit] The `defineText` function from `prosekit/core` is deprecated. Use the following import instead: `import { defineText } from \"prosekit/extensions/text\"`.");
1437
- return defineNodeSpec({
1438
- name: "text",
1439
- group: "inline"
1440
- });
1441
- }
1442
-
1443
1434
  //#endregion
1444
1435
  //#region src/utils/can-use-regex-lookbehind.ts
1445
1436
  /**
@@ -1464,41 +1455,6 @@ const canUseRegexLookbehind = once(() => {
1464
1455
  */
1465
1456
  const clsx = clsxLite;
1466
1457
 
1467
- //#endregion
1468
- //#region src/utils/collect-children.ts
1469
- /**
1470
- * Collects all children of a node or a fragment, and returns them as an array.
1471
- *
1472
- * @deprecated Use `node.children` or `fragment.content` instead.
1473
- *
1474
- * @hidden
1475
- */
1476
- function collectChildren(parent) {
1477
- const children = [];
1478
- for (let i = 0; i < parent.childCount; i++) children.push(parent.child(i));
1479
- return children;
1480
- }
1481
-
1482
- //#endregion
1483
- //#region src/utils/collect-nodes.ts
1484
- /**
1485
- * Collects all nodes from a given content.
1486
- *
1487
- * @deprecated Use `collectChildren` instead.
1488
- *
1489
- * @hidden
1490
- */
1491
- function collectNodes(content) {
1492
- if (Array.isArray(content)) return content.flatMap(collectNodes);
1493
- if (content instanceof ProseMirrorNode) return [content];
1494
- if (content instanceof ProseMirrorFragment) {
1495
- const nodes = [];
1496
- for (let i = 0; i < content.childCount; i++) nodes.push(content.child(i));
1497
- return nodes;
1498
- }
1499
- throw new ProseKitError(`Invalid node content: ${typeof content}`);
1500
- }
1501
-
1502
1458
  //#endregion
1503
1459
  //#region src/utils/contains-inline-node.ts
1504
1460
  /**
@@ -1513,21 +1469,6 @@ function containsInlineNode(doc, from, to) {
1513
1469
  return found;
1514
1470
  }
1515
1471
 
1516
- //#endregion
1517
- //#region src/utils/get-id.ts
1518
- let id = 0;
1519
- /**
1520
- * Returns a unique id in the current process that can be used in various places.
1521
- *
1522
- * @internal
1523
- *
1524
- * @deprecated Import `getId` from `@ocavue/utils` package instead. Remove it in a future version.
1525
- */
1526
- function getId() {
1527
- id = (id + 1) % Number.MAX_SAFE_INTEGER;
1528
- return `id:${id}`;
1529
- }
1530
-
1531
1472
  //#endregion
1532
1473
  //#region src/utils/is-at-block-start.ts
1533
1474
  /**
@@ -1584,5 +1525,5 @@ function withSkipCodeBlock(command) {
1584
1525
  }
1585
1526
 
1586
1527
  //#endregion
1587
- export { Editor, EditorNotFoundError, OBJECT_REPLACEMENT_CHARACTER, Priority, ProseKitError, getId as _getId, addMark, assert, canUseRegexLookbehind, clsx, collectChildren, collectNodes, containsInlineNode, createEditor, defaultBlockAt, defineBaseCommands, defineBaseKeymap, defineClickHandler, defineClickOnHandler, defineClipboardSerializer, defineCommands, defineDOMEventHandler, defineDefaultState, defineDoc, defineDocChangeHandler, defineDoubleClickHandler, defineDoubleClickOnHandler, defineDropHandler, defineFacet, defineFacetPayload, defineFocusChangeHandler, defineHistory, defineKeyDownHandler, defineKeyPressHandler, defineKeymap, defineMarkAttr, defineMarkSpec, defineMarkView, defineMarkViewComponent, defineMarkViewFactory, defineMountHandler, defineNodeAttr, defineNodeSpec, defineNodeView, defineNodeViewComponent, defineNodeViewFactory, defineParagraph, definePasteHandler, definePlugin, defineScrollToSelectionHandler, defineText, defineTextInputHandler, defineTripleClickHandler, defineTripleClickOnHandler, defineUnmountHandler, defineUpdateHandler, editorEventFacet, elementFromJSON, elementFromNode, expandMark, findParentNode, findParentNodeOfType, getMarkType, getNodeType, htmlFromJSON, htmlFromNode, insertDefaultBlock, insertNode, isAllSelection, isApple, isAtBlockStart, isFragment, isInCodeBlock, isMark, isMarkAbsent, isMarkActive, isNodeSelection, isProseMirrorNode, isSelection, isSlice, isTextSelection, jsonFromHTML, jsonFromNode, jsonFromState, keymapFacet, maybeRun, nodeFromElement, nodeFromHTML, nodeFromJSON, pluginFacet, removeMark, removeNode, setBlockType, setNodeAttrs, setSelectionAround, stateFromJSON, toggleMark, toggleNode, toggleWrap, union, unsetBlockType, unsetMark, withPriority, withSkipCodeBlock, wrap };
1528
+ export { Editor, EditorNotFoundError, OBJECT_REPLACEMENT_CHARACTER, Priority, ProseKitError, addMark, assert, canUseRegexLookbehind, clsx, containsInlineNode, createEditor, defaultBlockAt, defineBaseCommands, defineBaseKeymap, defineClickHandler, defineClickOnHandler, defineClipboardSerializer, defineCommands, defineDOMEventHandler, defineDefaultState, defineDocChangeHandler, defineDoubleClickHandler, defineDoubleClickOnHandler, defineDropHandler, defineFacet, defineFacetPayload, defineFocusChangeHandler, defineHistory, defineKeyDownHandler, defineKeyPressHandler, defineKeymap, defineMarkAttr, defineMarkSpec, defineMarkView, defineMarkViewComponent, defineMarkViewFactory, defineMountHandler, defineNodeAttr, defineNodeSpec, defineNodeView, defineNodeViewComponent, defineNodeViewFactory, definePasteHandler, definePlugin, defineScrollToSelectionHandler, defineTextInputHandler, defineTripleClickHandler, defineTripleClickOnHandler, defineUnmountHandler, defineUpdateHandler, editorEventFacet, elementFromJSON, elementFromNode, expandMark, findParentNode, findParentNodeOfType, getMarkType, getNodeType, htmlFromJSON, htmlFromNode, insertDefaultBlock, insertNode, isAllSelection, isApple, isAtBlockStart, isFragment, isInCodeBlock, isMark, isMarkAbsent, isMarkActive, isNodeSelection, isProseMirrorNode, isSelection, isSlice, isTextSelection, jsonFromHTML, jsonFromNode, jsonFromState, keymapFacet, maybeRun, nodeFromElement, nodeFromHTML, nodeFromJSON, pluginFacet, removeMark, removeNode, selectAll, selectBlock, setBlockType, setNodeAttrs, setSelectionAround, stateFromJSON, toggleMark, toggleNode, toggleWrap, union, unsetBlockType, unsetMark, withPriority, withSkipCodeBlock, wrap };
1588
1529
  //# sourceMappingURL=prosekit-core.js.map