@domternal/core 0.2.1 → 0.3.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.
package/README.md CHANGED
@@ -3,13 +3,16 @@
3
3
  [![Version](https://img.shields.io/npm/v/@domternal/core.svg)](https://www.npmjs.com/package/@domternal/core)
4
4
  [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/domternal/domternal/blob/main/LICENSE)
5
5
 
6
- A lightweight, extensible rich text editor toolkit built on [ProseMirror](https://prosemirror.net/). Framework-agnostic headless core with first-class **Angular** support. Use it headless with vanilla JS/TS, add the built-in toolbar and theme, or drop in ready-made Angular components. Fully tree-shakeable, import only what you use, unused extensions are stripped from your bundle.
6
+ A lightweight, extensible rich text editor toolkit built on <u>[ProseMirror](https://prosemirror.net/)</u>. Framework-agnostic headless core with first-class Angular support.
7
+ Use it headless with vanilla JS/TS, add the built-in toolbar and theme, or drop in ready-made Angular components. Fully tree-shakeable, import only what you use, unused extensions are stripped from your bundle.
7
8
 
8
- **[Website](https://domternal.dev)** · **[Documentation](https://domternal.dev/v1/introduction)** · **[StackBlitz (Vanilla TS)](https://stackblitz.com/edit/domternal-vanilla-full-example)** · **[StackBlitz (Angular)](https://stackblitz.com/edit/domternal-angular-full-example)**
9
+ ## Links
10
+
11
+ <u>[Website](https://domternal.dev)</u> &nbsp;&nbsp;&nbsp;•&nbsp;&nbsp;&nbsp; <u>[Documentation](https://domternal.dev/v1/introduction)</u> &nbsp;&nbsp;&nbsp;•&nbsp;&nbsp;&nbsp; <u>[StackBlitz (Vanilla TS)](https://stackblitz.com/edit/domternal-vanilla-full-example)</u> &nbsp;&nbsp;&nbsp;•&nbsp;&nbsp;&nbsp; <u>[StackBlitz (Angular)](https://stackblitz.com/edit/domternal-angular-full-example)</u>
9
12
 
10
13
  ## Features
11
14
 
12
- See [Packages & Bundle Size](https://domternal.dev/v1/packages) for a full breakdown of all packages and what each one includes.
15
+ See <u>[Packages & Bundle Size](https://domternal.dev/v1/packages)</u> for a full breakdown of all packages and what each one includes.
13
16
 
14
17
  - **Headless core** - use with any framework or vanilla JS/TS
15
18
  - **Angular components** - editor, toolbar, bubble menu, floating menu, emoji picker (signals, OnPush, zoneless-ready)
@@ -17,20 +20,20 @@ See [Packages & Bundle Size](https://domternal.dev/v1/packages) for a full break
17
20
  - **140+ chainable commands** - `editor.chain().focus().toggleBold().run()`
18
21
  - **Full table support** - cell merging, column resize, row/column controls, cell toolbar, all free and MIT licensed
19
22
  - **Tree-shakeable** - import only what you use, your bundler strips the rest
20
- - **~38 KB gzipped** (own code), [~108 KB total](https://domternal.dev/v1/packages) with ProseMirror
23
+ - **~38 KB gzipped** (own code), <u>[~108 KB total](https://domternal.dev/v1/packages)</u> with ProseMirror
21
24
  - **TypeScript first** - 100% typed, zero `any`
22
- - **4,200+ tests** - 2,675 unit tests and 1,550 E2E tests across 34 Playwright specs
25
+ - **4,400+ tests** - 2,687 unit tests and 1,796 E2E tests across 37 Playwright specs
23
26
  - **Light and dark theme** - 70+ CSS custom properties for full visual control
24
27
  - **Inline styles export** - `getHTML({ styled: true })` produces inline CSS ready for email clients, CMS, and Google Docs
25
28
  - **SSR helpers** - `generateHTML`, `generateJSON`, `generateText` for server-side rendering
26
29
 
27
30
  ## Documentation
28
31
 
29
- - [Getting Started](https://domternal.dev/v1/getting-started) - install and create your first editor
30
- - [Introduction](https://domternal.dev/v1/introduction) - core concepts, architecture, and design decisions
31
- - [Packages & Bundle Size](https://domternal.dev/v1/packages) - what each package includes and bundle size breakdown
32
- - [Blog](https://domternal.dev/blog)
32
+ - <u>[Getting Started](https://domternal.dev/v1/getting-started)</u> - install and create your first editor
33
+ - <u>[Introduction](https://domternal.dev/v1/introduction)</u> - core concepts, architecture, and design decisions
34
+ - <u>[Packages & Bundle Size](https://domternal.dev/v1/packages)</u> - what each package includes and bundle size breakdown
35
+ - <u>[Blog](https://domternal.dev/blog)</u>
33
36
 
34
37
  ## License
35
38
 
36
- [MIT](https://github.com/domternal/domternal/blob/main/LICENSE)
39
+ <u>[MIT](https://github.com/domternal/domternal/blob/main/LICENSE)</u>
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputRulesPlugin.d.ts","sourceRoot":"","sources":["../../src/helpers/inputRulesPlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AA6G1D;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,GAAG,MAAM,CA4C1E"}
package/dist/index.cjs CHANGED
@@ -4,8 +4,8 @@ var state = require('@domternal/pm/state');
4
4
  var view = require('@domternal/pm/view');
5
5
  var model = require('@domternal/pm/model');
6
6
  var keymap = require('@domternal/pm/keymap');
7
- var inputrules = require('@domternal/pm/inputrules');
8
7
  var commands = require('@domternal/pm/commands');
8
+ var inputrules = require('@domternal/pm/inputrules');
9
9
  var transform = require('@domternal/pm/transform');
10
10
  var schemaList = require('@domternal/pm/schema-list');
11
11
  var dom = require('@floating-ui/dom');
@@ -109,6 +109,112 @@ var EventEmitter = class {
109
109
  return Array.from(this.callbacks.keys());
110
110
  }
111
111
  };
112
+ var MAX_MATCH = 500;
113
+ function run(view, from, to, text, rules, plugin) {
114
+ if (view.composing) return false;
115
+ const state = view.state;
116
+ const $from = state.doc.resolve(from);
117
+ const textBefore = $from.parent.textBetween(
118
+ Math.max(0, $from.parentOffset - MAX_MATCH),
119
+ $from.parentOffset,
120
+ null,
121
+ "\uFFFC"
122
+ ) + text;
123
+ for (const rawRule of rules) {
124
+ const rule = rawRule;
125
+ if (!rule.inCodeMark && $from.marks().some((m) => m.type.spec.code)) continue;
126
+ if ($from.parent.type.spec.code) {
127
+ if (!rule.inCode) continue;
128
+ } else if (rule.inCode === "only") {
129
+ continue;
130
+ }
131
+ const match = rule.match.exec(textBefore);
132
+ if (!match || match[0].length < text.length) continue;
133
+ const startPos = from - (match[0].length - text.length);
134
+ if (!rule.inCodeMark) {
135
+ const codeMarks = [];
136
+ state.doc.nodesBetween(startPos, $from.pos, (node) => {
137
+ if (node.isInline && node.marks.some((m) => m.type.spec.code)) codeMarks.push(true);
138
+ });
139
+ if (codeMarks.length > 0) continue;
140
+ }
141
+ const tr = rule.handler(state, match, startPos, to);
142
+ if (!tr) continue;
143
+ if (rule.undoable) {
144
+ tr.setMeta(plugin, { transform: tr, from, to, text });
145
+ }
146
+ view.dispatch(tr);
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+ function undoInputRule(plugin, state$1, dispatch) {
152
+ const undoable = plugin.getState(state$1);
153
+ if (!undoable) return false;
154
+ if (dispatch) {
155
+ const tr = state$1.tr;
156
+ const toUndo = undoable.transform;
157
+ for (let j = toUndo.steps.length - 1; j >= 0; j--) {
158
+ const step = toUndo.steps[j];
159
+ const doc = toUndo.docs[j];
160
+ if (step && doc) tr.step(step.invert(doc));
161
+ }
162
+ if (undoable.text) {
163
+ const marks = tr.doc.resolve(undoable.from).marks();
164
+ tr.replaceWith(undoable.from, undoable.to, state$1.schema.text(undoable.text, marks));
165
+ const endPos = undoable.from + undoable.text.length;
166
+ if (endPos <= tr.doc.content.size) {
167
+ tr.setSelection(state.TextSelection.create(tr.doc, endPos));
168
+ }
169
+ } else {
170
+ tr.delete(undoable.from, undoable.to);
171
+ }
172
+ dispatch(tr);
173
+ }
174
+ return true;
175
+ }
176
+ function inputRulesPlugin({ rules }) {
177
+ const plugin = new state.Plugin({
178
+ state: {
179
+ init() {
180
+ return null;
181
+ },
182
+ apply(tr, prev) {
183
+ const stored = tr.getMeta(plugin);
184
+ if (stored) return stored;
185
+ if (tr.getMeta("appendedTransaction")) return prev;
186
+ return tr.selectionSet || tr.docChanged ? null : prev;
187
+ }
188
+ },
189
+ props: {
190
+ handleTextInput(view, from, to, text) {
191
+ return run(view, from, to, text, rules, plugin);
192
+ },
193
+ handleKeyDown(view, event) {
194
+ if (event.key === "Backspace" && !event.ctrlKey && !event.metaKey && !event.altKey) {
195
+ return undoInputRule(plugin, view.state, (tr) => {
196
+ view.dispatch(tr);
197
+ });
198
+ }
199
+ return false;
200
+ },
201
+ handleDOMEvents: {
202
+ compositionend: (view) => {
203
+ setTimeout(() => {
204
+ const { $cursor } = view.state.selection;
205
+ if ($cursor) {
206
+ run(view, $cursor.pos, $cursor.pos, "", rules, plugin);
207
+ }
208
+ });
209
+ }
210
+ }
211
+ },
212
+ // Tag so external undoInputRule can also find this plugin
213
+ isInputRules: true
214
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
215
+ });
216
+ return plugin;
217
+ }
112
218
 
113
219
  // src/helpers/callOrReturn.ts
114
220
  function callOrReturn(value, context, ...args) {
@@ -486,14 +592,14 @@ var ExtensionManager = class {
486
592
  */
487
593
  buildPlugins() {
488
594
  const plugins = [];
595
+ const rules = this.collectInputRules();
596
+ if (rules.length > 0) {
597
+ plugins.push(inputRulesPlugin({ rules }));
598
+ }
489
599
  const shortcuts = this.collectKeyboardShortcuts();
490
600
  if (Object.keys(shortcuts).length > 0) {
491
601
  plugins.push(keymap.keymap(shortcuts));
492
602
  }
493
- const rules = this.collectInputRules();
494
- if (rules.length > 0) {
495
- plugins.push(inputrules.inputRules({ rules }));
496
- }
497
603
  for (const ext of this._extensions) {
498
604
  const addPlugins = ext.config.addProseMirrorPlugins;
499
605
  if (addPlugins) {
@@ -936,7 +1042,7 @@ function isDocumentEmpty(doc) {
936
1042
  });
937
1043
  }
938
1044
  function markInputRule(options) {
939
- const { find: find2, type, getAttributes } = options;
1045
+ const { find: find2, type, getAttributes, undoable } = options;
940
1046
  return new inputrules.InputRule(
941
1047
  find2,
942
1048
  (state, match, start, end) => {
@@ -953,7 +1059,8 @@ function markInputRule(options) {
953
1059
  tr.addMark(start, start + textContent.length, type.create(attributes ?? void 0));
954
1060
  tr.removeStoredMark(type);
955
1061
  return tr;
956
- }
1062
+ },
1063
+ undoable !== void 0 ? { undoable } : {}
957
1064
  );
958
1065
  }
959
1066
  var markInputRulePatterns = {
@@ -978,6 +1085,69 @@ var markInputRulePatterns = {
978
1085
  */
979
1086
  highlight: /(?:==)([^=]+)(?:==)$/
980
1087
  };
1088
+ function wrappingInputRule(options) {
1089
+ const { find: find2, type, getAttributes = null, joinPredicate, undoable, guard } = options;
1090
+ return new inputrules.InputRule(
1091
+ find2,
1092
+ (state, match, start, end) => {
1093
+ if (guard && !guard(state)) return null;
1094
+ const attrs = getAttributes instanceof Function ? getAttributes(match) : getAttributes;
1095
+ const tr = state.tr.delete(start, end);
1096
+ const $start = tr.doc.resolve(start);
1097
+ const range = $start.blockRange();
1098
+ const wrapping = range && transform.findWrapping(range, type, attrs);
1099
+ if (!wrapping) return null;
1100
+ tr.wrap(range, wrapping);
1101
+ const before = tr.doc.resolve(start - 1).nodeBefore;
1102
+ if (before?.type === type && transform.canJoin(tr.doc, start - 1) && (!joinPredicate || joinPredicate(match, before))) {
1103
+ tr.join(start - 1);
1104
+ }
1105
+ return tr;
1106
+ },
1107
+ undoable !== void 0 ? { undoable } : {}
1108
+ );
1109
+ }
1110
+ function notInsideList(state) {
1111
+ const { $from } = state.selection;
1112
+ for (let d = $from.depth; d > 0; d--) {
1113
+ const name = $from.node(d).type.name;
1114
+ if (name === "listItem" || name === "taskItem") return false;
1115
+ }
1116
+ return true;
1117
+ }
1118
+ function textblockTypeInputRule(options) {
1119
+ const { find: find2, type, getAttributes = null, undoable } = options;
1120
+ return new inputrules.InputRule(
1121
+ find2,
1122
+ (state, match, start, end) => {
1123
+ const $start = state.doc.resolve(start);
1124
+ const attrs = getAttributes instanceof Function ? getAttributes(match) : getAttributes;
1125
+ if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), type)) return null;
1126
+ return state.tr.delete(start, end).setBlockType(start, start, type, attrs);
1127
+ },
1128
+ undoable !== void 0 ? { undoable } : {}
1129
+ );
1130
+ }
1131
+ function textInputRule(options) {
1132
+ const { find: find2, replace, undoable } = options;
1133
+ return new inputrules.InputRule(
1134
+ find2,
1135
+ (state, _match, start, end) => state.tr.replaceWith(start, end, state.schema.text(replace)),
1136
+ undoable !== void 0 ? { undoable } : {}
1137
+ );
1138
+ }
1139
+ function nodeInputRule(options) {
1140
+ const { find: find2, type, getAttributes = null, undoable } = options;
1141
+ return new inputrules.InputRule(
1142
+ find2,
1143
+ (state, match, start, end) => {
1144
+ const attrs = getAttributes instanceof Function ? getAttributes(match, state) : getAttributes;
1145
+ if (getAttributes instanceof Function && attrs === null) return null;
1146
+ return state.tr.replaceWith(start, end, type.create(attrs));
1147
+ },
1148
+ undoable !== void 0 ? { undoable } : {}
1149
+ );
1150
+ }
981
1151
 
982
1152
  // src/helpers/isValidUrl.ts
983
1153
  function isValidUrl(url, options = {}) {
@@ -1821,8 +1991,8 @@ var wrapIn = (nodeName, attributes) => ({ state, tr, dispatch }) => {
1821
1991
  return true;
1822
1992
  };
1823
1993
  var toggleWrap = (nodeName, attributes) => (props) => {
1824
- const { state: state$1, tr, dispatch } = props;
1825
- const nodeType = state$1.schema.nodes[nodeName];
1994
+ const { state, tr, dispatch } = props;
1995
+ const nodeType = state.schema.nodes[nodeName];
1826
1996
  if (!nodeType) {
1827
1997
  return false;
1828
1998
  }
@@ -1866,8 +2036,18 @@ var toggleWrap = (nodeName, attributes) => (props) => {
1866
2036
  const allWrapped = contentBlocks.length > 0 ? contentBlocks.every(({ pos }) => isInsideWrap(pos)) : isInsideWrap(from);
1867
2037
  if (allWrapped) {
1868
2038
  const first = contentBlocks[0];
1869
- if (first) {
1870
- tr.setSelection(state.TextSelection.create(tr.doc, first.pos + 1));
2039
+ const last = contentBlocks[contentBlocks.length - 1];
2040
+ if (first && last) {
2041
+ const $liftFrom = tr.doc.resolve(first.pos + 1);
2042
+ const $liftTo = tr.doc.resolve(last.pos + 1);
2043
+ const range = $liftFrom.blockRange($liftTo);
2044
+ if (!range) return false;
2045
+ const target = transform.liftTarget(range);
2046
+ if (target === null) return false;
2047
+ if (!dispatch) return true;
2048
+ tr.lift(range, target).scrollIntoView();
2049
+ dispatch(tr);
2050
+ return true;
1871
2051
  }
1872
2052
  return lift()(props);
1873
2053
  }
@@ -1901,6 +2081,36 @@ var lift = () => ({ tr, dispatch }) => {
1901
2081
  dispatch(tr);
1902
2082
  return true;
1903
2083
  };
2084
+ function joinListBackwards(tr, listType) {
2085
+ const { $from } = tr.selection;
2086
+ for (let d = $from.depth; d >= 0; d--) {
2087
+ if ($from.node(d).type === listType) {
2088
+ const listPos = $from.before(d);
2089
+ if (listPos > 0 && transform.canJoin(tr.doc, listPos)) {
2090
+ const nodeBefore = tr.doc.resolve(listPos - 1).parent;
2091
+ if (nodeBefore.type === listType) {
2092
+ tr.join(listPos);
2093
+ }
2094
+ }
2095
+ return;
2096
+ }
2097
+ }
2098
+ }
2099
+ function joinListForwards(tr, listType) {
2100
+ const { $from } = tr.selection;
2101
+ for (let d = $from.depth; d >= 0; d--) {
2102
+ if ($from.node(d).type === listType) {
2103
+ const after = $from.after(d);
2104
+ if (after < tr.doc.content.size && transform.canJoin(tr.doc, after)) {
2105
+ const nodeAfter = tr.doc.nodeAt(after);
2106
+ if (nodeAfter?.type === listType) {
2107
+ tr.join(after);
2108
+ }
2109
+ }
2110
+ return;
2111
+ }
2112
+ }
2113
+ }
1904
2114
  var toggleList = (listNodeName, listItemNodeName, attributes) => ({ state: state$1, tr, dispatch }) => {
1905
2115
  const listType = state$1.schema.nodes[listNodeName];
1906
2116
  const listItemType = state$1.schema.nodes[listItemNodeName];
@@ -2056,11 +2266,56 @@ var toggleList = (listNodeName, listItemNodeName, attributes) => ({ state: state
2056
2266
  dispatch(tr);
2057
2267
  return true;
2058
2268
  }
2059
- const { $from: $wrapFrom, $to: $wrapTo } = tr.selection;
2269
+ const blocksInList = contentBlocks.filter((b) => b.inSomeList);
2270
+ if (blocksInList.length === 0) {
2271
+ const { $from: $wf, $to: $wt } = tr.selection;
2272
+ const wr = $wf.blockRange($wt);
2273
+ if (!wr) return false;
2274
+ if (!schemaList.wrapRangeInList(dispatch ? tr : null, wr, listType, attributes)) return false;
2275
+ if (dispatch) {
2276
+ joinListBackwards(tr, listType);
2277
+ joinListForwards(tr, listType);
2278
+ dispatch(tr.scrollIntoView());
2279
+ }
2280
+ return true;
2281
+ }
2282
+ if (!dispatch) return true;
2283
+ const seen = /* @__PURE__ */ new Set();
2284
+ const listPositions = [];
2285
+ for (const block of blocksInList) {
2286
+ const $pos = tr.doc.resolve(block.pos);
2287
+ for (let d = $pos.depth; d >= 0; d--) {
2288
+ const groups = ($pos.node(d).type.spec.group ?? "").split(/\s+/);
2289
+ if (groups.includes("list")) {
2290
+ const lpos = $pos.before(d);
2291
+ if (!seen.has(lpos)) {
2292
+ seen.add(lpos);
2293
+ listPositions.push(lpos);
2294
+ }
2295
+ break;
2296
+ }
2297
+ }
2298
+ }
2299
+ listPositions.sort((a, b) => b - a);
2300
+ for (const pos of listPositions) {
2301
+ const listNode = tr.doc.nodeAt(pos);
2302
+ if (!listNode) continue;
2303
+ const children = [];
2304
+ listNode.forEach((item) => {
2305
+ item.forEach((child) => children.push(child));
2306
+ });
2307
+ tr.replaceWith(pos, pos + listNode.nodeSize, children);
2308
+ }
2309
+ const mappedFrom = tr.mapping.map(from, -1);
2310
+ const mappedTo = tr.mapping.map(to, 1);
2311
+ const $wrapFrom = tr.doc.resolve(mappedFrom);
2312
+ const $wrapTo = tr.doc.resolve(mappedTo);
2060
2313
  const wrapRange = $wrapFrom.blockRange($wrapTo);
2061
2314
  if (!wrapRange) return false;
2062
- if (!schemaList.wrapRangeInList(dispatch ? tr : null, wrapRange, listType, attributes)) return false;
2063
- if (dispatch) dispatch(tr.scrollIntoView());
2315
+ schemaList.wrapRangeInList(tr, wrapRange, listType, attributes);
2316
+ joinListBackwards(tr, listType);
2317
+ joinListForwards(tr, listType);
2318
+ dispatch(tr.scrollIntoView());
2064
2319
  return true;
2065
2320
  };
2066
2321
 
@@ -4409,7 +4664,32 @@ var Heading = Node.create({
4409
4664
  ];
4410
4665
  },
4411
4666
  addProseMirrorPlugins() {
4667
+ const { options, editor } = this;
4668
+ const codeToLevel = {};
4669
+ for (const level of options.levels) {
4670
+ codeToLevel[`Digit${String(level)}`] = level;
4671
+ }
4672
+ codeToLevel["Digit0"] = 0;
4412
4673
  return [
4674
+ new state.Plugin({
4675
+ key: new state.PluginKey("headingKeydownFix"),
4676
+ props: {
4677
+ handleDOMEvents: {
4678
+ keydown(_view, event) {
4679
+ if (!event.altKey || !(event.metaKey || event.ctrlKey)) return false;
4680
+ const level = codeToLevel[event.code];
4681
+ if (level === void 0) return false;
4682
+ event.preventDefault();
4683
+ if (level === 0) {
4684
+ editor?.commands["setParagraph"]?.();
4685
+ } else {
4686
+ editor?.commands["toggleHeading"]?.({ level });
4687
+ }
4688
+ return true;
4689
+ }
4690
+ }
4691
+ }
4692
+ }),
4413
4693
  keymap.keymap({
4414
4694
  Backspace: ((state, dispatch) => {
4415
4695
  const { selection } = state;
@@ -4436,10 +4716,10 @@ var Heading = Node.create({
4436
4716
  }
4437
4717
  const maxLevel = Math.max(...options.levels);
4438
4718
  return [
4439
- inputrules.textblockTypeInputRule(
4440
- new RegExp(`^(#{1,${String(maxLevel)}})\\s$`),
4441
- nodeType,
4442
- (match) => {
4719
+ textblockTypeInputRule({
4720
+ find: new RegExp(`^(#{1,${String(maxLevel)}})\\s$`),
4721
+ type: nodeType,
4722
+ getAttributes: (match) => {
4443
4723
  const hashes = match[1];
4444
4724
  if (!hashes) {
4445
4725
  return null;
@@ -4450,10 +4730,12 @@ var Heading = Node.create({
4450
4730
  }
4451
4731
  return { level };
4452
4732
  }
4453
- )
4733
+ })
4454
4734
  ];
4455
4735
  }
4456
4736
  });
4737
+
4738
+ // src/nodes/Blockquote.ts
4457
4739
  var Blockquote = Node.create({
4458
4740
  name: "blockquote",
4459
4741
  group: "block",
@@ -4513,7 +4795,7 @@ var Blockquote = Node.create({
4513
4795
  return [];
4514
4796
  }
4515
4797
  return [
4516
- inputrules.wrappingInputRule(/^\s*>\s$/, nodeType)
4798
+ wrappingInputRule({ find: /^\s*>\s$/, type: nodeType })
4517
4799
  ];
4518
4800
  }
4519
4801
  });
@@ -4643,14 +4925,14 @@ var CodeBlock = Node.create({
4643
4925
  return [];
4644
4926
  }
4645
4927
  return [
4646
- inputrules.textblockTypeInputRule(
4647
- /^```([a-z]*)?[\s\n]$/,
4648
- nodeType,
4649
- (match) => {
4928
+ textblockTypeInputRule({
4929
+ find: /^```([a-z]*)?[\s\n]$/,
4930
+ type: nodeType,
4931
+ getAttributes: (match) => {
4650
4932
  const language = match[1] ?? null;
4651
4933
  return { language };
4652
4934
  }
4653
- )
4935
+ })
4654
4936
  ];
4655
4937
  }
4656
4938
  });
@@ -4834,14 +5116,16 @@ var BulletList = Node.create({
4834
5116
  }
4835
5117
  return [
4836
5118
  // - item
4837
- inputrules.wrappingInputRule(/^\s*[-]\s$/, nodeType),
5119
+ wrappingInputRule({ find: /^\s*[-]\s$/, type: nodeType, guard: notInsideList }),
4838
5120
  // * item
4839
- inputrules.wrappingInputRule(/^\s*[*]\s$/, nodeType),
5121
+ wrappingInputRule({ find: /^\s*[*]\s$/, type: nodeType, guard: notInsideList }),
4840
5122
  // + item
4841
- inputrules.wrappingInputRule(/^\s*[+]\s$/, nodeType)
5123
+ wrappingInputRule({ find: /^\s*[+]\s$/, type: nodeType, guard: notInsideList })
4842
5124
  ];
4843
5125
  }
4844
5126
  });
5127
+
5128
+ // src/nodes/OrderedList.ts
4845
5129
  var OrderedList = Node.create({
4846
5130
  name: "orderedList",
4847
5131
  group: "block list",
@@ -4917,14 +5201,15 @@ var OrderedList = Node.create({
4917
5201
  }
4918
5202
  return [
4919
5203
  // 1. item (any number followed by . )
4920
- inputrules.wrappingInputRule(
4921
- /^(\d+)\.\s$/,
4922
- nodeType,
4923
- (match) => {
5204
+ wrappingInputRule({
5205
+ find: /^(\d+)\.\s$/,
5206
+ type: nodeType,
5207
+ guard: notInsideList,
5208
+ getAttributes: (match) => {
4924
5209
  const num = match[1];
4925
5210
  return { start: num ? parseInt(num, 10) : 1 };
4926
5211
  }
4927
- )
5212
+ })
4928
5213
  ];
4929
5214
  }
4930
5215
  });
@@ -4999,13 +5284,12 @@ var HorizontalRule = Node.create({
4999
5284
  const $start = state$1.doc.resolve(start);
5000
5285
  const from = $start.before();
5001
5286
  const to = $start.after();
5002
- tr.replaceWith(from, to, nodeType.create());
5003
- if (from + 1 < tr.doc.content.size) {
5004
- const $after = tr.doc.resolve(from + 1);
5005
- const sel = state.TextSelection.findFrom($after, 1);
5006
- if (sel) {
5007
- tr.setSelection(sel);
5008
- }
5287
+ const paragraph = state$1.schema.nodes["paragraph"]?.create();
5288
+ const nodes = paragraph ? [nodeType.create(), paragraph] : [nodeType.create()];
5289
+ tr.replaceWith(from, to, nodes);
5290
+ const sel = state.TextSelection.findFrom(tr.doc.resolve(from + 1), 1);
5291
+ if (sel) {
5292
+ tr.setSelection(sel);
5009
5293
  }
5010
5294
  }
5011
5295
  return tr;
@@ -5296,9 +5580,9 @@ var TaskList = Node.create({
5296
5580
  }
5297
5581
  return [
5298
5582
  // [ ] at start of line creates unchecked task
5299
- inputrules.wrappingInputRule(/^\s*\[\s?\]\s$/, nodeType),
5583
+ wrappingInputRule({ find: /^\s*\[\s?\]\s$/, type: nodeType, guard: notInsideList }),
5300
5584
  // [x] or [X] at start of line creates checked task
5301
- inputrules.wrappingInputRule(/^\s*\[[xX]\]\s$/, nodeType)
5585
+ wrappingInputRule({ find: /^\s*\[[xX]\]\s$/, type: nodeType, guard: notInsideList })
5302
5586
  ];
5303
5587
  }
5304
5588
  });
@@ -6596,40 +6880,39 @@ var Typography = Extension.create({
6596
6880
  },
6597
6881
  addInputRules() {
6598
6882
  const rules = [];
6599
- const textReplace = (find2, replacement) => new inputrules.InputRule(find2, (state, _match, start, end) => state.tr.replaceWith(start, end, state.schema.text(replacement)));
6600
6883
  if (this.options.emDash) {
6601
- rules.push(textReplace(/--$/, "\u2014"));
6884
+ rules.push(textInputRule({ find: /--$/, replace: "\u2014" }));
6602
6885
  }
6603
6886
  if (this.options.ellipsis) {
6604
- rules.push(textReplace(/\.\.\.$/, "\u2026"));
6887
+ rules.push(textInputRule({ find: /\.\.\.$/, replace: "\u2026" }));
6605
6888
  }
6606
6889
  if (this.options.arrows) {
6607
- rules.push(textReplace(/<-$/, "\u2190"));
6608
- rules.push(textReplace(/->$/, "\u2192"));
6609
- rules.push(textReplace(/=>$/, "\u21D2"));
6890
+ rules.push(textInputRule({ find: /<-$/, replace: "\u2190" }));
6891
+ rules.push(textInputRule({ find: /->$/, replace: "\u2192" }));
6892
+ rules.push(textInputRule({ find: /=>$/, replace: "\u21D2" }));
6610
6893
  }
6611
6894
  if (this.options.fractions) {
6612
- rules.push(textReplace(/1\/2$/, "\xBD"));
6613
- rules.push(textReplace(/1\/4$/, "\xBC"));
6614
- rules.push(textReplace(/3\/4$/, "\xBE"));
6615
- rules.push(textReplace(/1\/3$/, "\u2153"));
6616
- rules.push(textReplace(/2\/3$/, "\u2154"));
6895
+ rules.push(textInputRule({ find: /1\/2$/, replace: "\xBD" }));
6896
+ rules.push(textInputRule({ find: /1\/4$/, replace: "\xBC" }));
6897
+ rules.push(textInputRule({ find: /3\/4$/, replace: "\xBE" }));
6898
+ rules.push(textInputRule({ find: /1\/3$/, replace: "\u2153" }));
6899
+ rules.push(textInputRule({ find: /2\/3$/, replace: "\u2154" }));
6617
6900
  }
6618
6901
  if (this.options.symbols) {
6619
- rules.push(textReplace(/\(c\)$/i, "\xA9"));
6620
- rules.push(textReplace(/\(r\)$/i, "\xAE"));
6621
- rules.push(textReplace(/\(tm\)$/i, "\u2122"));
6622
- rules.push(textReplace(/\(sm\)$/i, "\u2120"));
6902
+ rules.push(textInputRule({ find: /\(c\)$/i, replace: "\xA9" }));
6903
+ rules.push(textInputRule({ find: /\(r\)$/i, replace: "\xAE" }));
6904
+ rules.push(textInputRule({ find: /\(tm\)$/i, replace: "\u2122" }));
6905
+ rules.push(textInputRule({ find: /\(sm\)$/i, replace: "\u2120" }));
6623
6906
  }
6624
6907
  if (this.options.math) {
6625
- rules.push(textReplace(/\+\/-$/, "\xB1"));
6626
- rules.push(textReplace(/!=$/, "\u2260"));
6627
- rules.push(textReplace(/<=$/, "\u2264"));
6628
- rules.push(textReplace(/>=$/, "\u2265"));
6908
+ rules.push(textInputRule({ find: /\+\/-$/, replace: "\xB1" }));
6909
+ rules.push(textInputRule({ find: /!=$/, replace: "\u2260" }));
6910
+ rules.push(textInputRule({ find: /<=$/, replace: "\u2264" }));
6911
+ rules.push(textInputRule({ find: />=$/, replace: "\u2265" }));
6629
6912
  }
6630
6913
  if (this.options.guillemets) {
6631
- rules.push(textReplace(/<<$/, "\xAB"));
6632
- rules.push(textReplace(/>>$/, "\xBB"));
6914
+ rules.push(textInputRule({ find: /<<$/, replace: "\xAB" }));
6915
+ rules.push(textInputRule({ find: />>$/, replace: "\xBB" }));
6633
6916
  }
6634
6917
  if (this.options.smartQuotes) {
6635
6918
  const { openDoubleQuote, closeDoubleQuote, openSingleQuote, closeSingleQuote } = this.options;
@@ -7866,11 +8149,13 @@ function linkPopoverPlugin({ editor, markType, protocols }) {
7866
8149
  applyBtn.type = "button";
7867
8150
  applyBtn.className = "dm-link-popover-btn dm-link-popover-apply";
7868
8151
  applyBtn.title = "Apply link";
8152
+ applyBtn.setAttribute("aria-label", "Apply link");
7869
8153
  applyBtn.innerHTML = defaultIcons["check"] ?? "";
7870
8154
  const removeBtn = document.createElement("button");
7871
8155
  removeBtn.type = "button";
7872
8156
  removeBtn.className = "dm-link-popover-btn dm-link-popover-remove";
7873
8157
  removeBtn.title = "Remove link";
8158
+ removeBtn.setAttribute("aria-label", "Remove link");
7874
8159
  removeBtn.innerHTML = defaultIcons["linkBreak"] ?? "";
7875
8160
  el.appendChild(input);
7876
8161
  el.appendChild(applyBtn);
@@ -8636,6 +8921,7 @@ exports.linkPastePlugin = linkPastePlugin;
8636
8921
  exports.linkPastePluginKey = linkPastePluginKey;
8637
8922
  exports.markInputRule = markInputRule;
8638
8923
  exports.markInputRulePatterns = markInputRulePatterns;
8924
+ exports.nodeInputRule = nodeInputRule;
8639
8925
  exports.placeholderPluginKey = placeholderPluginKey;
8640
8926
  exports.positionFloating = positionFloating;
8641
8927
  exports.positionFloatingOnce = positionFloatingOnce;
@@ -8646,6 +8932,8 @@ exports.selectionDecorationPluginKey = selectionDecorationPluginKey;
8646
8932
  exports.setBlockType = setBlockType;
8647
8933
  exports.setContent = setContent;
8648
8934
  exports.setMark = setMark;
8935
+ exports.textInputRule = textInputRule;
8936
+ exports.textblockTypeInputRule = textblockTypeInputRule;
8649
8937
  exports.toggleBlockType = toggleBlockType;
8650
8938
  exports.toggleList = toggleList;
8651
8939
  exports.toggleMark = toggleMark;
@@ -8655,5 +8943,6 @@ exports.unsetAllMarks = unsetAllMarks;
8655
8943
  exports.unsetMark = unsetMark;
8656
8944
  exports.updateAttributes = updateAttributes;
8657
8945
  exports.wrapIn = wrapIn;
8946
+ exports.wrappingInputRule = wrappingInputRule;
8658
8947
  //# sourceMappingURL=index.cjs.map
8659
8948
  //# sourceMappingURL=index.cjs.map