react-highlight-search
Version:
Text highlight with deep search through DOM elements.
2 lines (1 loc) • 3 kB
JavaScript
import e,{useRef as t,useEffect as n,memo as o,useState as r,useCallback as l}from"react";const s=(e,t,n,o)=>{var r,l;let s=0,d=0,a=-1,i=-1,c=0,h=0;for(let u=0;u<e.length&&(d=s+((null===(l=null===(r=e[u])||void 0===r?void 0:r.textContent)||void 0===l?void 0:l.length)||1)-1,t>=s&&t<=d&&(a=u,c=t-s),n>=s&&n<=d&&(i=u,h=n-s+1),a!==u&&i!==u||o({index:u,node:e[u],startPos:a===u?c:0,endPos:i===u?h:d+1}),s=d+1,!(i>-1));u++);};!function(e,t){void 0===t&&(t={});var n=t.insertAt;if("undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css","top"===n&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e))}}(".hlsearch-span-el{background-color:#7ec9ff}");var d=o((({searchString:o,setTriggerSearch:d,searchMinLength:a=1,onMatchData:i,children:c,spanClassName:h="hlsearch-span-el",ignoreCase:u=!0,index:p=0})=>{const f=t(null),v=t(null),[m,g]=r(),E=function(e){const o=t();return n((()=>{o.current=e}),[e]),o.current}(o),x=l((e=>{null==i||i({wrapperIndex:p,matchesFound:e,matchParentElement:e?f.current:null})}),[p,i]),N=l((e=>{var t,n;if(x(0),void 0!==(n=m)&&n.forEach((({newNodes:e,oldNode:t,parentNode:n})=>{const o=e[e.length-1].nextSibling||null;null==n||n.insertBefore(t,o),e.forEach((e=>{e.remove()}))})),(null==e?void 0:e.length)<(a>0?a:1))return void g(void 0);const o=[],r=e=>{null==e||e.forEach((e=>{e.nodeType===e.ELEMENT_NODE?r(e.childNodes):e.nodeType===e.TEXT_NODE&&o.push(e)}))};if(r(null===(t=v.current)||void 0===t?void 0:t.childNodes),!o.length)return;let l="";o.forEach((e=>{l+=e.textContent}));const d=new RegExp(e,u?"ig":"g"),i=l.matchAll(d);let c=0;const{matchData:p,matchDataController:f}=(()=>{const e=[];return{matchData:e,matchDataController:({index:t,node:n,startPos:o,endPos:r})=>{var l;e[t]?null===(l=e[t].positionsArr)||void 0===l||l.push({startPos:o,endPos:r}):e[t]={node:n,positionsArr:[{startPos:o,endPos:r}]}}}})();for(const e of i){if(void 0===e.index)return;c++,s(o,e.index,e.index+e[0].length-1,f)}x(c),((e,t,n)=>{const o=[];e.forEach((({node:e,positionsArr:t})=>{const r=e.parentNode,l=e.nextSibling||null,s=e.textContent,d=[],a=[];t.forEach((({startPos:e,endPos:n},o)=>{var r;e!==n&&(o<1&&d.push((null==s?void 0:s.slice(0,e))||""),d.push((null==s?void 0:s.slice(e,n))||""),d.push((null==s?void 0:s.slice(n,(null===(r=t[o+1])||void 0===r?void 0:r.startPos)||s.length))||""))})),e.remove(),d.forEach(((e,t)=>{if(e){let o=document.createTextNode(e);if(t%2!=0){const e=document.createElement("span");n&&e.classList.add(n),e.appendChild(o),a.push(e),null==r||r.insertBefore(e,l)}else a.push(o),null==r||r.insertBefore(o,l)}})),o.push({newNodes:a,oldNode:e,parentNode:r})})),t(o)})(p,g,h)}),[u,m,a,x,h]);return n((()=>{void 0!==o&&o!==E&&N(o)}),[E,o,N]),n((()=>{null==d||d((()=>e=>N(e)))}),[d,N]),e.createElement("div",{ref:f},e.createElement("div",{ref:v},c))}));export{d as HighlightSearchWrapper};