@prosekit/core 0.8.7 → 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 (56) 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-B0L9BgMi.js → editor-DGNUXn-u.js} +98 -115
  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 +81 -180
  8. package/dist/prosekit-core.d.ts.map +1 -1
  9. package/dist/prosekit-core.js +316 -403
  10. package/dist/prosekit-core.js.map +1 -1
  11. package/package.json +8 -10
  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 +9 -5
  27. package/src/extensions/keymap.ts +13 -56
  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/output-spec.ts +11 -0
  43. package/src/utils/parse.ts +9 -9
  44. package/dist/editor-B0L9BgMi.js.map +0 -1
  45. package/dist/editor-M9OimMiI.d.ts.map +0 -1
  46. package/src/extensions/doc.ts +0 -31
  47. package/src/extensions/paragraph.ts +0 -61
  48. package/src/extensions/text.ts +0 -34
  49. package/src/types/base-node-view-options.ts +0 -33
  50. package/src/types/object-entries.ts +0 -13
  51. package/src/utils/collect-children.ts +0 -21
  52. package/src/utils/collect-nodes.ts +0 -37
  53. package/src/utils/deep-equals.spec.ts +0 -26
  54. package/src/utils/deep-equals.ts +0 -29
  55. package/src/utils/get-id.spec.ts +0 -14
  56. 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-B0L9BgMi.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] ?? []);
@@ -1169,61 +1002,30 @@ function defineKeymap(keymap$1) {
1169
1002
  */
1170
1003
  const keymapFacet = defineFacet({
1171
1004
  reduce: () => {
1172
- let handler;
1173
- const handlerWrapper = (view, event) => {
1174
- 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;
1175
1008
  return false;
1176
1009
  };
1177
1010
  const plugin = new Plugin({
1178
1011
  key: keymapPluginKey,
1179
- props: { handleKeyDown: handlerWrapper }
1012
+ props: { handleKeyDown: rootHandler }
1180
1013
  });
1181
1014
  return (keymaps) => {
1182
- handler = keydownHandler(mergeKeymaps(toReversed(keymaps)));
1015
+ subHandlers = keymaps.map(keydownHandler).reverse();
1183
1016
  return plugin;
1184
1017
  };
1185
1018
  },
1186
1019
  parent: pluginFacet,
1187
1020
  singleton: true
1188
1021
  });
1189
- function mergeKeymaps(keymaps) {
1190
- const bindings = {};
1191
- for (const keymap$1 of keymaps) for (const [key, command] of Object.entries(keymap$1)) {
1192
- const normalizedKey = normalizeKeyName(key);
1193
- (bindings[normalizedKey] ||= []).push(command);
1194
- }
1195
- return mapValues(bindings, mergeCommands);
1196
- }
1197
- function mergeCommands(commands$1) {
1198
- return chainCommands(...commands$1);
1199
- }
1200
- function normalizeKeyName(name) {
1201
- let parts = name.split(/-(?!$)/), result = parts[parts.length - 1];
1202
- if (result == "Space") result = " ";
1203
- let alt, ctrl, shift, meta;
1204
- for (let i = 0; i < parts.length - 1; i++) {
1205
- let mod = parts[i];
1206
- if (/^(cmd|meta|m)$/i.test(mod)) meta = true;
1207
- else if (/^a(lt)?$/i.test(mod)) alt = true;
1208
- else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
1209
- else if (/^s(hift)?$/i.test(mod)) shift = true;
1210
- else if (/^mod$/i.test(mod)) if (isApple) meta = true;
1211
- else ctrl = true;
1212
- else throw new Error("Unrecognized modifier name: " + mod);
1213
- }
1214
- if (alt) result = "Alt-" + result;
1215
- if (ctrl) result = "Ctrl-" + result;
1216
- if (meta) result = "Meta-" + result;
1217
- if (shift) result = "Shift-" + result;
1218
- return result;
1219
- }
1220
1022
  const keymapPluginKey = new PluginKey("prosekit-keymap");
1221
1023
 
1222
1024
  //#endregion
1223
1025
  //#region src/extensions/history.ts
1224
1026
  const keymap = {
1225
1027
  "Mod-z": undo,
1226
- "Shift-Mod-z": redo
1028
+ "Mod-Z": redo
1227
1029
  };
1228
1030
  if (!isApple) keymap["Mod-y"] = redo;
1229
1031
  const commands = {
@@ -1248,25 +1050,168 @@ function defineHistory({ depth = 200, newGroupDelay = 250 } = {}) {
1248
1050
  //#region src/extensions/keymap-base.ts
1249
1051
  const customEnter = chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitSplittableBlock);
1250
1052
  const customBackspace = chainCommands(deleteSelection, joinTextblockBackward, selectNodeBackward);
1251
- const customBaseKeymap = {
1252
- ...baseKeymap,
1253
- Enter: customEnter,
1254
- Backspace: customBackspace
1255
- };
1256
1053
  /**
1257
1054
  * Defines some basic key bindings.
1258
1055
  *
1056
+ * @param options
1057
+ *
1259
1058
  * @public
1260
1059
  */
1261
- function defineBaseKeymap(options) {
1262
- const priority = options?.priority ?? Priority.low;
1263
- 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("; ");
1264
1192
  }
1265
1193
 
1266
1194
  //#endregion
1267
1195
  //#region src/extensions/mark-spec.ts
1268
1196
  /**
1197
+ * Defines a mark type into the editor schema.
1198
+ *
1269
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
+ * ```
1270
1215
  */
1271
1216
  function defineMarkSpec(options) {
1272
1217
  return defineFacetPayload(markSpecFacet, [[options, void 0]]);
@@ -1287,20 +1232,22 @@ const markSpecFacet = defineFacet({
1287
1232
  if (prevSpec) specs = specs.update(name, mergeSpecs(prevSpec, spec));
1288
1233
  else specs = specs.addToStart(name, spec);
1289
1234
  }
1290
- const groupedAttrs = groupBy(attrPayloads, (payload) => payload.type);
1291
- for (const [type, attrs] of Object.entries(groupedAttrs)) {
1235
+ const groupedAttrs = mapGroupBy(attrPayloads, (payload) => payload.type);
1236
+ for (const [type, attrs] of groupedAttrs.entries()) {
1292
1237
  if (!attrs) continue;
1293
- const maybeSpec = specs.get(type);
1294
- assert(maybeSpec, `Mark type ${type} must be defined`);
1295
- const spec = clone(maybeSpec);
1296
- if (!spec.attrs) spec.attrs = {};
1297
- 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] = {
1298
1245
  default: attr.default,
1299
1246
  validate: attr.validate
1300
1247
  };
1301
- if (spec.toDOM) spec.toDOM = wrapOutputSpecAttrs(spec.toDOM, attrs);
1302
- if (spec.parseDOM) spec.parseDOM = spec.parseDOM.map((rule) => wrapParseRuleAttrs(rule, attrs));
1303
- 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);
1304
1251
  }
1305
1252
  return {
1306
1253
  marks: specs,
@@ -1310,10 +1257,6 @@ const markSpecFacet = defineFacet({
1310
1257
  parent: schemaSpecFacet,
1311
1258
  singleton: true
1312
1259
  });
1313
- function wrapParseRuleAttrs(rule, attrs) {
1314
- if (rule.tag) return wrapTagParseRuleAttrs(rule, attrs);
1315
- return rule;
1316
- }
1317
1260
 
1318
1261
  //#endregion
1319
1262
  //#region src/extensions/mark-view.ts
@@ -1366,6 +1309,77 @@ const markViewFactoryFacet = defineFacet({
1366
1309
  parent: pluginFacet
1367
1310
  });
1368
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
+
1369
1383
  //#endregion
1370
1384
  //#region src/extensions/node-view.ts
1371
1385
  function defineNodeView(options) {
@@ -1417,57 +1431,6 @@ const nodeViewFactoryFacet = defineFacet({
1417
1431
  parent: pluginFacet
1418
1432
  });
1419
1433
 
1420
- //#endregion
1421
- //#region src/extensions/paragraph.ts
1422
- /**
1423
- * Defines a paragraph node spec.
1424
- */
1425
- function defineParagraphSpec() {
1426
- return defineNodeSpec({
1427
- name: "paragraph",
1428
- content: "inline*",
1429
- group: "block",
1430
- parseDOM: [{ tag: "p" }],
1431
- toDOM() {
1432
- return ["p", 0];
1433
- }
1434
- });
1435
- }
1436
- /**
1437
- * @public
1438
- *
1439
- * Defines a paragraph node spec as the highest priority, because it should be the default block node for most cases.
1440
- *
1441
- * @deprecated Use the following import instead:
1442
- *
1443
- * ```ts
1444
- * import { defineParagraph } from 'prosekit/extensions/paragraph'
1445
- * ```
1446
- */
1447
- function defineParagraph() {
1448
- console.warn("[prosekit] The `defineParagraph` function from `prosekit/core` is deprecated. Use the following import instead: `import { defineParagraph } from \"prosekit/extensions/paragraph\"`.");
1449
- return withPriority(defineParagraphSpec(), Priority.highest);
1450
- }
1451
-
1452
- //#endregion
1453
- //#region src/extensions/text.ts
1454
- /**
1455
- * @public
1456
- *
1457
- * @deprecated Use the following import instead:
1458
- *
1459
- * ```ts
1460
- * import { defineText } from 'prosekit/extensions/text'
1461
- * ```
1462
- */
1463
- function defineText() {
1464
- console.warn("[prosekit] The `defineText` function from `prosekit/core` is deprecated. Use the following import instead: `import { defineText } from \"prosekit/extensions/text\"`.");
1465
- return defineNodeSpec({
1466
- name: "text",
1467
- group: "inline"
1468
- });
1469
- }
1470
-
1471
1434
  //#endregion
1472
1435
  //#region src/utils/can-use-regex-lookbehind.ts
1473
1436
  /**
@@ -1492,41 +1455,6 @@ const canUseRegexLookbehind = once(() => {
1492
1455
  */
1493
1456
  const clsx = clsxLite;
1494
1457
 
1495
- //#endregion
1496
- //#region src/utils/collect-children.ts
1497
- /**
1498
- * Collects all children of a node or a fragment, and returns them as an array.
1499
- *
1500
- * @deprecated Use `node.children` or `fragment.content` instead.
1501
- *
1502
- * @hidden
1503
- */
1504
- function collectChildren(parent) {
1505
- const children = [];
1506
- for (let i = 0; i < parent.childCount; i++) children.push(parent.child(i));
1507
- return children;
1508
- }
1509
-
1510
- //#endregion
1511
- //#region src/utils/collect-nodes.ts
1512
- /**
1513
- * Collects all nodes from a given content.
1514
- *
1515
- * @deprecated Use `collectChildren` instead.
1516
- *
1517
- * @hidden
1518
- */
1519
- function collectNodes(content) {
1520
- if (Array.isArray(content)) return content.flatMap(collectNodes);
1521
- if (content instanceof ProseMirrorNode) return [content];
1522
- if (content instanceof ProseMirrorFragment) {
1523
- const nodes = [];
1524
- for (let i = 0; i < content.childCount; i++) nodes.push(content.child(i));
1525
- return nodes;
1526
- }
1527
- throw new ProseKitError(`Invalid node content: ${typeof content}`);
1528
- }
1529
-
1530
1458
  //#endregion
1531
1459
  //#region src/utils/contains-inline-node.ts
1532
1460
  /**
@@ -1541,21 +1469,6 @@ function containsInlineNode(doc, from, to) {
1541
1469
  return found;
1542
1470
  }
1543
1471
 
1544
- //#endregion
1545
- //#region src/utils/get-id.ts
1546
- let id = 0;
1547
- /**
1548
- * Returns a unique id in the current process that can be used in various places.
1549
- *
1550
- * @internal
1551
- *
1552
- * @deprecated Import `getId` from `@ocavue/utils` package instead. Remove it in a future version.
1553
- */
1554
- function getId() {
1555
- id = (id + 1) % Number.MAX_SAFE_INTEGER;
1556
- return `id:${id}`;
1557
- }
1558
-
1559
1472
  //#endregion
1560
1473
  //#region src/utils/is-at-block-start.ts
1561
1474
  /**
@@ -1612,5 +1525,5 @@ function withSkipCodeBlock(command) {
1612
1525
  }
1613
1526
 
1614
1527
  //#endregion
1615
- 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 };
1616
1529
  //# sourceMappingURL=prosekit-core.js.map