UNPKG

rich-textarea

Version:

A small customizable textarea for React to colorize, highlight, decorate texts, offer autocomplete and much more.

7 lines (6 loc) 10.6 kB
"use client"; import{forwardRef as e,memo as t,useCallback as n,useEffect as o,useImperativeHandle as r,useLayoutEffect as i,useMemo as s,useRef as l,useState as c}from"react";import{Fragment as u,jsx as d,jsxs as a}from"react/jsx-runtime";var{min:p,max:h}=Math,g="current",f=/* @__PURE__ */d("span",{style:{color:"transparent"},children:"​"});function b(e,t,n,o){var r=e.ownerDocument;o||(o=r.createRange());let i,s,l,c=r.createNodeIterator(e,NodeFilter.SHOW_TEXT,null,!1),u={},d={};for(;i=c.nextNode();)s=i.nodeValue,l=s.length,!u.node&&l>t&&(u.node=i,u.offset=t),!d.node&&l>=n&&(d.node=i,d.offset=n),t-=l,n-=l;return u.node&&o.setStart(u.node,h(u.offset,0)),d.node&&o.setEnd(d.node,h(d.offset,0)),o}var S=["direction","padding","paddingTop","paddingBottom","paddingLeft","paddingRight","margin","marginTop","marginBottom","marginLeft","marginRight","border","borderWidth","borderTopWidth","borderBottomWidth","borderLeftWidth","borderRightWidth","borderStyle","borderTopStyle","borderBottomStyle","borderLeftStyle","borderRightStyle","fontSize","fontFamily","fontStyle","fontVariant","fontWeight","fontStretch","fontSizeAdjust","textAlign","textTransform","textIndent","letterSpacing","wordSpacing","lineHeight","whiteSpace","wordBreak","overflowWrap","tabSize","MozTabSize"],m=(e,t)=>e.getPropertyValue(t),v=(e,t,n)=>{e.setProperty(t,n)},x=(e,t)=>{const n=m(e,t);return n?parseInt(n,10):0},y=e=>getComputedStyle(e),w=e=>"string"==typeof e&&e.endsWith("%"),_=e=>x(e,"padding-top")+x(e,"padding-bottom")+x(e,"border-top")+x(e,"border-bottom"),M=e=>x(e,"padding-left")+x(e,"padding-right")+x(e,"border-left")+x(e,"border-right"),k=(e,t,n)=>{const o="pointer-events",r=e.style,i=t.style,s=m(r,o),l=m(i,o);v(r,o,"none"),v(i,o,"auto");const c=document.elementFromPoint(n.clientX,n.clientY);return v(r,o,s),v(i,o,l),z(c,t)?c:null},z=(e,t)=>!!e&&t!==e&&t.contains(e),T=(e,t,n)=>{e.dispatchEvent(new MouseEvent(t,n))},C=(e,t)=>{T(e,t.type,t)},E=(e,t)=>{e&&T(e,"mouseout",t)},A=e=>{e.stopPropagation()},W=(e,t,n,o)=>{const r=y(e),i=e.style,s=t.style;n.current||(n[g]=m(r,"color")),S.forEach(e=>{s[e]=r[e]}),i.color=s.borderColor="transparent",i.caretColor=o?.caretColor||n.current},R=(e,t,n)=>(e.addEventListener(t,n),()=>{e.removeEventListener(t,n)}),j=(e,t)=>{let n,o=[null,null];const r={t(){setTimeout(()=>{t((()=>{const e=r.o(),t=r.i();return o[0]===e&&o[1]===t||(o=[e,t]),o})())})},l(e){n=e},o(){const t=e[g];if(!t)return 0;const o=t.selectionStart;return n?p(o,t.selectionEnd-n.data.length):o},i(){const t=e[g];if(!t)return 0;const o=t.selectionEnd;return n?p(o,t.selectionStart+n.data.length):o}};return r},B="undefined"!=typeof window?i:o,D=e=>{const t=l(void 0);return t.current||(t.current=e())},L=(e,t,n,o,r)=>{let i=null;const s=new ResizeObserver(([t])=>{const{contentRect:{width:n,height:r},borderBoxSize:i}=t;if(i&&i[0])return void o([n,r,i[0].inlineSize-n,i[0].blockSize-r]);const s=y(e);o([n,r,M(s),_(s)])}),l=R(e,"focus",()=>{r(!0)}),c=R(e,"blur",()=>{r(!1)}),u=R(e,"scroll",()=>{const{scrollTop:n,scrollLeft:o}=e;t.style.transform=`translate(${-o}px, ${-n}px)`}),d=R(e,"mousedown",o=>{n.t();const r=R(document,"mouseup",()=>{n.t(),r()}),i=k(e,t,o);i&&C(i,o)}),a=R(e,"mouseup",n=>{const o=k(e,t,n);o&&C(o,n)}),p=R(e,"mousemove",n=>{const o=k(e,t,n);((e,t,n)=>{e&&C(e,n),t!==e&&(E(t,n),e&&T(e,"mouseover",n))})(o,i,n),i=o}),h=R(e,"mouseleave",e=>{E(i,e),i=null}),g=R(e,"click",n=>{const o=k(e,t,n);o&&C(o,n)}),f=R(e,"input",()=>{n.t()}),b=R(e,"compositionstart",e=>{n.l(e)}),S=R(e,"compositionupdate",e=>{n.l(e)}),m=R(e,"compositionend",()=>{n.l()});return s.observe(e),()=>{l(),c(),u(),d(),a(),p(),h(),g(),f(),b(),S(),m(),s.disconnect()}},U=t(({u:e,p:t,h:n,S:o})=>{const[i,l]=c("");return r(t,()=>l,[]),/* @__PURE__ */a("div",{ref:e,"aria-hidden":!0,style:s(()=>({width:o,transform:"translate(0px, 0px)",pointerEvents:"none",userSelect:"none",msUserSelect:"none",WebkitUserSelect:"none",boxSizing:"content-box",textSizeAdjust:"100%",WebkitTextSizeAdjust:"100%",MozTextSizeAdjust:"100%"}),[o]),onClick:A,onMouseDown:A,onMouseUp:A,onMouseOver:A,onMouseOut:A,onMouseMove:A,children:[s(()=>n?n(i):i,[i,n]),f]})}),$=/*#__PURE__*/e(({children:e,autoHeight:t,style:i,onChange:u,onKeyDown:p,onSelectionChange:h,...f},S)=>{const m=l(null),v=l(null),x=l(null),[[y,_,M,k],z]=c([0,0,0,0]),[T,C]=c(!1),E=l(""),[[A,R],$]=c([null,null]),O=D(()=>j(m,$)),H=y+M,K=_+k,I=!!(H+K);return r(S,()=>{const e=m[g],t={get selectionStart(){return O.o()},get selectionEnd(){return O.i()},setRangeText(t,n,o,r){e.setRangeText?e.setRangeText(t,n,o,r):(e.focus(),e.selectionStart=n,e.selectionEnd=o,document.execCommand("insertText",!1,t)),e.dispatchEvent(new Event("input",{bubbles:!0}))}};return new Proxy(e,{get(e,n){if(t[n])return t[n];const o=e[n];return"function"==typeof o?o.bind(e):o},set:(e,t,n)=>(e[t]=n,!0)})},[]),B(()=>{const e=m[g],t=v[g];if(e&&t)return L(e,t,O,z,C)},[]),B(()=>{const e=m[g];e&&x[g](e.value)},[f.value]),B(()=>{const e=m[g],t=v[g];t&&e&&W(e,t,E,i)},[i]),o(()=>{if(null!=A&&null!=R&&h)if(T){const e=b(v[g],A,A+1).getBoundingClientRect();h({focused:!0,top:e.top,left:e.left,height:e.height,selectionStart:A,selectionEnd:R})}else h({focused:!1,selectionStart:A,selectionEnd:R})},[T,A,R]),o(()=>{const e=m[g];t&&e&&(e.style.height="auto",e.style.height=e.scrollHeight+"px")}),/* @__PURE__ */a("div",{style:s(()=>{let e=H,t=K;return i&&(w(i.width)&&(e=i.width),w(i.height)&&(t=i.height)),{display:"inline-block",position:"relative",width:e,height:t}},[H,K,i]),children:[/* @__PURE__ */d("div",{style:s(()=>{const e={position:"absolute",overflow:"hidden",top:0,left:0,width:H,height:K};return i?(["background","backgroundColor"].forEach(t=>{i[t]&&(e[t]=i[t])}),e):e},[H,K,i]),children:/* @__PURE__ */d(U,{u:v,p:x,h:e,S:y})}),/* @__PURE__ */d("textarea",{...f,ref:m,style:s(()=>({...i,background:"transparent",margin:0,position:"absolute",...!I&&{position:void 0,verticalAlign:"top"}}),[i,I]),onChange:n(e=>{x[g]?.(e.target.value),u?.(e)},[u]),onKeyDown:n(e=>{e.nativeEvent.isComposing||229===e.nativeEvent.keyCode||(p?.(e),O.t())},[p])})]})}),O=/*#__PURE__*/t(({u:e,p:t,h:n,m:o})=>{const[i,l]=c("");return r(t,()=>l,[]),/* @__PURE__ */d("div",{ref:e,"aria-hidden":!0,onClick:A,onMouseDown:A,onMouseUp:A,onMouseOver:A,onMouseOut:A,onMouseMove:A,children:/* @__PURE__ */d("div",{style:{height:o},children:/* @__PURE__ */a("div",{style:s(()=>({transform:"translate(0px, 0px)",pointerEvents:"none",userSelect:"none",msUserSelect:"none",WebkitUserSelect:"none",boxSizing:"content-box",textSizeAdjust:"100%",WebkitTextSizeAdjust:"100%",MozTextSizeAdjust:"100%",whiteSpace:"pre"}),[]),children:[s(()=>n?n(i):i,[i,n]),f]})})})}),H=/*#__PURE__*/e(({children:e,autoHeight:t,style:i,onChange:u,onKeyDown:p,onSelectionChange:h,...f},S)=>{const m=l(null),v=l(null),x=l(null),[[y,_,M,k],z]=c([0,0,0,0]),[T,C]=c(!1),E=l(""),[[A,R],U]=c([null,null]),$=D(()=>{const e=(()=>{if("undefined"==typeof navigator)return!1;const e=navigator.userAgent.toLowerCase();return e.indexOf("safari")>-1&&e.indexOf("chrome")<=-1})();return j(m,t=>{if(U(t),e){if(!m.current||!v.current)return;const{scrollTop:e,scrollLeft:t}=m[g];v[g].style.transform=`translate(${-t}px, ${-e}px)`}})}),H=y+M,K=_+k,I=!!(H+K);return r(S,()=>{const e=m[g],t={get selectionStart(){return $.o()},get selectionEnd(){return $.i()},setRangeText(t,n,o,r){e.setRangeText?e.setRangeText(t,n,o,r):(e.focus(),e.selectionStart=n,e.selectionEnd=o,document.execCommand("insertText",!1,t)),e.dispatchEvent(new Event("input",{bubbles:!0}))}};return new Proxy(e,{get(e,n){if(t[n])return t[n];const o=e[n];return"function"==typeof o?o.bind(e):o},set:(e,t,n)=>(e[t]=n,!0)})},[]),B(()=>{const e=m[g],t=v[g];if(e&&t)return L(e,t,$,z,C)},[]),B(()=>{const e=m[g];e&&x[g](e.value)},[f.value]),B(()=>{const e=m[g],t=v[g];t&&e&&W(e,t,E,i)},[i]),o(()=>{if(null!=A&&null!=R&&h)if(T){const e=b(v[g],A,A+1).getBoundingClientRect();h({focused:!0,top:e.top,left:e.left,height:e.height,selectionStart:A,selectionEnd:R})}else h({focused:!1,selectionStart:A,selectionEnd:R})},[T,A,R]),o(()=>{const e=m[g];t&&e&&(e.style.height="auto",e.style.height=e.scrollHeight+"px")}),/* @__PURE__ */a("div",{style:s(()=>{let e=H,t=K;return i&&(w(i.width)&&(e=i.width),w(i.height)&&(t=i.height)),{display:"inline-block",position:"relative",width:e,height:t}},[H,K,i]),children:[/* @__PURE__ */d("div",{style:s(()=>{const e={position:"absolute",overflow:"hidden",top:0,left:0,width:H,height:K};return i?(["background","backgroundColor"].forEach(t=>{i[t]&&(e[t]=i[t])}),e):e},[H,K,i]),children:/* @__PURE__ */d(O,{u:v,p:x,h:e,m:_})}),/* @__PURE__ */d("input",{...f,ref:m,style:s(()=>({...i,background:"transparent",margin:0,position:"absolute",...!I&&{position:void 0,verticalAlign:"top"}}),[i,I]),onChange:n(e=>{x[g]?.(e.target.value),u?.(e)},[u]),onKeyDown:n(e=>{e.nativeEvent.isComposing||229===e.nativeEvent.keyCode||(p?.(e),$.t())},[p])})]})}),K=(e,t,n)=>{const o=[];let r=null;for(;r=e.exec(t);)n&&!n(t,r)||o.push(r);return o},I=e=>{const t=e.map(([,e])=>e);return n=>{const[o,r,i]=e.reduce((e,[t,o,r])=>(K(t,n,r).forEach(t=>{const n=t.index,r=t.index+t[0].length;e[0].add(n).add(r);let i=e[1].get(n),s=e[2].get(r);i||e[1].set(n,i=[]),s||e[2].set(r,s=[]),i.push(o),s.push(o)}),e),[ /* @__PURE__ */new Set, /* @__PURE__ */new Map, /* @__PURE__ */new Map]),s=Array.from(o);s.sort((e,t)=>e-t);let l=0;const c=[],u=[];for(let e=0;e<s.length;e++){const o=s[e],a=s[e+1]??n.length;if(o===a)continue;const p=n.slice(l,o);p&&u.push(p);const h=r.get(o),g=i.get(a);h&&(h.forEach(e=>{c.push(e)}),c.sort((e,n)=>t.indexOf(n)-t.indexOf(e)));const f=n.slice(o,a);u.push(c.reduceRight((e,t,n)=>{const r=0===n?o+"":void 0;return"function"==typeof t?t({children:e,value:f,key:r}):/* @__PURE__ */d("span",{style:t,children:e},r)},f)),g&&g.forEach(e=>{c.splice(c.indexOf(e),1)}),l=a}const a=n.slice(l);return a&&u.push(a),u}},F=e=>"rich-textarea-"+e,P=/*#__PURE__*/t(({v:e,_:t})=>{const n=l(null);return B(()=>{const o=n.current.firstChild,r=t.map(t=>new Highlight(...K(t,e).map(e=>{const t=e.index,n=e.index+e[0].length,r=new Range;return r.setStart(o,t),r.setEnd(o,n),r})));return r.forEach((e,t)=>{CSS.highlights.set(F(t),e)}),()=>{r.forEach((e,t)=>{CSS.highlights.delete(F(t)),e.clear()})}},[e]),/* @__PURE__ */d("div",{ref:n,children:e})}),N=e=>{const t=e.reduce((e,[,t],n)=>e+`::highlight(${F(n)}){${t}}`,""),n=e.map(([e])=>e);return e=>/* @__PURE__ */a(u,{children:[/* @__PURE__ */d(P,{v:e,_:n}),/* @__PURE__ */d("style",{children:t})]})};export{$ as RichTextarea,N as createCSSCustomHighlightRenderer,I as createRegexRenderer,H as experimental_RichInput}; //# sourceMappingURL=index.js.map