@tiptap/extension-find-and-replace 3.30.1 → 3.30.3

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/dist/index.js CHANGED
@@ -1,59 +1,44 @@
1
- // src/find-and-replace.ts
2
1
  import { Extension } from "@tiptap/core";
3
- import { TextSelection } from "@tiptap/pm/state";
4
-
5
- // src/state/debounced-search-state.ts
6
- var debouncedSearchState = /* @__PURE__ */ new WeakMap();
2
+ import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
3
+ import { RE2JS } from "re2js";
4
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
5
+ //#region src/state/debounced-search-state.ts
6
+ const debouncedSearchState = /* @__PURE__ */ new WeakMap();
7
7
  function getDebouncedSearchState(editor) {
8
- const existingState = debouncedSearchState.get(editor);
9
- if (existingState) {
10
- return existingState;
11
- }
12
- const nextState = {
13
- timeout: null,
14
- pendingTerm: null
15
- };
16
- debouncedSearchState.set(editor, nextState);
17
- return nextState;
8
+ const existingState = debouncedSearchState.get(editor);
9
+ if (existingState) return existingState;
10
+ const nextState = {
11
+ timeout: null,
12
+ pendingTerm: null
13
+ };
14
+ debouncedSearchState.set(editor, nextState);
15
+ return nextState;
18
16
  }
19
17
  function clearDebouncedSearchState(editor) {
20
- const state = debouncedSearchState.get(editor);
21
- if (!state) {
22
- return;
23
- }
24
- if (state.timeout !== null) {
25
- clearTimeout(state.timeout);
26
- }
27
- debouncedSearchState.delete(editor);
28
- }
29
-
30
- // src/plugin/plugin.ts
31
- import { Plugin, PluginKey } from "@tiptap/pm/state";
32
-
33
- // src/constants/constants.ts
34
- var resultClass = "find-and-replace-result";
35
- var currentResultClass = "find-and-replace-result-current";
36
-
37
- // src/style/create-style-tag.ts
38
- var createStyleTag = (style2, nonce) => {
39
- const existing = document.querySelector(
40
- "style[data-tiptap-extension-find-and-replace-style]"
41
- );
42
- if (existing !== null) {
43
- return existing;
44
- }
45
- const styleNode = document.createElement("style");
46
- if (nonce) {
47
- styleNode.setAttribute("nonce", nonce);
48
- }
49
- styleNode.setAttribute("data-tiptap-extension-find-and-replace-style", "");
50
- styleNode.textContent = style2;
51
- document.getElementsByTagName("head")[0].appendChild(styleNode);
52
- return styleNode;
18
+ const state = debouncedSearchState.get(editor);
19
+ if (!state) return;
20
+ if (state.timeout !== null) clearTimeout(state.timeout);
21
+ debouncedSearchState.delete(editor);
22
+ }
23
+ //#endregion
24
+ //#region src/constants/constants.ts
25
+ const resultClass = "find-and-replace-result";
26
+ const currentResultClass = "find-and-replace-result-current";
27
+ //#endregion
28
+ //#region src/style/create-style-tag.ts
29
+ const createStyleTag = (style, nonce) => {
30
+ const existing = document.querySelector("style[data-tiptap-extension-find-and-replace-style]");
31
+ if (existing !== null) return existing;
32
+ const styleNode = document.createElement("style");
33
+ if (nonce) styleNode.setAttribute("nonce", nonce);
34
+ styleNode.setAttribute("data-tiptap-extension-find-and-replace-style", "");
35
+ styleNode.textContent = style;
36
+ document.getElementsByTagName("head")[0].appendChild(styleNode);
37
+ return styleNode;
53
38
  };
54
-
55
- // src/style/style.ts
56
- var style = `.find-and-replace-result {
39
+ //#endregion
40
+ //#region src/style/style.ts
41
+ const style = `.find-and-replace-result {
57
42
  background-color: rgb(255 225 0 / 0.4);
58
43
  }
59
44
 
@@ -61,855 +46,760 @@ var style = `.find-and-replace-result {
61
46
  background-color: rgb(255 165 0 / 0.55);
62
47
  }
63
48
  `;
64
-
65
- // src/search/regex.ts
66
- import { RE2JS } from "re2js";
67
- var escapeRegExp = (value) => {
68
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
49
+ //#endregion
50
+ //#region src/search/regex.ts
51
+ const escapeRegExp = (value) => {
52
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
69
53
  };
70
- var unicodeWordCharacter = "[\\p{L}\\p{M}\\p{N}\\p{Pc}]";
54
+ /** Unicode word characters like letters, accents, numbers, and underscore-like punctuation. */
55
+ const unicodeWordCharacter = "[\\p{L}\\p{M}\\p{N}\\p{Pc}]";
71
56
  function compileNativeRegex(source, caseSensitive) {
72
- try {
73
- return new RegExp(source, caseSensitive ? "gu" : "giu");
74
- } catch {
75
- return null;
76
- }
57
+ try {
58
+ return new RegExp(source, caseSensitive ? "gu" : "giu");
59
+ } catch {
60
+ return null;
61
+ }
77
62
  }
78
63
  function compileSafeRegex(source, caseSensitive) {
79
- try {
80
- const flags = caseSensitive ? 0 : RE2JS.CASE_INSENSITIVE;
81
- return RE2JS.compile(source, flags);
82
- } catch {
83
- return null;
84
- }
64
+ try {
65
+ const flags = caseSensitive ? 0 : RE2JS.CASE_INSENSITIVE;
66
+ return RE2JS.compile(source, flags);
67
+ } catch {
68
+ return null;
69
+ }
85
70
  }
86
71
  function compileRegex(source, options) {
87
- return options.useRegex ? compileSafeRegex(source, options.caseSensitive) : compileNativeRegex(source, options.caseSensitive);
88
- }
72
+ return options.useRegex ? compileSafeRegex(source, options.caseSensitive) : compileNativeRegex(source, options.caseSensitive);
73
+ }
74
+ /**
75
+ * Creates a search matcher for a term.
76
+ * Regex mode uses RE2-compatible syntax to avoid catastrophic backtracking.
77
+ * @param term The search term, treated as regex source when `useRegex` is enabled.
78
+ * @param options Case sensitivity, regex mode, and whole word matching.
79
+ * @returns A compiled matcher, or `null` when the term is invalid or unsupported.
80
+ */
89
81
  function createSearchRegex(term, options) {
90
- if (!term) {
91
- return null;
92
- }
93
- let source;
94
- if (options.useRegex) {
95
- source = term;
96
- } else {
97
- const escaped = escapeRegExp(term);
98
- source = options.wholeWord ? `(?<!${unicodeWordCharacter})${escaped}(?!${unicodeWordCharacter})` : escaped;
99
- }
100
- return compileRegex(source, options);
101
- }
102
-
103
- // src/search/matches.ts
82
+ if (!term) return null;
83
+ let source;
84
+ if (options.useRegex) source = term;
85
+ else {
86
+ const escaped = escapeRegExp(term);
87
+ source = options.wholeWord ? `(?<!${unicodeWordCharacter})${escaped}(?!${unicodeWordCharacter})` : escaped;
88
+ }
89
+ return compileRegex(source, options);
90
+ }
91
+ //#endregion
92
+ //#region src/search/matches.ts
104
93
  function* findNativeMatches(regex, text) {
105
- for (const match of text.matchAll(regex)) {
106
- yield { index: match.index, value: match[0] };
107
- }
94
+ for (const match of text.matchAll(regex)) yield {
95
+ index: match.index,
96
+ value: match[0]
97
+ };
108
98
  }
109
99
  function* findSafeMatches(regex, text) {
110
- var _a;
111
- const matcher = regex.matcher(text);
112
- while (matcher.find()) {
113
- yield { index: matcher.start(), value: (_a = matcher.group()) != null ? _a : "" };
114
- }
100
+ const matcher = regex.matcher(text);
101
+ while (matcher.find()) {
102
+ var _matcher$group;
103
+ yield {
104
+ index: matcher.start(),
105
+ value: (_matcher$group = matcher.group()) !== null && _matcher$group !== void 0 ? _matcher$group : ""
106
+ };
107
+ }
115
108
  }
116
109
  function findMatches(regex, text) {
117
- return regex instanceof RegExp ? findNativeMatches(regex, text) : findSafeMatches(regex, text);
110
+ return regex instanceof RegExp ? findNativeMatches(regex, text) : findSafeMatches(regex, text);
118
111
  }
119
-
120
- // src/search/text-segments.ts
112
+ //#endregion
113
+ //#region src/search/text-segments.ts
121
114
  function getTextSegments(textblock, pos) {
122
- const segments = [];
123
- let textOffset = 0;
124
- textblock.forEach((child, offset) => {
125
- var _a;
126
- const text = child.isText ? (_a = child.text) != null ? _a : "" : "\n";
127
- segments.push({
128
- isText: child.isText,
129
- pos: pos + 1 + offset,
130
- length: child.nodeSize,
131
- text,
132
- textOffset
133
- });
134
- textOffset += text.length;
135
- });
136
- return segments;
115
+ const segments = [];
116
+ let textOffset = 0;
117
+ textblock.forEach((child, offset) => {
118
+ var _child$text;
119
+ const text = child.isText ? (_child$text = child.text) !== null && _child$text !== void 0 ? _child$text : "" : "\n";
120
+ segments.push({
121
+ isText: child.isText,
122
+ pos: pos + 1 + offset,
123
+ length: child.nodeSize,
124
+ text,
125
+ textOffset
126
+ });
127
+ textOffset += text.length;
128
+ });
129
+ return segments;
137
130
  }
138
131
  function findOffsetSegment(segments, offset) {
139
- var _a;
140
- let low = 0;
141
- let high = segments.length;
142
- while (low < high) {
143
- const middle = Math.floor((low + high) / 2);
144
- const segment = segments[middle];
145
- const segmentEnd = segment.textOffset + segment.text.length;
146
- if (offset < segmentEnd) {
147
- high = middle;
148
- } else {
149
- low = middle + 1;
150
- }
151
- }
152
- return (_a = segments[low]) != null ? _a : segments.at(-1);
132
+ var _segments$low;
133
+ let low = 0;
134
+ let high = segments.length;
135
+ while (low < high) {
136
+ const middle = Math.floor((low + high) / 2);
137
+ const segment = segments[middle];
138
+ if (offset < segment.textOffset + segment.text.length) high = middle;
139
+ else low = middle + 1;
140
+ }
141
+ return (_segments$low = segments[low]) !== null && _segments$low !== void 0 ? _segments$low : segments.at(-1);
153
142
  }
154
143
  function offsetToPos(segments, offset) {
155
- const segment = findOffsetSegment(segments, offset);
156
- return segment ? segment.pos + Math.min(offset - segment.textOffset, segment.length) : 0;
144
+ const segment = findOffsetSegment(segments, offset);
145
+ return segment ? segment.pos + Math.min(offset - segment.textOffset, segment.length) : 0;
157
146
  }
158
147
  function overlapsNonTextSegment(segments, from, to) {
159
- return segments.some(
160
- (segment) => !segment.isText && from < segment.textOffset + segment.text.length && to > segment.textOffset
161
- );
148
+ return segments.some((segment) => !segment.isText && from < segment.textOffset + segment.text.length && to > segment.textOffset);
162
149
  }
163
-
164
- // src/search/textblock-search.ts
150
+ //#endregion
151
+ //#region src/search/textblock-search.ts
165
152
  function searchTextblock(regex, textblock, pos) {
166
- const segments = getTextSegments(textblock, pos);
167
- const text = segments.map((segment) => segment.text).join("");
168
- const results = [];
169
- for (const match of findMatches(regex, text)) {
170
- if (match.value.length === 0) {
171
- continue;
172
- }
173
- const matchEnd = match.index + match.value.length;
174
- if (overlapsNonTextSegment(segments, match.index, matchEnd)) {
175
- continue;
176
- }
177
- results.push({
178
- from: offsetToPos(segments, match.index),
179
- to: offsetToPos(segments, matchEnd)
180
- });
181
- }
182
- return results;
183
- }
184
-
185
- // src/search/search.ts
153
+ const segments = getTextSegments(textblock, pos);
154
+ const text = segments.map((segment) => segment.text).join("");
155
+ const results = [];
156
+ for (const match of findMatches(regex, text)) {
157
+ if (match.value.length === 0) continue;
158
+ const matchEnd = match.index + match.value.length;
159
+ if (overlapsNonTextSegment(segments, match.index, matchEnd)) continue;
160
+ results.push({
161
+ from: offsetToPos(segments, match.index),
162
+ to: offsetToPos(segments, matchEnd)
163
+ });
164
+ }
165
+ return results;
166
+ }
167
+ //#endregion
168
+ //#region src/search/search.ts
169
+ /**
170
+ * Searches textblocks for a term and returns their matched ranges.
171
+ * @param textblocks The textblocks and their document positions.
172
+ * @param term The search term, treated as regex source when `useRegex` is enabled.
173
+ * @param options Case sensitivity, regex mode, and whole word matching.
174
+ * @returns The list of matched ranges in textblock order.
175
+ */
186
176
  function searchTextblocks(textblocks, term, options) {
187
- const regex = createSearchRegex(term, options);
188
- if (!regex) {
189
- return [];
190
- }
191
- return textblocks.flatMap(({ node, pos }) => searchTextblock(regex, node, pos));
192
- }
177
+ const regex = createSearchRegex(term, options);
178
+ if (!regex) return [];
179
+ return textblocks.flatMap(({ node, pos }) => searchTextblock(regex, node, pos));
180
+ }
181
+ /**
182
+ * Searches all textblocks of a document for a term and returns the matched ranges.
183
+ * Matches may span multiple text nodes (e.g. across marks), but never leave a textblock.
184
+ * @param doc The document to search in.
185
+ * @param term The search term, treated as regex source when `useRegex` is enabled.
186
+ * @param options Case sensitivity, regex mode, and whole word matching.
187
+ * @returns The list of matched ranges in document order.
188
+ */
193
189
  function searchDocument(doc, term, options) {
194
- const textblocks = [];
195
- doc.descendants((node, pos) => {
196
- if (!node.isTextblock) {
197
- return true;
198
- }
199
- textblocks.push({ node, pos });
200
- return false;
201
- });
202
- return searchTextblocks(textblocks, term, options);
203
- }
190
+ const textblocks = [];
191
+ doc.descendants((node, pos) => {
192
+ if (!node.isTextblock) return true;
193
+ textblocks.push({
194
+ node,
195
+ pos
196
+ });
197
+ return false;
198
+ });
199
+ return searchTextblocks(textblocks, term, options);
200
+ }
201
+ /**
202
+ * Finds the index of the first result at or after a position, wrapping around
203
+ * to the first result when the position is behind the last result.
204
+ * @param results The current search results.
205
+ * @param from The position to search from.
206
+ * @returns The result index, or `null` when there are no results.
207
+ */
204
208
  function findNextIndex(results, from) {
205
- if (results.length === 0) {
206
- return null;
207
- }
208
- const index = results.findIndex((result) => result.from >= from);
209
- return index === -1 ? 0 : index;
209
+ if (results.length === 0) return null;
210
+ const index = results.findIndex((result) => result.from >= from);
211
+ return index === -1 ? 0 : index;
210
212
  }
211
-
212
- // src/utils/createDecorations.ts
213
- import { DecorationSet } from "@tiptap/pm/view";
214
-
215
- // src/utils/createDecoration.ts
216
- import { Decoration } from "@tiptap/pm/view";
213
+ //#endregion
214
+ //#region src/utils/createDecoration.ts
217
215
  function createDecoration(result, currentIndex, index) {
218
- const className = index === currentIndex ? `${resultClass} ${currentResultClass}` : resultClass;
219
- return Decoration.inline(result.from, result.to, { class: className });
216
+ const className = index === currentIndex ? `${resultClass} ${currentResultClass}` : resultClass;
217
+ return Decoration.inline(result.from, result.to, { class: className });
220
218
  }
221
-
222
- // src/utils/createDecorations.ts
219
+ //#endregion
220
+ //#region src/utils/createDecorations.ts
223
221
  function createDecorations(doc, results, currentIndex) {
224
- const decorations = results.map((result, index) => createDecoration(result, currentIndex, index));
225
- return DecorationSet.create(doc, decorations);
222
+ const decorations = results.map((result, index) => createDecoration(result, currentIndex, index));
223
+ return DecorationSet.create(doc, decorations);
226
224
  }
227
-
228
- // src/utils/createState.ts
225
+ //#endregion
226
+ //#region src/utils/createState.ts
229
227
  function createState(doc, options) {
230
- const results = searchDocument(doc, options.searchTerm, options);
231
- const currentIndex = results.length > 0 ? 0 : null;
232
- return {
233
- searchTerm: options.searchTerm,
234
- replaceTerm: options.replaceTerm,
235
- caseSensitive: options.caseSensitive,
236
- useRegex: options.useRegex,
237
- wholeWord: options.wholeWord,
238
- results,
239
- currentIndex,
240
- decorations: createDecorations(doc, results, currentIndex)
241
- };
242
- }
243
-
244
- // src/utils/hasCurrentIndex.ts
228
+ const results = searchDocument(doc, options.searchTerm, options);
229
+ const currentIndex = results.length > 0 ? 0 : null;
230
+ return {
231
+ searchTerm: options.searchTerm,
232
+ replaceTerm: options.replaceTerm,
233
+ caseSensitive: options.caseSensitive,
234
+ useRegex: options.useRegex,
235
+ wholeWord: options.wholeWord,
236
+ results,
237
+ currentIndex,
238
+ decorations: createDecorations(doc, results, currentIndex)
239
+ };
240
+ }
241
+ //#endregion
242
+ //#region src/utils/hasCurrentIndex.ts
245
243
  function hasCurrentIndex(meta) {
246
- return !!meta && "currentIndex" in meta;
244
+ return !!meta && "currentIndex" in meta;
247
245
  }
248
-
249
- // src/utils/findDecorations.ts
246
+ //#endregion
247
+ //#region src/utils/findDecorations.ts
250
248
  function findDecorations(decorations, results, textblocks) {
251
- const found = /* @__PURE__ */ new Set();
252
- textblocks.forEach((textblock) => {
253
- decorations.find(textblock.from, textblock.to).forEach((decoration) => found.add(decoration));
254
- });
255
- results.forEach((result) => {
256
- decorations.find(result.from, result.to).filter((decoration) => {
257
- return decoration.from === result.from && decoration.to === result.to;
258
- }).forEach((decoration) => found.add(decoration));
259
- });
260
- return [...found];
261
- }
262
-
263
- // src/utils/sameResult.ts
249
+ const found = /* @__PURE__ */ new Set();
250
+ textblocks.forEach((textblock) => {
251
+ decorations.find(textblock.from, textblock.to).forEach((decoration) => found.add(decoration));
252
+ });
253
+ results.forEach((result) => {
254
+ decorations.find(result.from, result.to).filter((decoration) => {
255
+ return decoration.from === result.from && decoration.to === result.to;
256
+ }).forEach((decoration) => found.add(decoration));
257
+ });
258
+ return [...found];
259
+ }
260
+ //#endregion
261
+ //#region src/utils/sameResult.ts
264
262
  function sameResult(first, second) {
265
- return first.from === second.from && first.to === second.to;
263
+ return first.from === second.from && first.to === second.to;
266
264
  }
267
-
268
- // src/utils/isCurrentResult.ts
265
+ //#endregion
266
+ //#region src/utils/isCurrentResult.ts
269
267
  function isCurrentResult(result, current) {
270
- return current !== null && sameResult(result, current);
268
+ return current !== null && sameResult(result, current);
271
269
  }
272
-
273
- // src/utils/resultInTextblocks.ts
270
+ //#endregion
271
+ //#region src/utils/resultInTextblocks.ts
274
272
  function resultInTextblocks(result, textblocks) {
275
- let start = 0;
276
- let end = textblocks.length - 1;
277
- while (start <= end) {
278
- const index = Math.floor((start + end) / 2);
279
- const textblock = textblocks[index];
280
- if (result.from < textblock.from) {
281
- end = index - 1;
282
- continue;
283
- }
284
- if (result.to > textblock.to) {
285
- start = index + 1;
286
- continue;
287
- }
288
- return true;
289
- }
290
- return false;
291
- }
292
-
293
- // src/utils/shouldRefreshResult.ts
273
+ let start = 0;
274
+ let end = textblocks.length - 1;
275
+ while (start <= end) {
276
+ const index = Math.floor((start + end) / 2);
277
+ const textblock = textblocks[index];
278
+ if (result.from < textblock.from) {
279
+ end = index - 1;
280
+ continue;
281
+ }
282
+ if (result.to > textblock.to) {
283
+ start = index + 1;
284
+ continue;
285
+ }
286
+ return true;
287
+ }
288
+ return false;
289
+ }
290
+ //#endregion
291
+ //#region src/utils/shouldRefreshResult.ts
294
292
  function shouldRefreshResult(result, textblocks, previousCurrent, current) {
295
- return resultInTextblocks(result, textblocks) || isCurrentResult(result, previousCurrent) || isCurrentResult(result, current);
293
+ return resultInTextblocks(result, textblocks) || isCurrentResult(result, previousCurrent) || isCurrentResult(result, current);
296
294
  }
297
-
298
- // src/utils/getResultsToRefresh.ts
295
+ //#endregion
296
+ //#region src/utils/getResultsToRefresh.ts
299
297
  function getResultsToRefresh(results, textblocks, previousCurrent, currentIndex) {
300
- var _a;
301
- const current = currentIndex === null ? null : (_a = results[currentIndex]) != null ? _a : null;
302
- const refreshedResults = [];
303
- results.forEach((result, index) => {
304
- if (shouldRefreshResult(result, textblocks, previousCurrent, current)) {
305
- refreshedResults.push({ result, index });
306
- }
307
- });
308
- return refreshedResults;
309
- }
310
-
311
- // src/utils/refreshDecorations.ts
298
+ var _results$currentIndex;
299
+ const current = currentIndex === null ? null : (_results$currentIndex = results[currentIndex]) !== null && _results$currentIndex !== void 0 ? _results$currentIndex : null;
300
+ const refreshedResults = [];
301
+ results.forEach((result, index) => {
302
+ if (shouldRefreshResult(result, textblocks, previousCurrent, current)) refreshedResults.push({
303
+ result,
304
+ index
305
+ });
306
+ });
307
+ return refreshedResults;
308
+ }
309
+ //#endregion
310
+ //#region src/utils/refreshDecorations.ts
312
311
  function refreshDecorations(decorations, doc, results, currentIndex, textblocks, previousCurrent) {
313
- const resultsToRefresh = getResultsToRefresh(results, textblocks, previousCurrent, currentIndex);
314
- const refreshedResults = resultsToRefresh.map(({ result }) => result);
315
- const staleResults = previousCurrent ? [...refreshedResults, previousCurrent] : refreshedResults;
316
- const decorationsToRemove = findDecorations(decorations, staleResults, textblocks);
317
- const decorationsToAdd = resultsToRefresh.map(({ result, index }) => {
318
- return createDecoration(result, currentIndex, index);
319
- });
320
- return decorations.remove(decorationsToRemove).add(doc, decorationsToAdd);
321
- }
322
-
323
- // src/utils/normalizeCurrentIndex.ts
312
+ const resultsToRefresh = getResultsToRefresh(results, textblocks, previousCurrent, currentIndex);
313
+ const refreshedResults = resultsToRefresh.map(({ result }) => result);
314
+ const decorationsToRemove = findDecorations(decorations, previousCurrent ? [...refreshedResults, previousCurrent] : refreshedResults, textblocks);
315
+ const decorationsToAdd = resultsToRefresh.map(({ result, index }) => {
316
+ return createDecoration(result, currentIndex, index);
317
+ });
318
+ return decorations.remove(decorationsToRemove).add(doc, decorationsToAdd);
319
+ }
320
+ //#endregion
321
+ //#region src/utils/normalizeCurrentIndex.ts
324
322
  function normalizeCurrentIndex(currentIndex, length) {
325
- if (currentIndex === void 0 || currentIndex === null || length === 0) {
326
- return null;
327
- }
328
- return Math.max(0, Math.min(currentIndex, length - 1));
323
+ if (currentIndex === void 0 || currentIndex === null || length === 0) return null;
324
+ return Math.max(0, Math.min(currentIndex, length - 1));
329
325
  }
330
-
331
- // src/utils/getMetaCurrentIndex.ts
326
+ //#endregion
327
+ //#region src/utils/getMetaCurrentIndex.ts
332
328
  function getMetaCurrentIndex(meta, length) {
333
- if (!meta) {
334
- return void 0;
335
- }
336
- if (!hasCurrentIndex(meta)) {
337
- return void 0;
338
- }
339
- return normalizeCurrentIndex(meta.currentIndex, length);
329
+ if (!meta) return;
330
+ if (!hasCurrentIndex(meta)) return;
331
+ return normalizeCurrentIndex(meta.currentIndex, length);
340
332
  }
341
-
342
- // src/utils/getFallbackCurrentIndex.ts
333
+ //#endregion
334
+ //#region src/utils/getFallbackCurrentIndex.ts
343
335
  function getFallbackCurrentIndex(previousState, length) {
344
- return previousState.currentIndex === null ? 0 : Math.min(previousState.currentIndex, length - 1);
336
+ return previousState.currentIndex === null ? 0 : Math.min(previousState.currentIndex, length - 1);
345
337
  }
346
-
347
- // src/utils/getPreviousCurrentResult.ts
338
+ //#endregion
339
+ //#region src/utils/getPreviousCurrentResult.ts
348
340
  function getPreviousCurrentResult(previousState) {
349
- return previousState.currentIndex === null ? void 0 : previousState.results[previousState.currentIndex];
341
+ return previousState.currentIndex === null ? void 0 : previousState.results[previousState.currentIndex];
350
342
  }
351
-
352
- // src/utils/getMappedCurrentIndex.ts
343
+ //#endregion
344
+ //#region src/utils/getMappedCurrentIndex.ts
353
345
  function getMappedCurrentIndex(previousState, results, docChanged, mapping) {
354
- if (!docChanged) {
355
- return void 0;
356
- }
357
- if (!mapping) {
358
- return void 0;
359
- }
360
- const previousResult = getPreviousCurrentResult(previousState);
361
- if (!previousResult) {
362
- return void 0;
363
- }
364
- const mappedFrom = mapping.map(previousResult.from, 1);
365
- return findNextIndex(results, mappedFrom);
366
- }
367
-
368
- // src/utils/isNewSearch.ts
346
+ if (!docChanged) return;
347
+ if (!mapping) return;
348
+ const previousResult = getPreviousCurrentResult(previousState);
349
+ if (!previousResult) return;
350
+ return findNextIndex(results, mapping.map(previousResult.from, 1));
351
+ }
352
+ //#endregion
353
+ //#region src/utils/isNewSearch.ts
369
354
  function isNewSearch(meta) {
370
- return !!meta && "searchTerm" in meta;
355
+ return !!meta && "searchTerm" in meta;
371
356
  }
372
-
373
- // src/utils/getSearchCurrentIndex.ts
357
+ //#endregion
358
+ //#region src/utils/getSearchCurrentIndex.ts
374
359
  function getSearchCurrentIndex(previousState, results, meta, docChanged, mapping) {
375
- if (isNewSearch(meta)) {
376
- return 0;
377
- }
378
- const mappedIndex = getMappedCurrentIndex(previousState, results, docChanged, mapping);
379
- return mappedIndex != null ? mappedIndex : getFallbackCurrentIndex(previousState, results.length);
360
+ if (isNewSearch(meta)) return 0;
361
+ const mappedIndex = getMappedCurrentIndex(previousState, results, docChanged, mapping);
362
+ return mappedIndex !== null && mappedIndex !== void 0 ? mappedIndex : getFallbackCurrentIndex(previousState, results.length);
380
363
  }
381
-
382
- // src/utils/resolveCurrentIndex.ts
364
+ //#endregion
365
+ //#region src/utils/resolveCurrentIndex.ts
383
366
  function resolveCurrentIndex(previousState, results, meta, docChanged, mapping) {
384
- if (results.length === 0) {
385
- return null;
386
- }
387
- const metaIndex = getMetaCurrentIndex(meta, results.length);
388
- if (metaIndex !== void 0) {
389
- return metaIndex;
390
- }
391
- return getSearchCurrentIndex(previousState, results, meta, docChanged, mapping);
367
+ if (results.length === 0) return null;
368
+ const metaIndex = getMetaCurrentIndex(meta, results.length);
369
+ if (metaIndex !== void 0) return metaIndex;
370
+ return getSearchCurrentIndex(previousState, results, meta, docChanged, mapping);
392
371
  }
393
-
394
- // src/utils/refreshCurrentIndexState.ts
372
+ //#endregion
373
+ //#region src/utils/refreshCurrentIndexState.ts
395
374
  function refreshCurrentIndexState(previousState, state, doc, meta) {
396
- const currentIndex = resolveCurrentIndex(previousState, state.results, meta, false, void 0);
397
- const previousCurrent = previousState.currentIndex === null ? null : previousState.results[previousState.currentIndex];
398
- return {
399
- ...state,
400
- currentIndex,
401
- decorations: refreshDecorations(
402
- previousState.decorations,
403
- doc,
404
- state.results,
405
- currentIndex,
406
- [],
407
- previousCurrent
408
- )
409
- };
410
- }
411
-
412
- // src/utils/getChangedTextblocks.ts
375
+ const currentIndex = resolveCurrentIndex(previousState, state.results, meta, false, void 0);
376
+ const previousCurrent = previousState.currentIndex === null ? null : previousState.results[previousState.currentIndex];
377
+ return {
378
+ ...state,
379
+ currentIndex,
380
+ decorations: refreshDecorations(previousState.decorations, doc, state.results, currentIndex, [], previousCurrent)
381
+ };
382
+ }
383
+ //#endregion
384
+ //#region src/utils/getChangedTextblocks.ts
413
385
  function getChangedTextblocks(doc, mapping) {
414
- const textblocks = /* @__PURE__ */ new Map();
415
- mapping.maps.forEach((stepMap, index) => {
416
- const remaining = mapping.slice(index + 1);
417
- stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
418
- const from = Math.max(0, remaining.map(newStart, -1) - 1);
419
- const to = Math.min(doc.content.size, remaining.map(newEnd, 1) + 1);
420
- doc.nodesBetween(from, to, (node, pos) => {
421
- if (!node.isTextblock) {
422
- return true;
423
- }
424
- textblocks.set(pos, { node, pos, from: pos, to: pos + node.nodeSize });
425
- return false;
426
- });
427
- });
428
- });
429
- return [...textblocks.values()].sort((first, second) => first.pos - second.pos);
430
- }
431
-
432
- // src/utils/mapResult.ts
386
+ const textblocks = /* @__PURE__ */ new Map();
387
+ mapping.maps.forEach((stepMap, index) => {
388
+ const remaining = mapping.slice(index + 1);
389
+ stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
390
+ const from = Math.max(0, remaining.map(newStart, -1) - 1);
391
+ const to = Math.min(doc.content.size, remaining.map(newEnd, 1) + 1);
392
+ doc.nodesBetween(from, to, (node, pos) => {
393
+ if (!node.isTextblock) return true;
394
+ textblocks.set(pos, {
395
+ node,
396
+ pos,
397
+ from: pos,
398
+ to: pos + node.nodeSize
399
+ });
400
+ return false;
401
+ });
402
+ });
403
+ });
404
+ return [...textblocks.values()].sort((first, second) => first.pos - second.pos);
405
+ }
406
+ //#endregion
407
+ //#region src/utils/mapResult.ts
433
408
  function mapResult(result, mapping) {
434
- const from = mapping.map(result.from, 1);
435
- const to = mapping.map(result.to, -1);
436
- return from < to ? { from, to } : null;
437
- }
438
-
439
- // src/utils/mapResults.ts
409
+ const from = mapping.map(result.from, 1);
410
+ const to = mapping.map(result.to, -1);
411
+ return from < to ? {
412
+ from,
413
+ to
414
+ } : null;
415
+ }
416
+ //#endregion
417
+ //#region src/utils/mapResults.ts
440
418
  function mapResults(results, mapping) {
441
- const mappedResults = [];
442
- results.forEach((result) => {
443
- const mapped = mapResult(result, mapping);
444
- if (mapped) {
445
- mappedResults.push(mapped);
446
- }
447
- });
448
- return mappedResults;
449
- }
450
-
451
- // src/utils/mergeResults.ts
419
+ const mappedResults = [];
420
+ results.forEach((result) => {
421
+ const mapped = mapResult(result, mapping);
422
+ if (mapped) mappedResults.push(mapped);
423
+ });
424
+ return mappedResults;
425
+ }
426
+ //#endregion
427
+ //#region src/utils/mergeResults.ts
452
428
  function mergeResults(first, second) {
453
- const results = [];
454
- let firstIndex = 0;
455
- let secondIndex = 0;
456
- while (firstIndex < first.length && secondIndex < second.length) {
457
- if (first[firstIndex].from < second[secondIndex].from) {
458
- results.push(first[firstIndex++]);
459
- continue;
460
- }
461
- results.push(second[secondIndex++]);
462
- }
463
- return results.concat(first.slice(firstIndex), second.slice(secondIndex));
464
- }
465
-
466
- // src/utils/refreshDocumentState.ts
429
+ const results = [];
430
+ let firstIndex = 0;
431
+ let secondIndex = 0;
432
+ while (firstIndex < first.length && secondIndex < second.length) {
433
+ if (first[firstIndex].from < second[secondIndex].from) {
434
+ results.push(first[firstIndex++]);
435
+ continue;
436
+ }
437
+ results.push(second[secondIndex++]);
438
+ }
439
+ return results.concat(first.slice(firstIndex), second.slice(secondIndex));
440
+ }
441
+ //#endregion
442
+ //#region src/utils/refreshDocumentState.ts
467
443
  function refreshDocumentState(previousState, state, doc, meta, mapping) {
468
- const textblocks = getChangedTextblocks(doc, mapping);
469
- const mappedResults = mapResults(previousState.results, mapping);
470
- const unaffectedResults = mappedResults.filter((result) => !resultInTextblocks(result, textblocks));
471
- const changedResults = searchTextblocks(textblocks, state.searchTerm, state);
472
- const results = mergeResults(unaffectedResults, changedResults);
473
- const currentIndex = resolveCurrentIndex(previousState, results, meta, true, mapping);
474
- const previousCurrent = previousState.currentIndex === null ? null : mapResult(previousState.results[previousState.currentIndex], mapping);
475
- const decorations = previousState.decorations.map(mapping, doc);
476
- return {
477
- ...state,
478
- results,
479
- currentIndex,
480
- decorations: refreshDecorations(
481
- decorations,
482
- doc,
483
- results,
484
- currentIndex,
485
- textblocks,
486
- previousCurrent
487
- )
488
- };
489
- }
490
-
491
- // src/utils/refreshState.ts
444
+ const textblocks = getChangedTextblocks(doc, mapping);
445
+ const results = mergeResults(mapResults(previousState.results, mapping).filter((result) => !resultInTextblocks(result, textblocks)), searchTextblocks(textblocks, state.searchTerm, state));
446
+ const currentIndex = resolveCurrentIndex(previousState, results, meta, true, mapping);
447
+ const previousCurrent = previousState.currentIndex === null ? null : mapResult(previousState.results[previousState.currentIndex], mapping);
448
+ const decorations = previousState.decorations.map(mapping, doc);
449
+ return {
450
+ ...state,
451
+ results,
452
+ currentIndex,
453
+ decorations: refreshDecorations(decorations, doc, results, currentIndex, textblocks, previousCurrent)
454
+ };
455
+ }
456
+ //#endregion
457
+ //#region src/utils/refreshState.ts
492
458
  function refreshState(previousState, state, doc, meta, docChanged, mapping) {
493
- const results = searchDocument(doc, state.searchTerm, state);
494
- const currentIndex = resolveCurrentIndex(previousState, results, meta, docChanged, mapping);
495
- return {
496
- ...state,
497
- results,
498
- currentIndex,
499
- decorations: createDecorations(doc, results, currentIndex)
500
- };
501
- }
502
-
503
- // src/utils/touchesSearch.ts
504
- var searchKeys = ["searchTerm", "caseSensitive", "useRegex", "wholeWord"];
459
+ const results = searchDocument(doc, state.searchTerm, state);
460
+ const currentIndex = resolveCurrentIndex(previousState, results, meta, docChanged, mapping);
461
+ return {
462
+ ...state,
463
+ results,
464
+ currentIndex,
465
+ decorations: createDecorations(doc, results, currentIndex)
466
+ };
467
+ }
468
+ //#endregion
469
+ //#region src/utils/touchesSearch.ts
470
+ const searchKeys = [
471
+ "searchTerm",
472
+ "caseSensitive",
473
+ "useRegex",
474
+ "wholeWord"
475
+ ];
505
476
  function touchesSearch(meta) {
506
- return !!meta && searchKeys.some((key) => key in meta);
477
+ return !!meta && searchKeys.some((key) => key in meta);
507
478
  }
508
-
509
- // src/utils/updateState.ts
479
+ //#endregion
480
+ //#region src/utils/updateState.ts
510
481
  function updateState(previousState, state, doc, meta, docChanged, mapping) {
511
- if (touchesSearch(meta)) {
512
- return refreshState(previousState, state, doc, meta, docChanged, mapping);
513
- }
514
- if (docChanged) {
515
- return refreshDocumentState(previousState, state, doc, meta, mapping);
516
- }
517
- if (hasCurrentIndex(meta)) {
518
- return refreshCurrentIndexState(previousState, state, doc, meta);
519
- }
520
- return state;
521
- }
522
-
523
- // src/plugin/plugin.ts
524
- var FindAndReplacePluginKey = new PluginKey("findAndReplace");
525
- var FindAndReplacePlugin = (options, onCreate) => {
526
- return new Plugin({
527
- key: FindAndReplacePluginKey,
528
- state: {
529
- init: (_config, state) => {
530
- if (options.injectCSS && typeof document !== "undefined") {
531
- createStyleTag(style, options.injectNonce);
532
- }
533
- const pluginState = createState(state.doc, options);
534
- onCreate(pluginState);
535
- return pluginState;
536
- },
537
- apply: (tr, state, _oldState, newState) => {
538
- const meta = tr.getMeta(FindAndReplacePluginKey);
539
- if (!meta && !tr.docChanged) {
540
- return state;
541
- }
542
- return updateState(
543
- state,
544
- { ...state, ...meta },
545
- newState.doc,
546
- meta,
547
- tr.docChanged,
548
- tr.mapping
549
- );
550
- }
551
- },
552
- props: {
553
- decorations(state) {
554
- var _a;
555
- return (_a = FindAndReplacePluginKey.getState(state)) == null ? void 0 : _a.decorations;
556
- }
557
- }
558
- });
482
+ if (touchesSearch(meta)) return refreshState(previousState, state, doc, meta, docChanged, mapping);
483
+ if (docChanged) return refreshDocumentState(previousState, state, doc, meta, mapping);
484
+ if (hasCurrentIndex(meta)) return refreshCurrentIndexState(previousState, state, doc, meta);
485
+ return state;
486
+ }
487
+ //#endregion
488
+ //#region src/plugin/plugin.ts
489
+ const FindAndReplacePluginKey = new PluginKey("findAndReplace");
490
+ const FindAndReplacePlugin = (options, onCreate) => {
491
+ return new Plugin({
492
+ key: FindAndReplacePluginKey,
493
+ state: {
494
+ init: (_config, state) => {
495
+ if (options.injectCSS && typeof document !== "undefined") createStyleTag(style, options.injectNonce);
496
+ const pluginState = createState(state.doc, options);
497
+ onCreate(pluginState);
498
+ return pluginState;
499
+ },
500
+ apply: (tr, state, _oldState, newState) => {
501
+ const meta = tr.getMeta(FindAndReplacePluginKey);
502
+ if (!meta && !tr.docChanged) return state;
503
+ return updateState(state, {
504
+ ...state,
505
+ ...meta
506
+ }, newState.doc, meta, tr.docChanged, tr.mapping);
507
+ }
508
+ },
509
+ props: { decorations(state) {
510
+ var _FindAndReplacePlugin;
511
+ return (_FindAndReplacePlugin = FindAndReplacePluginKey.getState(state)) === null || _FindAndReplacePlugin === void 0 ? void 0 : _FindAndReplacePlugin.decorations;
512
+ } }
513
+ });
559
514
  };
560
-
561
- // src/utils/getTextNodeResult.ts
515
+ //#endregion
516
+ //#region src/utils/getTextNodeResult.ts
562
517
  function getTextNodeResult(state, result) {
563
- const $from = state.doc.resolve(result.from);
564
- const node = $from.parent.child($from.index());
565
- if (!node.isText || !node.text) {
566
- return null;
567
- }
568
- const from = result.from - $from.textOffset;
569
- return result.to <= from + node.nodeSize ? { from, text: node.text } : null;
570
- }
571
-
572
- // src/utils/groupResults.ts
518
+ const $from = state.doc.resolve(result.from);
519
+ const node = $from.parent.child($from.index());
520
+ if (!node.isText || !node.text) return null;
521
+ const from = result.from - $from.textOffset;
522
+ return result.to <= from + node.nodeSize ? {
523
+ from,
524
+ text: node.text
525
+ } : null;
526
+ }
527
+ //#endregion
528
+ //#region src/utils/groupResults.ts
573
529
  function shouldMergeResult(group, textNode) {
574
- if (!group || !textNode) {
575
- return false;
576
- }
577
- return group.from === textNode.from && group.text !== null;
530
+ if (!group || !textNode) return false;
531
+ return group.from === textNode.from && group.text !== null;
578
532
  }
579
533
  function createTextResultGroup(result, textNode) {
580
- return {
581
- from: textNode.from,
582
- text: textNode.text,
583
- results: [result]
584
- };
534
+ return {
535
+ from: textNode.from,
536
+ text: textNode.text,
537
+ results: [result]
538
+ };
585
539
  }
586
540
  function createResultGroup(result) {
587
- return {
588
- from: result.from,
589
- text: null,
590
- results: [result]
591
- };
541
+ return {
542
+ from: result.from,
543
+ text: null,
544
+ results: [result]
545
+ };
592
546
  }
593
547
  function appendResult(groups, result, textNode) {
594
- const group = groups.at(-1);
595
- if (shouldMergeResult(group, textNode)) {
596
- group.results.push(result);
597
- return;
598
- }
599
- if (textNode) {
600
- groups.push(createTextResultGroup(result, textNode));
601
- return;
602
- }
603
- groups.push(createResultGroup(result));
548
+ const group = groups.at(-1);
549
+ if (shouldMergeResult(group, textNode)) {
550
+ group.results.push(result);
551
+ return;
552
+ }
553
+ if (textNode) {
554
+ groups.push(createTextResultGroup(result, textNode));
555
+ return;
556
+ }
557
+ groups.push(createResultGroup(result));
604
558
  }
605
559
  function groupResults(state, results) {
606
- const groups = [];
607
- for (const result of results) {
608
- appendResult(groups, result, getTextNodeResult(state, result));
609
- }
610
- return groups;
560
+ const groups = [];
561
+ for (const result of results) appendResult(groups, result, getTextNodeResult(state, result));
562
+ return groups;
611
563
  }
612
-
613
- // src/utils/replaceGroup.ts
564
+ //#endregion
565
+ //#region src/utils/replaceGroup.ts
614
566
  function replaceSeparateResults(tr, results, replaceTerm) {
615
- for (const result of [...results].reverse()) {
616
- tr.insertText(replaceTerm, result.from, result.to);
617
- }
567
+ for (const result of [...results].reverse()) tr.insertText(replaceTerm, result.from, result.to);
618
568
  }
619
569
  function createReplacement(group, text, firstResult, replaceTerm) {
620
- let offset = firstResult.from - group.from;
621
- const replacement = [];
622
- for (const result of group.results) {
623
- const from = result.from - group.from;
624
- const to = result.to - group.from;
625
- replacement.push(text.slice(offset, from), replaceTerm);
626
- offset = to;
627
- }
628
- return replacement.join("");
570
+ let offset = firstResult.from - group.from;
571
+ const replacement = [];
572
+ for (const result of group.results) {
573
+ const from = result.from - group.from;
574
+ const to = result.to - group.from;
575
+ replacement.push(text.slice(offset, from), replaceTerm);
576
+ offset = to;
577
+ }
578
+ return replacement.join("");
629
579
  }
630
580
  function replaceGroup(tr, group, replaceTerm) {
631
- const firstResult = group.results[0];
632
- const lastResult = group.results.at(-1);
633
- if (!lastResult) {
634
- return;
635
- }
636
- if (group.text === null) {
637
- replaceSeparateResults(tr, group.results, replaceTerm);
638
- return;
639
- }
640
- tr.insertText(
641
- createReplacement(group, group.text, firstResult, replaceTerm),
642
- firstResult.from,
643
- lastResult.to
644
- );
645
- }
646
-
647
- // src/utils/replaceAllResults.ts
581
+ const firstResult = group.results[0];
582
+ const lastResult = group.results.at(-1);
583
+ if (!lastResult) return;
584
+ if (group.text === null) {
585
+ replaceSeparateResults(tr, group.results, replaceTerm);
586
+ return;
587
+ }
588
+ tr.insertText(createReplacement(group, group.text, firstResult, replaceTerm), firstResult.from, lastResult.to);
589
+ }
590
+ //#endregion
591
+ //#region src/utils/replaceAllResults.ts
648
592
  function replaceAllResults(tr, state, results, replaceTerm) {
649
- const groups = groupResults(state, results);
650
- for (const group of groups.reverse()) {
651
- replaceGroup(tr, group, replaceTerm);
652
- }
593
+ const groups = groupResults(state, results);
594
+ for (const group of groups.reverse()) replaceGroup(tr, group, replaceTerm);
653
595
  }
654
-
655
- // src/find-and-replace.ts
596
+ //#endregion
597
+ //#region src/find-and-replace.ts
656
598
  function mergePluginMeta(tr, meta) {
657
- const currentMeta = tr.getMeta(FindAndReplacePluginKey);
658
- tr.setMeta(FindAndReplacePluginKey, { ...currentMeta, ...meta });
599
+ const currentMeta = tr.getMeta(FindAndReplacePluginKey);
600
+ tr.setMeta(FindAndReplacePluginKey, {
601
+ ...currentMeta,
602
+ ...meta
603
+ });
659
604
  }
660
605
  function setPluginMeta(meta) {
661
- return ({ tr, dispatch }) => {
662
- if (dispatch) {
663
- mergePluginMeta(tr, meta);
664
- }
665
- return true;
666
- };
606
+ return ({ tr, dispatch }) => {
607
+ if (dispatch) mergePluginMeta(tr, meta);
608
+ return true;
609
+ };
667
610
  }
668
611
  function applySearchTerm(editor, term) {
669
- const tr = editor.state.tr;
670
- mergePluginMeta(tr, { searchTerm: term });
671
- editor.view.dispatch(tr);
612
+ const tr = editor.state.tr;
613
+ mergePluginMeta(tr, { searchTerm: term });
614
+ editor.view.dispatch(tr);
672
615
  }
673
616
  function consumePendingSearch(editor) {
674
- const state = getDebouncedSearchState(editor);
675
- if (state.pendingTerm === null) {
676
- return null;
677
- }
678
- const pendingTerm = state.pendingTerm;
679
- state.pendingTerm = null;
680
- if (state.timeout !== null) {
681
- clearTimeout(state.timeout);
682
- state.timeout = null;
683
- }
684
- return pendingTerm;
617
+ const state = getDebouncedSearchState(editor);
618
+ if (state.pendingTerm === null) return null;
619
+ const pendingTerm = state.pendingTerm;
620
+ state.pendingTerm = null;
621
+ if (state.timeout !== null) {
622
+ clearTimeout(state.timeout);
623
+ state.timeout = null;
624
+ }
625
+ return pendingTerm;
685
626
  }
686
627
  function getPendingAwarePluginState(state, pendingTerm) {
687
- const pluginState = FindAndReplacePluginKey.getState(state);
688
- if (!pluginState) {
689
- return null;
690
- }
691
- if (pendingTerm === null) {
692
- return pluginState.results.length === 0 ? null : pluginState;
693
- }
694
- const results = searchDocument(state.doc, pendingTerm, {
695
- caseSensitive: pluginState.caseSensitive,
696
- useRegex: pluginState.useRegex,
697
- wholeWord: pluginState.wholeWord
698
- });
699
- if (results.length === 0) {
700
- return null;
701
- }
702
- return {
703
- ...pluginState,
704
- searchTerm: pendingTerm,
705
- results,
706
- currentIndex: 0
707
- };
628
+ const pluginState = FindAndReplacePluginKey.getState(state);
629
+ if (!pluginState) return null;
630
+ if (pendingTerm === null) return pluginState.results.length === 0 ? null : pluginState;
631
+ const results = searchDocument(state.doc, pendingTerm, {
632
+ caseSensitive: pluginState.caseSensitive,
633
+ useRegex: pluginState.useRegex,
634
+ wholeWord: pluginState.wholeWord
635
+ });
636
+ if (results.length === 0) return null;
637
+ return {
638
+ ...pluginState,
639
+ searchTerm: pendingTerm,
640
+ results,
641
+ currentIndex: 0
642
+ };
708
643
  }
709
644
  function currentResult(pluginState) {
710
- var _a;
711
- return pluginState.results[(_a = pluginState.currentIndex) != null ? _a : 0];
645
+ var _pluginState$currentI;
646
+ return pluginState.results[(_pluginState$currentI = pluginState.currentIndex) !== null && _pluginState$currentI !== void 0 ? _pluginState$currentI : 0];
712
647
  }
713
648
  function shiftIndex(currentIndex, length, direction) {
714
- if (currentIndex === null) {
715
- return direction === 1 ? 0 : length - 1;
716
- }
717
- return (currentIndex + direction + length) % length;
649
+ if (currentIndex === null) return direction === 1 ? 0 : length - 1;
650
+ return (currentIndex + direction + length) % length;
718
651
  }
719
652
  function selectResult(tr, result, index) {
720
- tr.setSelection(TextSelection.create(tr.doc, result.from, result.to));
721
- mergePluginMeta(tr, { currentIndex: index });
722
- tr.scrollIntoView();
653
+ tr.setSelection(TextSelection.create(tr.doc, result.from, result.to));
654
+ mergePluginMeta(tr, { currentIndex: index });
655
+ tr.scrollIntoView();
723
656
  }
724
657
  function replaceResult(tr, pluginState, result) {
725
- const { searchTerm, replaceTerm, caseSensitive, useRegex, wholeWord } = pluginState;
726
- tr.insertText(replaceTerm, result.from, result.to);
727
- const results = searchDocument(tr.doc, searchTerm, { caseSensitive, useRegex, wholeWord });
728
- const nextIndex = findNextIndex(results, result.from + replaceTerm.length);
729
- if (nextIndex === null) {
730
- mergePluginMeta(tr, { currentIndex: null });
731
- return;
732
- }
733
- selectResult(tr, results[nextIndex], nextIndex);
734
- }
735
- var FindAndReplace = Extension.create({
736
- name: "findAndReplace",
737
- addOptions() {
738
- return {
739
- searchTerm: "",
740
- replaceTerm: "",
741
- caseSensitive: false,
742
- useRegex: false,
743
- wholeWord: false,
744
- searchDebounceMs: 250,
745
- injectCSS: true,
746
- injectNonce: void 0
747
- };
748
- },
749
- addStorage() {
750
- return {
751
- searchTerm: this.options.searchTerm,
752
- replaceTerm: this.options.replaceTerm,
753
- caseSensitive: this.options.caseSensitive,
754
- useRegex: this.options.useRegex,
755
- wholeWord: this.options.wholeWord,
756
- results: [],
757
- currentIndex: null
758
- };
759
- },
760
- addProseMirrorPlugins() {
761
- return [
762
- FindAndReplacePlugin(this.options, (pluginState) => {
763
- this.storage.results = pluginState.results;
764
- this.storage.currentIndex = pluginState.currentIndex;
765
- })
766
- ];
767
- },
768
- onTransaction() {
769
- const pluginState = FindAndReplacePluginKey.getState(this.editor.state);
770
- if (!pluginState) {
771
- return;
772
- }
773
- this.storage.searchTerm = pluginState.searchTerm;
774
- this.storage.replaceTerm = pluginState.replaceTerm;
775
- this.storage.caseSensitive = pluginState.caseSensitive;
776
- this.storage.useRegex = pluginState.useRegex;
777
- this.storage.wholeWord = pluginState.wholeWord;
778
- this.storage.results = pluginState.results;
779
- this.storage.currentIndex = pluginState.currentIndex;
780
- },
781
- addCommands() {
782
- const scheduleSearchTerm = (term) => {
783
- const state = getDebouncedSearchState(this.editor);
784
- if (this.options.searchDebounceMs <= 0) {
785
- if (state.timeout !== null) {
786
- clearTimeout(state.timeout);
787
- state.timeout = null;
788
- }
789
- state.pendingTerm = null;
790
- applySearchTerm(this.editor, term);
791
- return true;
792
- }
793
- if (state.timeout !== null) {
794
- clearTimeout(state.timeout);
795
- }
796
- state.pendingTerm = term;
797
- state.timeout = setTimeout(() => {
798
- const debouncedState = getDebouncedSearchState(this.editor);
799
- debouncedState.timeout = null;
800
- if (debouncedState.pendingTerm === null) {
801
- return;
802
- }
803
- const pendingTerm = debouncedState.pendingTerm;
804
- debouncedState.pendingTerm = null;
805
- applySearchTerm(this.editor, pendingTerm);
806
- }, this.options.searchDebounceMs);
807
- return true;
808
- };
809
- return {
810
- setSearchTerm: (term) => ({ dispatch }) => {
811
- if (!dispatch) {
812
- return true;
813
- }
814
- return scheduleSearchTerm(term);
815
- },
816
- setReplaceTerm: (term) => setPluginMeta({ replaceTerm: term }),
817
- setCaseSensitive: (caseSensitive) => setPluginMeta({ caseSensitive }),
818
- setUseRegex: (useRegex) => setPluginMeta({ useRegex }),
819
- setWholeWord: (wholeWord) => setPluginMeta({ wholeWord }),
820
- clearSearch: () => ({ tr, dispatch }) => {
821
- const state = getDebouncedSearchState(this.editor);
822
- if (state.timeout !== null) {
823
- clearTimeout(state.timeout);
824
- state.timeout = null;
825
- }
826
- state.pendingTerm = null;
827
- if (dispatch) {
828
- mergePluginMeta(tr, { searchTerm: "" });
829
- }
830
- return true;
831
- },
832
- replace: () => ({ tr, state, dispatch }) => {
833
- const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
834
- if (dispatch && pendingTerm !== null) {
835
- mergePluginMeta(tr, { searchTerm: pendingTerm });
836
- }
837
- const pluginState = getPendingAwarePluginState(state, pendingTerm);
838
- if (!pluginState) {
839
- return false;
840
- }
841
- const result = currentResult(pluginState);
842
- if (!result) {
843
- return false;
844
- }
845
- if (dispatch) {
846
- replaceResult(tr, pluginState, result);
847
- }
848
- return true;
849
- },
850
- replaceAll: () => ({ tr, state, dispatch }) => {
851
- const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
852
- if (dispatch && pendingTerm !== null) {
853
- mergePluginMeta(tr, { searchTerm: pendingTerm });
854
- }
855
- const pluginState = getPendingAwarePluginState(state, pendingTerm);
856
- if (!pluginState) {
857
- return false;
858
- }
859
- if (dispatch) {
860
- replaceAllResults(tr, state, pluginState.results, pluginState.replaceTerm);
861
- }
862
- return true;
863
- },
864
- goToNextResult: () => ({ tr, state, dispatch }) => {
865
- const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
866
- if (dispatch && pendingTerm !== null) {
867
- mergePluginMeta(tr, { searchTerm: pendingTerm });
868
- }
869
- const pluginState = getPendingAwarePluginState(state, pendingTerm);
870
- if (!pluginState) {
871
- return false;
872
- }
873
- const nextIndex = shiftIndex(pluginState.currentIndex, pluginState.results.length, 1);
874
- if (dispatch) {
875
- selectResult(tr, pluginState.results[nextIndex], nextIndex);
876
- }
877
- return true;
878
- },
879
- goToPreviousResult: () => ({ tr, state, dispatch }) => {
880
- const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
881
- if (dispatch && pendingTerm !== null) {
882
- mergePluginMeta(tr, { searchTerm: pendingTerm });
883
- }
884
- const pluginState = getPendingAwarePluginState(state, pendingTerm);
885
- if (!pluginState) {
886
- return false;
887
- }
888
- const previousIndex = shiftIndex(pluginState.currentIndex, pluginState.results.length, -1);
889
- if (dispatch) {
890
- selectResult(tr, pluginState.results[previousIndex], previousIndex);
891
- }
892
- return true;
893
- }
894
- };
895
- },
896
- onDestroy() {
897
- clearDebouncedSearchState(this.editor);
898
- }
658
+ const { searchTerm, replaceTerm, caseSensitive, useRegex, wholeWord } = pluginState;
659
+ tr.insertText(replaceTerm, result.from, result.to);
660
+ const results = searchDocument(tr.doc, searchTerm, {
661
+ caseSensitive,
662
+ useRegex,
663
+ wholeWord
664
+ });
665
+ const nextIndex = findNextIndex(results, result.from + replaceTerm.length);
666
+ if (nextIndex === null) {
667
+ mergePluginMeta(tr, { currentIndex: null });
668
+ return;
669
+ }
670
+ selectResult(tr, results[nextIndex], nextIndex);
671
+ }
672
+ const FindAndReplace = Extension.create({
673
+ name: "findAndReplace",
674
+ addOptions() {
675
+ return {
676
+ searchTerm: "",
677
+ replaceTerm: "",
678
+ caseSensitive: false,
679
+ useRegex: false,
680
+ wholeWord: false,
681
+ searchDebounceMs: 250,
682
+ injectCSS: true,
683
+ injectNonce: void 0
684
+ };
685
+ },
686
+ addStorage() {
687
+ return {
688
+ searchTerm: this.options.searchTerm,
689
+ replaceTerm: this.options.replaceTerm,
690
+ caseSensitive: this.options.caseSensitive,
691
+ useRegex: this.options.useRegex,
692
+ wholeWord: this.options.wholeWord,
693
+ results: [],
694
+ currentIndex: null
695
+ };
696
+ },
697
+ addProseMirrorPlugins() {
698
+ return [FindAndReplacePlugin(this.options, (pluginState) => {
699
+ this.storage.results = pluginState.results;
700
+ this.storage.currentIndex = pluginState.currentIndex;
701
+ })];
702
+ },
703
+ onTransaction() {
704
+ const pluginState = FindAndReplacePluginKey.getState(this.editor.state);
705
+ if (!pluginState) return;
706
+ this.storage.searchTerm = pluginState.searchTerm;
707
+ this.storage.replaceTerm = pluginState.replaceTerm;
708
+ this.storage.caseSensitive = pluginState.caseSensitive;
709
+ this.storage.useRegex = pluginState.useRegex;
710
+ this.storage.wholeWord = pluginState.wholeWord;
711
+ this.storage.results = pluginState.results;
712
+ this.storage.currentIndex = pluginState.currentIndex;
713
+ },
714
+ addCommands() {
715
+ const scheduleSearchTerm = (term) => {
716
+ const state = getDebouncedSearchState(this.editor);
717
+ if (this.options.searchDebounceMs <= 0) {
718
+ if (state.timeout !== null) {
719
+ clearTimeout(state.timeout);
720
+ state.timeout = null;
721
+ }
722
+ state.pendingTerm = null;
723
+ applySearchTerm(this.editor, term);
724
+ return true;
725
+ }
726
+ if (state.timeout !== null) clearTimeout(state.timeout);
727
+ state.pendingTerm = term;
728
+ state.timeout = setTimeout(() => {
729
+ const debouncedState = getDebouncedSearchState(this.editor);
730
+ debouncedState.timeout = null;
731
+ if (debouncedState.pendingTerm === null) return;
732
+ const pendingTerm = debouncedState.pendingTerm;
733
+ debouncedState.pendingTerm = null;
734
+ applySearchTerm(this.editor, pendingTerm);
735
+ }, this.options.searchDebounceMs);
736
+ return true;
737
+ };
738
+ return {
739
+ setSearchTerm: (term) => ({ dispatch }) => {
740
+ if (!dispatch) return true;
741
+ return scheduleSearchTerm(term);
742
+ },
743
+ setReplaceTerm: (term) => setPluginMeta({ replaceTerm: term }),
744
+ setCaseSensitive: (caseSensitive) => setPluginMeta({ caseSensitive }),
745
+ setUseRegex: (useRegex) => setPluginMeta({ useRegex }),
746
+ setWholeWord: (wholeWord) => setPluginMeta({ wholeWord }),
747
+ clearSearch: () => ({ tr, dispatch }) => {
748
+ const state = getDebouncedSearchState(this.editor);
749
+ if (state.timeout !== null) {
750
+ clearTimeout(state.timeout);
751
+ state.timeout = null;
752
+ }
753
+ state.pendingTerm = null;
754
+ if (dispatch) mergePluginMeta(tr, { searchTerm: "" });
755
+ return true;
756
+ },
757
+ replace: () => ({ tr, state, dispatch }) => {
758
+ const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
759
+ if (dispatch && pendingTerm !== null) mergePluginMeta(tr, { searchTerm: pendingTerm });
760
+ const pluginState = getPendingAwarePluginState(state, pendingTerm);
761
+ if (!pluginState) return false;
762
+ const result = currentResult(pluginState);
763
+ if (!result) return false;
764
+ if (dispatch) replaceResult(tr, pluginState, result);
765
+ return true;
766
+ },
767
+ replaceAll: () => ({ tr, state, dispatch }) => {
768
+ const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
769
+ if (dispatch && pendingTerm !== null) mergePluginMeta(tr, { searchTerm: pendingTerm });
770
+ const pluginState = getPendingAwarePluginState(state, pendingTerm);
771
+ if (!pluginState) return false;
772
+ if (dispatch) replaceAllResults(tr, state, pluginState.results, pluginState.replaceTerm);
773
+ return true;
774
+ },
775
+ goToNextResult: () => ({ tr, state, dispatch }) => {
776
+ const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
777
+ if (dispatch && pendingTerm !== null) mergePluginMeta(tr, { searchTerm: pendingTerm });
778
+ const pluginState = getPendingAwarePluginState(state, pendingTerm);
779
+ if (!pluginState) return false;
780
+ const nextIndex = shiftIndex(pluginState.currentIndex, pluginState.results.length, 1);
781
+ if (dispatch) selectResult(tr, pluginState.results[nextIndex], nextIndex);
782
+ return true;
783
+ },
784
+ goToPreviousResult: () => ({ tr, state, dispatch }) => {
785
+ const pendingTerm = dispatch ? consumePendingSearch(this.editor) : null;
786
+ if (dispatch && pendingTerm !== null) mergePluginMeta(tr, { searchTerm: pendingTerm });
787
+ const pluginState = getPendingAwarePluginState(state, pendingTerm);
788
+ if (!pluginState) return false;
789
+ const previousIndex = shiftIndex(pluginState.currentIndex, pluginState.results.length, -1);
790
+ if (dispatch) selectResult(tr, pluginState.results[previousIndex], previousIndex);
791
+ return true;
792
+ }
793
+ };
794
+ },
795
+ onDestroy() {
796
+ clearDebouncedSearchState(this.editor);
797
+ }
899
798
  });
799
+ //#endregion
800
+ //#region src/index.ts
801
+ var src_default = FindAndReplace;
802
+ //#endregion
803
+ export { FindAndReplace, FindAndReplacePlugin, FindAndReplacePluginKey, createSearchRegex, currentResultClass, src_default as default, findNextIndex, resultClass, searchDocument, searchTextblocks };
900
804
 
901
- // src/index.ts
902
- var index_default = FindAndReplace;
903
- export {
904
- FindAndReplace,
905
- FindAndReplacePlugin,
906
- FindAndReplacePluginKey,
907
- createSearchRegex,
908
- currentResultClass,
909
- index_default as default,
910
- findNextIndex,
911
- resultClass,
912
- searchDocument,
913
- searchTextblocks
914
- };
915
805
  //# sourceMappingURL=index.js.map