diff --git a/packages/super-editor/src/core/Editor.js b/packages/super-editor/src/core/Editor.js index b5ad623b67..38b21de8f8 100644 --- a/packages/super-editor/src/core/Editor.js +++ b/packages/super-editor/src/core/Editor.js @@ -136,7 +136,7 @@ export class Editor extends EventEmitter { if (textModes.includes(options.mode) && options.element) { options.element.classList.add('sd-super-editor-html'); } - }; + } options.element = options.isHeadless ? null : options.element || document.createElement('div'); } diff --git a/packages/super-editor/src/extensions/search/search.js b/packages/super-editor/src/extensions/search/search.js index c6648ffe32..4bca2ab157 100644 --- a/packages/super-editor/src/extensions/search/search.js +++ b/packages/super-editor/src/extensions/search/search.js @@ -1,11 +1,41 @@ import { Extension } from '@core/Extension.js'; import { search, SearchQuery, setSearchState, getMatchHighlights } from 'prosemirror-search'; -import { TextSelection } from 'prosemirror-state'; - +import { Plugin, PluginKey, TextSelection } from 'prosemirror-state'; +import { Decoration, DecorationSet } from 'prosemirror-view'; +import { v4 as uuidv4 } from 'uuid'; export const Search = Extension.create({ + addStorage() { + return { + searchResults: [], + }; + }, + addPmPlugins() { - return [search()]; + const editor = this.editor; + const storage = this.storage; + + const searchHighlightWithIdPlugin = new Plugin({ + key: new PluginKey('customSearchHighlights'), + props: { + decorations(state) { + if (!editor) return null; + + const matches = storage?.searchResults; + if (!matches?.length) return null; + + const decorations = matches.map((match, index) => + Decoration.inline(match.from, match.to, { + id: `search-match-${match.id}`, + }) + ); + + return DecorationSet.create(state.doc, decorations); + } + } + }); + + return [search(), searchHighlightWithIdPlugin]; }, addCommands() { @@ -19,7 +49,7 @@ export const Search = Extension.create({ editor.view.domAtPos(firstSearchItemPosition)?.node?.scrollIntoView(true); }, - search: (patternInput) => ({ state, dispatch }) => { + search: (patternInput) => ({ state, editor, dispatch }) => { let pattern; let caseSensitive = false; let regexp = false; @@ -47,14 +77,21 @@ export const Search = Extension.create({ const tr = setSearchState(state.tr, query); dispatch(tr); - const newState = state.apply(tr); - const decoSet = getMatchHighlights(newState); - const matches = decoSet ? decoSet.find() : []; - return matches.map(d => ({ + const newState = state.apply(tr); + + const decoSet = getMatchHighlights(newState); + const matches = decoSet ? decoSet.find() : []; + + const resultMatches = matches.map(d => ({ from: d.from, - to: d.to, - text: newState.doc.textBetween(d.from, d.to) + to: d.to, + text: newState.doc.textBetween(d.from, d.to), + id: uuidv4(), })); + + this.storage.searchResults = resultMatches; + + return resultMatches; }, goToSearchResult: (match) => ({ state, dispatch, editor }) => { @@ -71,9 +108,13 @@ export const Search = Extension.create({ node.scrollIntoView({ block: 'center', inline: 'nearest' }) } - return true + return true; }, } } }); + + + +