@prosekit/core 0.2.2 → 0.2.4

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.
@@ -3,6 +3,7 @@ import { Attrs } from '@prosekit/pm/model';
3
3
  import { Attrs as Attrs_2 } from 'prosemirror-model';
4
4
  import { Command } from '@prosekit/pm/state';
5
5
  import type { ConditionalExcept } from 'type-fest';
6
+ import type { ContentMatch } from '@prosekit/pm/model';
6
7
  import type { DirectEditorProps } from '@prosekit/pm/view';
7
8
  import { EditorState } from '@prosekit/pm/state';
8
9
  import type { EditorStateConfig } from '@prosekit/pm/state';
@@ -120,6 +121,17 @@ declare interface BaseNodeViewOptions {
120
121
  export { BaseNodeViewOptions }
121
122
  export { BaseNodeViewOptions as BaseNodeViewOptions_alias_1 }
122
123
 
124
+ /**
125
+ * A utility for constructing `className` strings conditionally.
126
+ *
127
+ * It is a re-export of [clsx/lite](https://www.npmjs.com/package/clsx) with stricter types.
128
+ *
129
+ * @public
130
+ */
131
+ declare const clsx: (...args: Array<string | boolean | null | undefined>) => string;
132
+ export { clsx }
133
+ export { clsx as clsx_alias_1 }
134
+
123
135
  export declare function collectNodes(content: NodeContent): ProseMirrorNode[];
124
136
 
125
137
  export declare interface CommandApplier<Args extends any[] = any[]> {
@@ -169,6 +181,13 @@ export declare const default_alias_1: {
169
181
  };
170
182
  };
171
183
 
184
+ /**
185
+ * @internal
186
+ */
187
+ declare function defaultBlockAt(match: ContentMatch): NodeType_2 | null;
188
+ export { defaultBlockAt }
189
+ export { defaultBlockAt as defaultBlockAt_alias_1 }
190
+
172
191
  declare interface DefaultStateOptions {
173
192
  /**
174
193
  * A JSON object representing the starting document to use when creating the
@@ -286,6 +305,15 @@ declare function defineDocChangeHandler(handler: DocChangeHandler): Extension<Ex
286
305
  export { defineDocChangeHandler }
287
306
  export { defineDocChangeHandler as defineDocChangeHandler_alias_1 }
288
307
 
308
+ /**
309
+ * Registers a event handler that is called when the editor gains or loses focus.
310
+ *
311
+ * @public
312
+ */
313
+ declare function defineFocusChangeHandler(handler: FocusChangeHandler): Extension<ExtensionTyping<string, string, CommandArgs>>;
314
+ export { defineFocusChangeHandler }
315
+ export { defineFocusChangeHandler as defineFocusChangeHandler_alias_1 }
316
+
289
317
  /**
290
318
  * Add undo/redo history to the editor.
291
319
  */
@@ -321,6 +349,13 @@ declare function defineKeymap(keymap: Keymap): Extension;
321
349
  export { defineKeymap }
322
350
  export { defineKeymap as defineKeymap_alias_1 }
323
351
 
352
+ /**
353
+ * @public
354
+ */
355
+ declare function defineMarkAttr(options: MarkAttrOptions): Extension;
356
+ export { defineMarkAttr }
357
+ export { defineMarkAttr as defineMarkAttr_alias_1 }
358
+
324
359
  /**
325
360
  * @public
326
361
  */
@@ -340,6 +375,17 @@ export { defineMountHandler }
340
375
  export { defineMountHandler as defineMountHandler_alias_1 }
341
376
 
342
377
  /**
378
+ * Defines an attribute for a node type.
379
+ *
380
+ * @public
381
+ */
382
+ declare function defineNodeAttr(options: NodeAttrOptions): Extension;
383
+ export { defineNodeAttr }
384
+ export { defineNodeAttr as defineNodeAttr_alias_1 }
385
+
386
+ /**
387
+ * Defines a node type.
388
+ *
343
389
  * @public
344
390
  */
345
391
  declare function defineNodeSpec<NodeName extends string>(options: NodeSpecOptions<NodeName>): Extension<{
@@ -443,12 +489,33 @@ declare class Editor<E extends Extension = any> {
443
489
  * @internal
444
490
  */
445
491
  static create(instance: any): Editor<any>;
492
+ /**
493
+ * Whether the editor is mounted.
494
+ */
446
495
  get mounted(): boolean;
496
+ /**
497
+ * The editor view.
498
+ */
447
499
  get view(): EditorView;
500
+ /**
501
+ * The editor schema.
502
+ */
448
503
  get schema(): Schema<ExtractNodes<E>, ExtractMarks<E>>;
449
504
  get commands(): ExtractCommandAppliers<E>;
505
+ /**
506
+ * Whether the editor is focused.
507
+ */
508
+ get focused(): boolean;
450
509
  mount(place: HTMLElement | null | undefined | void): void;
451
510
  unmount(): void;
511
+ /**
512
+ * Focus the editor.
513
+ */
514
+ focus(): void;
515
+ /**
516
+ * Blur the editor.
517
+ */
518
+ blur(): void;
452
519
  use(extension: Extension): VoidFunction;
453
520
  get nodes(): Record<ExtractNodes<E>, NodeBuilder>;
454
521
  get marks(): Record<ExtractMarks<E>, MarkBuilder>;
@@ -638,6 +705,17 @@ declare interface FacetOptions<Input, Output> {
638
705
  export { FacetOptions }
639
706
  export { FacetOptions as FacetOptions_alias_1 }
640
707
 
708
+ /**
709
+ * A function that is called when the editor gains or loses focus.
710
+ *
711
+ * @param hasFocus - Whether the editor has focus.
712
+ *
713
+ * @public
714
+ */
715
+ declare type FocusChangeHandler = (hasFocus: boolean) => void;
716
+ export { FocusChangeHandler }
717
+ export { FocusChangeHandler as FocusChangeHandler_alias_1 }
718
+
641
719
  export declare function getBrowserDocument(): Document | undefined;
642
720
 
643
721
  export declare function getBrowserWindow(): (Window & typeof globalThis) | null | undefined;
@@ -701,6 +779,8 @@ declare function isAllSelection(sel: Selection_2): sel is AllSelection;
701
779
  export { isAllSelection }
702
780
  export { isAllSelection as isAllSelection_alias_1 }
703
781
 
782
+ export declare function isElement(value: unknown): value is Element;
783
+
704
784
  export declare const isMac: boolean;
705
785
 
706
786
  /**
@@ -796,6 +876,36 @@ declare type KeymapPayload = Keymap;
796
876
  export { KeymapPayload }
797
877
  export { KeymapPayload as KeymapPayload_alias_1 }
798
878
 
879
+ /**
880
+ * @public
881
+ */
882
+ declare interface MarkAttrOptions {
883
+ /**
884
+ * The name of the mark type.
885
+ */
886
+ type: string;
887
+ /**
888
+ * The name of the attribute.
889
+ */
890
+ attr: string;
891
+ /**
892
+ * The default value for this attribute, to use when no explicit value is
893
+ * provided. Attributes that have no default must be provided whenever a mark
894
+ * of a type that has them is created.
895
+ */
896
+ default?: any;
897
+ /**
898
+ * Returns the attribute key and value to be set on the DOM node.
899
+ */
900
+ toDOM?: (value: any) => [key: string, value: string] | null | void;
901
+ /**
902
+ * Parses the attribute value from the DOM.
903
+ */
904
+ parseDOM?: (node: HTMLElement) => any;
905
+ }
906
+ export { MarkAttrOptions }
907
+ export { MarkAttrOptions as MarkAttrOptions_alias_1 }
908
+
799
909
  export declare interface MarkBuilder {
800
910
  (attrs: Attrs | null, ...children: NodeChild[]): ProseMirrorNode[];
801
911
  (...children: NodeChild[]): ProseMirrorNode[];
@@ -822,6 +932,36 @@ declare type MountHandler = (view: EditorView) => void;
822
932
  export { MountHandler }
823
933
  export { MountHandler as MountHandler_alias_1 }
824
934
 
935
+ /**
936
+ * @public
937
+ */
938
+ declare interface NodeAttrOptions {
939
+ /**
940
+ * The name of the node type.
941
+ */
942
+ type: string;
943
+ /**
944
+ * The name of the attribute.
945
+ */
946
+ attr: string;
947
+ /**
948
+ * The default value for this attribute, to use when no explicit value is
949
+ * provided. Attributes that have no default must be provided whenever a node
950
+ * of a type that has them is created.
951
+ */
952
+ default?: any;
953
+ /**
954
+ * Returns the attribute key and value to be set on the DOM node.
955
+ */
956
+ toDOM?: (value: any) => [key: string, value: string] | null | void;
957
+ /**
958
+ * Parses the attribute value from the DOM.
959
+ */
960
+ parseDOM?: (node: HTMLElement) => any;
961
+ }
962
+ export { NodeAttrOptions }
963
+ export { NodeAttrOptions as NodeAttrOptions_alias_1 }
964
+
825
965
  export declare interface NodeBuilder {
826
966
  (attrs: Attrs | null, ...children: NodeChild[]): ProseMirrorNode;
827
967
  (...children: NodeChild[]): ProseMirrorNode;
@@ -906,6 +1046,13 @@ declare interface NodeViewOptions {
906
1046
  export { NodeViewOptions }
907
1047
  export { NodeViewOptions as NodeViewOptions_alias_1 }
908
1048
 
1049
+ /**
1050
+ * @internal
1051
+ */
1052
+ declare const OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
1053
+ export { OBJECT_REPLACEMENT_CHARACTER }
1054
+ export { OBJECT_REPLACEMENT_CHARACTER as OBJECT_REPLACEMENT_CHARACTER_alias_1 }
1055
+
909
1056
  export declare function objectEqual<T>(a: T, b: T): boolean;
910
1057
 
911
1058
  declare type Payload = unknown;
@@ -931,6 +1078,8 @@ export { PluginPayload }
931
1078
  export { PluginPayload as PluginPayload_alias_1 }
932
1079
 
933
1080
  /**
1081
+ * ProseKit extension priority.
1082
+ *
934
1083
  * @public
935
1084
  */
936
1085
  declare const enum Priority {
@@ -1146,6 +1295,13 @@ declare function withPriority<T extends Extension>(extension: T, priority: Prior
1146
1295
  export { withPriority }
1147
1296
  export { withPriority as withPriority_alias_1 }
1148
1297
 
1298
+ /**
1299
+ * @internal
1300
+ */
1301
+ declare function withSkipCodeBlock(command: Command): Command;
1302
+ export { withSkipCodeBlock }
1303
+ export { withSkipCodeBlock as withSkipCodeBlock_alias_1 }
1304
+
1149
1305
  export declare function wrap({ nodeType, attrs, }: {
1150
1306
  nodeType: NodeType;
1151
1307
  attrs?: Attrs | null;
@@ -15,14 +15,16 @@ export { defineCommands } from './_tsup-dts-rollup';
15
15
  export { defineDefaultState } from './_tsup-dts-rollup';
16
16
  export { DefaultStateOptions } from './_tsup-dts-rollup';
17
17
  export { defineDoc } from './_tsup-dts-rollup';
18
+ export { defineDocChangeHandler } from './_tsup-dts-rollup';
19
+ export { DocChangeHandler } from './_tsup-dts-rollup';
20
+ export { defineFocusChangeHandler } from './_tsup-dts-rollup';
21
+ export { FocusChangeHandler } from './_tsup-dts-rollup';
18
22
  export { defineMountHandler } from './_tsup-dts-rollup';
19
23
  export { defineUnmountHandler } from './_tsup-dts-rollup';
20
24
  export { defineUpdateHandler } from './_tsup-dts-rollup';
21
25
  export { MountHandler } from './_tsup-dts-rollup';
22
26
  export { UnmountHandler } from './_tsup-dts-rollup';
23
27
  export { UpdateHandler } from './_tsup-dts-rollup';
24
- export { defineDocChangeHandler } from './_tsup-dts-rollup';
25
- export { DocChangeHandler } from './_tsup-dts-rollup';
26
28
  export { defineHistory } from './_tsup-dts-rollup';
27
29
  export { defineInputRule } from './_tsup-dts-rollup';
28
30
  export { defineBaseKeymap } from './_tsup-dts-rollup';
@@ -30,9 +32,13 @@ export { defineKeymap } from './_tsup-dts-rollup';
30
32
  export { keymapFacet } from './_tsup-dts-rollup';
31
33
  export { Keymap } from './_tsup-dts-rollup';
32
34
  export { KeymapPayload } from './_tsup-dts-rollup';
35
+ export { defineMarkAttr } from './_tsup-dts-rollup';
33
36
  export { defineMarkSpec } from './_tsup-dts-rollup';
37
+ export { MarkAttrOptions } from './_tsup-dts-rollup';
34
38
  export { MarkSpecOptions } from './_tsup-dts-rollup';
39
+ export { defineNodeAttr } from './_tsup-dts-rollup';
35
40
  export { defineNodeSpec } from './_tsup-dts-rollup';
41
+ export { NodeAttrOptions } from './_tsup-dts-rollup';
36
42
  export { NodeSpecOptions } from './_tsup-dts-rollup';
37
43
  export { defineNodeView } from './_tsup-dts-rollup';
38
44
  export { NodeViewOptions } from './_tsup-dts-rollup';
@@ -59,6 +65,8 @@ export { SelectionJSON } from './_tsup-dts-rollup';
59
65
  export { StateJSON } from './_tsup-dts-rollup';
60
66
  export { Priority } from './_tsup-dts-rollup';
61
67
  export { SimplifyUnion } from './_tsup-dts-rollup';
68
+ export { clsx } from './_tsup-dts-rollup';
69
+ export { defaultBlockAt } from './_tsup-dts-rollup';
62
70
  export { _getId } from './_tsup-dts-rollup';
63
71
  export { getMarkType } from './_tsup-dts-rollup';
64
72
  export { getNodeType } from './_tsup-dts-rollup';
@@ -75,3 +83,5 @@ export { isMark } from './_tsup-dts-rollup';
75
83
  export { isNodeSelection } from './_tsup-dts-rollup';
76
84
  export { isProseMirrorNode } from './_tsup-dts-rollup';
77
85
  export { isTextSelection } from './_tsup-dts-rollup';
86
+ export { withSkipCodeBlock } from './_tsup-dts-rollup';
87
+ export { OBJECT_REPLACEMENT_CHARACTER } from './_tsup-dts-rollup';
@@ -986,18 +986,34 @@ var Editor = class _Editor {
986
986
  }
987
987
  return new _Editor(instance);
988
988
  }
989
+ /**
990
+ * Whether the editor is mounted.
991
+ */
989
992
  get mounted() {
990
993
  return !!this.instance.view;
991
994
  }
995
+ /**
996
+ * The editor view.
997
+ */
992
998
  get view() {
993
999
  return this.instance.assertView;
994
1000
  }
1001
+ /**
1002
+ * The editor schema.
1003
+ */
995
1004
  get schema() {
996
1005
  return this.instance.schema;
997
1006
  }
998
1007
  get commands() {
999
1008
  return this.instance.commandAppliers;
1000
1009
  }
1010
+ /**
1011
+ * Whether the editor is focused.
1012
+ */
1013
+ get focused() {
1014
+ var _a, _b;
1015
+ return (_b = (_a = this.instance.view) == null ? void 0 : _a.hasFocus()) != null ? _b : false;
1016
+ }
1001
1017
  mount(place) {
1002
1018
  if (!place) {
1003
1019
  return this.unmount();
@@ -1010,6 +1026,20 @@ var Editor = class _Editor {
1010
1026
  this.instance.unmount();
1011
1027
  }
1012
1028
  }
1029
+ /**
1030
+ * Focus the editor.
1031
+ */
1032
+ focus() {
1033
+ var _a;
1034
+ (_a = this.instance.view) == null ? void 0 : _a.focus();
1035
+ }
1036
+ /**
1037
+ * Blur the editor.
1038
+ */
1039
+ blur() {
1040
+ var _a;
1041
+ (_a = this.instance.view) == null ? void 0 : _a.dom.blur();
1042
+ }
1013
1043
  use(extension) {
1014
1044
  if (!this.mounted) {
1015
1045
  let lazyRemove = null;
@@ -1099,26 +1129,110 @@ function defineBaseCommands() {
1099
1129
  });
1100
1130
  }
1101
1131
 
1132
+ // src/utils/is-element.ts
1133
+ var hasElement = typeof Element !== "undefined";
1134
+ function isElement(value) {
1135
+ return hasElement && value instanceof Element;
1136
+ }
1137
+
1138
+ // src/utils/is-not-null.ts
1139
+ function isNotNull(value) {
1140
+ return value != null;
1141
+ }
1142
+
1102
1143
  // src/extensions/node-spec.ts
1103
1144
  function defineNodeSpec(options) {
1104
- return nodeSpecFacet.extension([options]);
1145
+ const payload = [options, void 0];
1146
+ return nodeSpecFacet.extension([payload]);
1147
+ }
1148
+ function defineNodeAttr(options) {
1149
+ const payload = [void 0, options];
1150
+ return nodeSpecFacet.extension([payload]);
1105
1151
  }
1106
1152
  var nodeSpecFacet = Facet.define({
1107
- convert: (options) => {
1153
+ convert: (payloads) => {
1108
1154
  const nodes = {};
1109
1155
  let topNodeName = void 0;
1110
- for (const { name, topNode, ...spec } of options) {
1156
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
1157
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNull);
1158
+ for (const { name, topNode, ...spec } of specPayloads) {
1111
1159
  if (nodes[name]) {
1112
1160
  throw new ProseKitError(`Node type ${name} has already been defined`);
1113
1161
  }
1114
- if (topNodeName && !topNode) {
1162
+ if (topNode) {
1115
1163
  topNodeName = name;
1116
1164
  }
1117
1165
  nodes[name] = spec;
1118
1166
  }
1167
+ for (const {
1168
+ type,
1169
+ attr,
1170
+ default: defaultValue,
1171
+ toDOM,
1172
+ parseDOM
1173
+ } of attrPayloads) {
1174
+ const spec = nodes[type];
1175
+ if (!spec) {
1176
+ throw new ProseKitError(
1177
+ `Node type ${type} must be defined before defining attributes`
1178
+ );
1179
+ }
1180
+ if (!spec.attrs) {
1181
+ spec.attrs = {};
1182
+ }
1183
+ spec.attrs[attr] = { default: defaultValue };
1184
+ if (toDOM && spec.toDOM) {
1185
+ const existingToDom = spec.toDOM;
1186
+ spec.toDOM = (node) => {
1187
+ const dom = existingToDom(node);
1188
+ if (!dom) {
1189
+ return dom;
1190
+ }
1191
+ const attrDOM = toDOM(node.attrs[attr]);
1192
+ if (!attrDOM) {
1193
+ return dom;
1194
+ }
1195
+ const [key, value] = attrDOM;
1196
+ if (!key) {
1197
+ return dom;
1198
+ }
1199
+ if (Array.isArray(dom)) {
1200
+ if (typeof dom[1] === "object") {
1201
+ return [dom[0], { ...dom[1], [key]: value }, ...dom.slice(2)];
1202
+ } else {
1203
+ return [dom[0], { [key]: value }, ...dom.slice(1)];
1204
+ }
1205
+ } else if (isElement(dom)) {
1206
+ dom.setAttribute(key, value);
1207
+ } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
1208
+ dom.dom.setAttribute(key, value);
1209
+ }
1210
+ return dom;
1211
+ };
1212
+ }
1213
+ if (parseDOM && spec.parseDOM) {
1214
+ for (const rule of spec.parseDOM) {
1215
+ const existingGetAttrs = rule.getAttrs;
1216
+ const existingAttrs = rule.attrs;
1217
+ rule.getAttrs = (dom) => {
1218
+ var _a;
1219
+ const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
1220
+ if (attrs === false || !dom || !isElement(dom)) {
1221
+ return attrs != null ? attrs : null;
1222
+ }
1223
+ const value = parseDOM(dom);
1224
+ return {
1225
+ ...attrs,
1226
+ [attr]: value
1227
+ };
1228
+ };
1229
+ }
1230
+ }
1231
+ }
1119
1232
  return { nodes, topNode: topNodeName };
1120
1233
  },
1121
- next: schemaFacet
1234
+ next: schemaFacet,
1235
+ singleton: true
1122
1236
  });
1123
1237
 
1124
1238
  // src/extensions/doc.ts
@@ -1242,6 +1356,28 @@ function defineDocChangeHandler(handler) {
1242
1356
  });
1243
1357
  }
1244
1358
 
1359
+ // src/extensions/events/focus.ts
1360
+ import { PluginKey as PluginKey2, ProseMirrorPlugin as ProseMirrorPlugin2 } from "@prosekit/pm/state";
1361
+ function defineFocusChangeHandler(handler) {
1362
+ const handleFocus = () => handler(true);
1363
+ const handleBlur = () => handler(false);
1364
+ const plugin = new ProseMirrorPlugin2({
1365
+ key: new PluginKey2("prosekit-focus-handler"),
1366
+ view: (view) => {
1367
+ const dom = view.dom;
1368
+ dom.addEventListener("focus", handleFocus);
1369
+ dom.addEventListener("blur", handleBlur);
1370
+ return {
1371
+ destroy: () => {
1372
+ dom.removeEventListener("focus", handleFocus);
1373
+ dom.removeEventListener("blur", handleBlur);
1374
+ }
1375
+ };
1376
+ }
1377
+ });
1378
+ return definePlugin(plugin);
1379
+ }
1380
+
1245
1381
  // src/extensions/history.ts
1246
1382
  import { history, redo, undo } from "@prosekit/pm/history";
1247
1383
 
@@ -1251,7 +1387,7 @@ var isMac = typeof navigator !== "undefined" ? /Mac|iP(hone|[ao]d)/.test(navigat
1251
1387
  // src/extensions/keymap.ts
1252
1388
  import { baseKeymap, chainCommands } from "@prosekit/pm/commands";
1253
1389
  import { keydownHandler } from "@prosekit/pm/keymap";
1254
- import { Plugin as Plugin3, PluginKey as PluginKey2 } from "@prosekit/pm/state";
1390
+ import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@prosekit/pm/state";
1255
1391
  function defineKeymap(keymap) {
1256
1392
  return keymapFacet.extension([keymap]);
1257
1393
  }
@@ -1302,7 +1438,7 @@ function mergeKeymaps(keymaps) {
1302
1438
  ])
1303
1439
  );
1304
1440
  }
1305
- var keymapPluginKey = new PluginKey2("prosekit-keymap");
1441
+ var keymapPluginKey = new PluginKey3("prosekit-keymap");
1306
1442
 
1307
1443
  // src/extensions/history.ts
1308
1444
  function defineHistory() {
@@ -1351,24 +1487,97 @@ var inputRuleFacet = Facet.define({
1351
1487
 
1352
1488
  // src/extensions/mark-spec.ts
1353
1489
  function defineMarkSpec(options) {
1354
- return markSpecFacet.extension([options]);
1490
+ const payload = [options, void 0];
1491
+ return markSpecFacet.extension([payload]);
1492
+ }
1493
+ function defineMarkAttr(options) {
1494
+ const payload = [void 0, options];
1495
+ return markSpecFacet.extension([payload]);
1355
1496
  }
1356
1497
  var markSpecFacet = Facet.define({
1357
- convert: (options) => {
1498
+ convert: (payloads) => {
1358
1499
  const marks = {};
1359
- for (const { name, ...spec } of options) {
1500
+ const specPayloads = payloads.map((input) => input[0]).filter(isNotNull);
1501
+ const attrPayloads = payloads.map((input) => input[1]).filter(isNotNull);
1502
+ for (const { name, ...spec } of specPayloads) {
1360
1503
  if (marks[name]) {
1361
1504
  throw new ProseKitError(`Mark type ${name} has already been defined`);
1362
1505
  }
1363
1506
  marks[name] = spec;
1364
1507
  }
1508
+ for (const {
1509
+ type,
1510
+ attr,
1511
+ default: defaultValue,
1512
+ toDOM,
1513
+ parseDOM
1514
+ } of attrPayloads) {
1515
+ const spec = marks[type];
1516
+ if (!spec) {
1517
+ throw new ProseKitError(
1518
+ `Mark type ${type} must be defined before defining attributes`
1519
+ );
1520
+ }
1521
+ if (!spec.attrs) {
1522
+ spec.attrs = {};
1523
+ }
1524
+ spec.attrs[attr] = { default: defaultValue };
1525
+ if (toDOM && spec.toDOM) {
1526
+ const existingToDom = spec.toDOM;
1527
+ spec.toDOM = (mark, inline) => {
1528
+ const dom = existingToDom(mark, inline);
1529
+ if (!dom) {
1530
+ return dom;
1531
+ }
1532
+ const attrDOM = toDOM(mark.attrs[attr]);
1533
+ if (!attrDOM) {
1534
+ return dom;
1535
+ }
1536
+ const [key, value] = attrDOM;
1537
+ if (!key) {
1538
+ return dom;
1539
+ }
1540
+ if (Array.isArray(dom)) {
1541
+ if (typeof dom[1] === "object") {
1542
+ return [dom[0], { ...dom[1], [key]: value }, ...dom.slice(2)];
1543
+ } else {
1544
+ return [dom[0], { [key]: value }, ...dom.slice(1)];
1545
+ }
1546
+ } else if (isElement(dom)) {
1547
+ dom.setAttribute(key, value);
1548
+ } else if (typeof dom === "object" && "dom" in dom && isElement(dom.dom)) {
1549
+ dom.dom.setAttribute(key, value);
1550
+ }
1551
+ return dom;
1552
+ };
1553
+ }
1554
+ if (parseDOM && spec.parseDOM) {
1555
+ for (const rule of spec.parseDOM) {
1556
+ const existingGetAttrs = rule.getAttrs;
1557
+ const existingAttrs = rule.attrs;
1558
+ rule.getAttrs = (dom) => {
1559
+ var _a;
1560
+ const attrs = (_a = existingGetAttrs == null ? void 0 : existingGetAttrs(dom)) != null ? _a : existingAttrs;
1561
+ if (attrs === false || !dom || !isElement(dom)) {
1562
+ return attrs != null ? attrs : null;
1563
+ }
1564
+ const value = parseDOM(dom);
1565
+ return {
1566
+ ...attrs,
1567
+ [attr]: value
1568
+ };
1569
+ };
1570
+ }
1571
+ }
1572
+ }
1365
1573
  return { marks, nodes: {} };
1366
1574
  },
1367
- next: schemaFacet
1575
+ next: schemaFacet,
1576
+ singleton: true
1368
1577
  });
1369
1578
 
1370
1579
  // src/extensions/node-view.ts
1371
- import { ProseMirrorPlugin as ProseMirrorPlugin2 } from "@prosekit/pm/state";
1580
+ import { ProseMirrorPlugin as ProseMirrorPlugin3 } from "@prosekit/pm/state";
1372
1581
  import "@prosekit/pm/view";
1373
1582
  function defineNodeView(options) {
1374
1583
  return nodeViewFacet.extension([options]);
@@ -1381,13 +1590,13 @@ var nodeViewFacet = Facet.define({
1381
1590
  nodeViews[input.name] = input.constructor;
1382
1591
  }
1383
1592
  }
1384
- return () => [new ProseMirrorPlugin2({ props: { nodeViews } })];
1593
+ return () => [new ProseMirrorPlugin3({ props: { nodeViews } })];
1385
1594
  },
1386
1595
  next: pluginFacet
1387
1596
  });
1388
1597
 
1389
1598
  // src/extensions/node-view-effect.ts
1390
- import { ProseMirrorPlugin as ProseMirrorPlugin3 } from "@prosekit/pm/state";
1599
+ import { ProseMirrorPlugin as ProseMirrorPlugin4 } from "@prosekit/pm/state";
1391
1600
  import "@prosekit/pm/view";
1392
1601
  function defineNodeViewFactory(options) {
1393
1602
  return nodeViewFactoryFacet.extension([options]);
@@ -1415,7 +1624,7 @@ var nodeViewFactoryFacet = Facet.define({
1415
1624
  nodeViews[name] = factory(args);
1416
1625
  }
1417
1626
  }
1418
- return () => [new ProseMirrorPlugin3({ props: { nodeViews } })];
1627
+ return () => [new ProseMirrorPlugin4({ props: { nodeViews } })];
1419
1628
  },
1420
1629
  next: pluginFacet
1421
1630
  });
@@ -1444,31 +1653,70 @@ function defineText() {
1444
1653
  });
1445
1654
  }
1446
1655
 
1656
+ // src/utils/clsx.ts
1657
+ import clsxLite from "clsx/lite";
1658
+ var clsx = clsxLite;
1659
+
1660
+ // src/utils/default-block-at.ts
1661
+ function defaultBlockAt(match) {
1662
+ for (let i = 0; i < match.edgeCount; i++) {
1663
+ const { type } = match.edge(i);
1664
+ if (type.isTextblock && !type.hasRequiredAttrs())
1665
+ return type;
1666
+ }
1667
+ return null;
1668
+ }
1669
+
1447
1670
  // src/utils/get-id.ts
1448
1671
  var id = 0;
1449
1672
  function getId() {
1450
1673
  id = (id + 1) % Number.MAX_SAFE_INTEGER;
1451
1674
  return `id:${id}`;
1452
1675
  }
1676
+
1677
+ // src/utils/unicode.ts
1678
+ var OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
1679
+
1680
+ // src/utils/with-skip-code-block.ts
1681
+ function isCodeBlockType(type) {
1682
+ return type.spec.code && type.isBlock;
1683
+ }
1684
+ function isInCodeBlock(selection) {
1685
+ return isCodeBlockType(selection.$from.parent.type) || isCodeBlockType(selection.$to.parent.type);
1686
+ }
1687
+ function withSkipCodeBlock(command) {
1688
+ return (state, dispatch, view) => {
1689
+ if (isInCodeBlock(state.selection)) {
1690
+ return false;
1691
+ }
1692
+ return command(state, dispatch, view);
1693
+ };
1694
+ }
1453
1695
  export {
1454
1696
  Editor,
1455
1697
  Facet,
1698
+ OBJECT_REPLACEMENT_CHARACTER,
1456
1699
  Priority,
1457
1700
  ProseKitError,
1458
1701
  getId as _getId,
1459
1702
  addMark,
1703
+ clsx,
1460
1704
  createEditor,
1705
+ defaultBlockAt,
1461
1706
  defineBaseCommands,
1462
1707
  defineBaseKeymap,
1463
1708
  defineCommands,
1464
1709
  defineDefaultState,
1465
1710
  defineDoc,
1466
1711
  defineDocChangeHandler,
1712
+ defineFocusChangeHandler,
1467
1713
  defineHistory,
1468
1714
  defineInputRule,
1469
1715
  defineKeymap,
1716
+ defineMarkAttr,
1470
1717
  defineMarkSpec,
1471
1718
  defineMountHandler,
1719
+ defineNodeAttr,
1472
1720
  defineNodeSpec,
1473
1721
  defineNodeView,
1474
1722
  defineNodeViewFactory,
@@ -1500,5 +1748,6 @@ export {
1500
1748
  toggleMark,
1501
1749
  toggleNode,
1502
1750
  union,
1503
- withPriority
1751
+ withPriority,
1752
+ withSkipCodeBlock
1504
1753
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/core",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.2.4",
5
5
  "private": false,
6
6
  "author": {
7
7
  "name": "ocavue",
@@ -36,6 +36,7 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@prosekit/pm": "^0.1.1",
39
+ "clsx": "^2.1.0",
39
40
  "orderedmap": "^2.1.1",
40
41
  "type-fest": "^4.9.0"
41
42
  },
@@ -43,7 +44,7 @@
43
44
  "@prosekit/dev": "*",
44
45
  "tsup": "^8.0.1",
45
46
  "typescript": "^5.3.3",
46
- "vitest": "^1.1.1"
47
+ "vitest": "^1.1.3"
47
48
  },
48
49
  "scripts": {
49
50
  "build:tsup": "tsup",
package/src/index.ts CHANGED
@@ -14,6 +14,14 @@ export {
14
14
  type DefaultStateOptions,
15
15
  } from './extensions/default-state'
16
16
  export { defineDoc } from './extensions/doc'
17
+ export {
18
+ defineDocChangeHandler,
19
+ type DocChangeHandler,
20
+ } from './extensions/events/doc-change'
21
+ export {
22
+ defineFocusChangeHandler,
23
+ type FocusChangeHandler,
24
+ } from './extensions/events/focus'
17
25
  export {
18
26
  defineMountHandler,
19
27
  defineUnmountHandler,
@@ -22,10 +30,6 @@ export {
22
30
  type UnmountHandler,
23
31
  type UpdateHandler,
24
32
  } from './extensions/events/plugin-view'
25
- export {
26
- defineDocChangeHandler,
27
- type DocChangeHandler,
28
- } from './extensions/events/doc-change'
29
33
  export { defineHistory } from './extensions/history'
30
34
  export { defineInputRule } from './extensions/input-rules'
31
35
  export {
@@ -35,8 +39,18 @@ export {
35
39
  type Keymap,
36
40
  type KeymapPayload,
37
41
  } from './extensions/keymap'
38
- export { defineMarkSpec, type MarkSpecOptions } from './extensions/mark-spec'
39
- export { defineNodeSpec, type NodeSpecOptions } from './extensions/node-spec'
42
+ export {
43
+ defineMarkAttr,
44
+ defineMarkSpec,
45
+ type MarkAttrOptions,
46
+ type MarkSpecOptions,
47
+ } from './extensions/mark-spec'
48
+ export {
49
+ defineNodeAttr,
50
+ defineNodeSpec,
51
+ type NodeAttrOptions,
52
+ type NodeSpecOptions,
53
+ } from './extensions/node-spec'
40
54
  export { defineNodeView, type NodeViewOptions } from './extensions/node-view'
41
55
  export {
42
56
  defineNodeViewFactory,
@@ -64,6 +78,8 @@ export { type ExtensionTyping } from './types/extension-typing'
64
78
  export type { NodeJSON, SelectionJSON, StateJSON } from './types/model'
65
79
  export { Priority } from './types/priority'
66
80
  export { type SimplifyUnion } from './types/simplify-union'
81
+ export { clsx } from './utils/clsx'
82
+ export { defaultBlockAt } from './utils/default-block-at'
67
83
  export { getId as _getId } from './utils/get-id'
68
84
  export { getMarkType } from './utils/get-mark-type'
69
85
  export { getNodeType } from './utils/get-node-type'
@@ -84,3 +100,5 @@ export {
84
100
  isProseMirrorNode,
85
101
  isTextSelection,
86
102
  } from './utils/type-assertion'
103
+ export * from './utils/unicode'
104
+ export { withSkipCodeBlock } from './utils/with-skip-code-block'