Highlight tokens on the DOM like the Grammarly. Inspired by Making Grammarly Feel Native On Every Website.
yarn add dom-highlight-lib
# or
npm install --save dom-highlight-lib
-
Define an asynchronous
match
function that accepts an array of strings and returns an two-level array of tokens (the keywords found in the input strings).- For each input string, the function should return an array of tokens.
- The order of returned two-level array should be same to the order of the input strings, so that we could tell what tokens are returned for a specific input string.
// for example let id = 0; const regex = /\w+/mg const match = (texts) => new Promise((resolve) => { const tokenize = (text) => { const tokens = []; let m = regex.exec(text); while (m !== null) { tokens.push({ id: `${id}`, color: `#ff0000`, start: m.index, end: m.index + m[0].length, keyword: m[0] }); id += 1; m = regex.exec(text); } return tokens; }; resolve(texts.map(tokenize)); });
-
Decide what to do when the user mouse hover on a highlight.
// for example const tokenView = document.createElement('div'); tokenView.style.color = '#fff'; tokenView.style.borderRadius = '8px'; tokenView.style.boxShadow = '0 2px 15px 0 rgba(68, 70, 73, 0.2)'; tokenView.style.padding = '10px'; tokenView.style.position = 'absolute'; tokenView.style.width = '362px'; tokenView.style.zIndex = '2147483647'; document.body.appendChild(tokenView); const showToken = (token, rect, event) => { tokenView.style.background = token.color; tokenView.style.top = `${rect.top}px`; tokenView.style.left = `${rect.left}px`; tokenView.innerHTML = `<ul><li>ID: {token.id}</li><li>Title: {token.keyword}</li></ul>`; tokenView.style.display = 'block'; }; const hideToken = (token, rect, event) => { tokenView.innerHTML = ''; tokenView.style.display = 'none'; };
-
Optionally, provide below parameters:
selectors
: specify CSS selector string of the root nodes to match. Defaults to thedocument.documentElement
.ignoreInvisibleNodes
: whether ignores invisible nodes. Defaults totrue
.minTextLength
: Ignore text nodes whose text length is less than specified value. Defaults to3
.trimInvisibleChars
: Whether ignores the leading and trailing invisible chars before counting the text length. Defaults totrue
.minBatchTextLength
: controls how often to invoke thematch
function according to the total number of characters in the strings. Defaults to1000
.className
: the CSS class name for the highlights container. Defaults to empty string.throttleUpdates
: Throttle highlight updates, update at most once every specified milliseconds. Defaults to500
ms.
-
Start the highlighter.
// for example, on a web page const highlighter = require('dom-highlight-lib'); highlighter.start({ match, showToken, hideToken, selectors: '', ignoreInvisibleNodes: true, minTextLength: 3, trimInvisibleChars: true, minBatchTextLength: 1000, className: '', throttleUpdates: 500 });
The highlighter now scans and monitor changes (
scroll
,resize
, andMutationObserver
) on the web page, and update highlights when necessary.
textarea
andinput
controls are not supported becauseRange.getClientRects()
returns empty list.- Because the
match
function is asynchronous, it possible for the highlighter to run into an inconsistent state when DOM changes frequently.