UNPKG

@re-dev/react-truncate

Version:

Provides `Truncate`, `MiddleTruncate` and `ShowMore` React components for truncating multi-line spans and adding an ellipsis.

15 lines (14 loc) 13.5 kB
/** * name: @re-dev/react-truncate * version: v0.6.0 * description: Provides `Truncate`, `MiddleTruncate` and `ShowMore` React components for truncating multi-line spans and adding an ellipsis. * author: chengpeiquan <chengpeiquan@chengpeiquan.com> * homepage: https://truncate.js.org * license: MIT */ "use strict";"use client";var ReactTruncate=(()=>{var de=Object.create;var D=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var he=Object.getPrototypeOf,xe=Object.prototype.hasOwnProperty;var Te=(n,t)=>()=>(t||n((t={exports:{}}).exports,t),t.exports),ye=(n,t)=>{for(var e in t)D(n,e,{get:t[e],enumerable:!0})},Y=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ge(t))!xe.call(n,o)&&o!==e&&D(n,o,{get:()=>t[o],enumerable:!(r=fe(t,o))||r.enumerable});return n};var F=(n,t,e)=>(e=n!=null?de(he(n)):{},Y(t||!n||!n.__esModule?D(e,"default",{value:n,enumerable:!0}):e,n)),be=n=>Y(D({},"__esModule",{value:!0}),n);var v=Te((Pe,Z)=>{"use strict";Z.exports=window.React});var He={};ye(He,{MiddleTruncate:()=>pe,ShowMore:()=>me,Truncate:()=>z});var p=F(v(),1);var C=F(v(),1),Me=n=>n==="class"?"className":n,Se=n=>n.split(";").map(t=>t.trim()).filter(Boolean).reduce((t,e)=>{let[r,...o]=e.split(":"),i=r?.trim(),s=o.join(":").trim();if(!i||!s)return t;let u=i.replace(/-([a-z])/g,(k,a)=>a.toUpperCase());return t[u]=s,t},{}),ke=n=>Object.entries(n).reduce((t,[e,r])=>{let o=Me(e);return t[o]=o==="style"?Se(r):r,t},{}),V=(n,t="markup")=>n.reduce((e,r,o)=>{let i=`${t}-${o}`;if(r.type==="text")return r.text&&e.push(r.text),e;if(r.type==="line-break")return e.push(C.default.createElement("br",{key:i})),e;let s=V(r.children,`${i}-child`);return s.length===0||e.push(C.default.createElement(r.tagName,{key:i,...ke(r.attributes)},...s)),e},[]),Ee=(n,t)=>{if(t<=0)return{taken:[],rest:[n],remaining:t};if(n.type==="text")return n.text.length<=t?{taken:[n],rest:[],remaining:t-n.text.length}:{taken:[{...n,text:n.text.slice(0,t)}],rest:[{...n,text:n.text.slice(t)}],remaining:0};if(n.type==="line-break")return t>=1?{taken:[n],rest:[],remaining:t-1}:{taken:[],rest:[n],remaining:t};let e=_(n.children,t);return{taken:e.taken.length?[{...n,children:e.taken}]:[],rest:e.rest.length?[{...n,children:e.rest}]:[],remaining:e.remaining}},_=(n,t)=>{let e=[],r=[],o=t;return n.forEach(i=>{if(o<=0){r.push(i);return}let s=Ee(i,o);e.push(...s.taken),r.push(...s.rest),o=s.remaining}),{taken:e,rest:r,remaining:o}},O=n=>{if(n.length===0)return n;let[t,...e]=n;if(t.type==="text"){let r=t.text.replace(/^\s+/,"");return r?[{...t,text:r},...e]:O(e)}if(t.type==="element"){let r=O(t.children);return r.length===0?O(e):[{...t,children:r},...e]}return n},W=n=>{if(n.length===0)return n;let t=n.slice(0,-1),e=n.at(-1);if(!e)return n;if(e.type==="line-break")return W(t);if(e.type==="text"){let o=e.text.replace(/\s+$/,"");return o?[...t,{...e,text:o}]:W(t)}let r=W(e.children);return r.length===0?W(t):[...t,{...e,children:r}]},I=n=>n.reduce((t,e)=>e.type==="text"?t+e.text.length:e.type==="line-break"?t+1:t+I(e.children),0),ee=(n,t,e)=>{let r=n;return t.map((o,i)=>{let s=_(r,o.length);r=O(s.rest);let u=V(s.taken,`markup-line-${i}`);return i===t.length-1?C.default.createElement("span",{key:`markup-line-${i}`},u,e):u.length===0?C.default.createElement("br",{key:`markup-line-${i}`}):C.default.createElement(C.default.Fragment,{key:`markup-line-${i}`},u,C.default.createElement("br",null))})},te=(n,t,e,r=!1)=>{let o=_(n,t),i=r?W(o.taken):o.taken;return[...V(i,"markup-prefix"),C.default.createElement(C.default.Fragment,{key:"markup-ellipsis"},e)]};var Ne=(n,t)=>n.replace(/\r\n|\r|\n/g,t),we=n=>Array.from(n.attributes).reduce((t,e)=>(t[e.name]=e.value,t),{}),J=(n,t)=>n?Array.from(n.childNodes).flatMap(e=>{if(e instanceof HTMLBRElement)return[{type:"line-break"}];if(e.nodeType===Node.TEXT_NODE){let r=Ne(e.textContent||"",t);return r?[{type:"text",text:r}]:[]}if(e.nodeType===Node.ELEMENT_NODE){let r=e;return[{type:"element",tagName:r.tagName.toLowerCase(),attributes:we(r),children:J(r,t)}]}return[]}):[];var Le=(n,t)=>n.replace(/\r\n|\r|\n/g,t),X=n=>{let t=Number.parseFloat(n);return Number.isFinite(t)?t:0},Re=(n,t)=>{let e=n?.parentElement;if(!e)return t;let r=e.getBoundingClientRect().width,o=window.getComputedStyle(e),i=X(o.paddingLeft)+X(o.paddingRight),s=X(o.borderLeftWidth)+X(o.borderRightWidth),u=Math.floor(r-i-s);return u>0?u:t},Ce=(n,t)=>{let e=document.createElement("span"),r=n?window.getComputedStyle(n):null;return e.setAttribute("aria-hidden","true"),e.style.position="fixed",e.style.top="0",e.style.left="0",e.style.visibility="hidden",e.style.pointerEvents="none",e.style.display="block",e.style.margin="0",e.style.padding="0",e.style.border="0",e.style.boxSizing="content-box",e.style.width=`${Math.max(t,1)}px`,e.style.whiteSpace=r?.whiteSpace||"normal",e.style.wordBreak=r?.wordBreak||"normal",e.style.overflowWrap=r?.overflowWrap||"break-word",e.style.font=r?.font||"",e.style.fontFamily=r?.fontFamily||"",e.style.fontSize=r?.fontSize||"",e.style.fontStyle=r?.fontStyle||"",e.style.fontWeight=r?.fontWeight||"",e.style.letterSpacing=r?.letterSpacing||"",e.style.lineHeight=r?.lineHeight||"",e.style.wordSpacing=r?.wordSpacing||"",e.style.textTransform=r?.textTransform||"",e.style.textIndent=r?.textIndent||"",e.style.direction=r?.direction||"",e},ve=(n,t)=>{t&&Array.from(t.childNodes).forEach(e=>{n.appendChild(e.cloneNode(!0))})},re=n=>{let t=Array.from(n.childNodes);for(let e=t.length-1;e>=0;e-=1){let r=t[e];if(r instanceof HTMLBRElement){r.remove();continue}if(r.nodeType===Node.TEXT_NODE){let o=(r.textContent||"").replace(/\s+$/,"");if(!o){r.remove();continue}r.textContent=o;return}if(r.nodeType===Node.ELEMENT_NODE){if(re(r),r.childNodes.length===0){r.remove();continue}return}r.remove()}},oe=(n,t,e)=>{let r=Array.from(n.childNodes),o=t;return r.forEach(i=>{if(o<=0){i.remove();return}if(i instanceof HTMLBRElement){o-=1;return}if(i.nodeType===Node.TEXT_NODE){let s=Le(i.textContent||"",e);if(s.length<=o){i.textContent=s,o-=s.length;return}i.textContent=s.slice(0,o),o=0;return}if(i.nodeType===Node.ELEMENT_NODE){o=oe(i,o,e),i.childNodes.length===0&&i.remove();return}i.remove()}),o},ne=({ellipsisNode:n,node:t,separator:e,trimWhitespace:r,visibleLength:o})=>{let i=document.createDocumentFragment(),s=t.cloneNode(!0);return typeof o=="number"&&(oe(s,o,e),r&&re(s)),Array.from(s.childNodes).forEach(u=>{i.appendChild(u)}),typeof o=="number"&&ve(i,n),i},q=(n,t)=>(n.replaceChildren(t),n.getBoundingClientRect().height),ie=({ellipsis:n,ellipsisNode:t,fallbackDidTruncate:e,fallbackVisibleTextLines:r,lines:o,node:i,rootNode:s,separator:u,trimWhitespace:k})=>{if(!i)return{didTruncate:!1,result:null};let a=J(i,u),E=I(a),l={didTruncate:e,result:e?ee(a,r,n):null};if(E===0)return{didTruncate:!1,result:null};let M=Ce(s,Re(s,s?.parentElement?.getBoundingClientRect().width||0));document.body.appendChild(M);try{let x=document.createDocumentFragment();x.appendChild(document.createTextNode("A"));let g=q(M,x);if(g===0)return l;let c=Math.max(g,1)*o+.5,h=q(M,ne({ellipsisNode:t,node:i,separator:u,trimWhitespace:k}));if(h===0)return l;if(h<=c)return{didTruncate:!1,result:null};let T=0,f=E,m=0;for(;T<=f;){let y=Math.floor((T+f)/2);q(M,ne({ellipsisNode:t,node:i,separator:u,trimWhitespace:k,visibleLength:y}))<=c?(m=y,T=y+1):f=y-1}return{didTruncate:!0,result:te(a,m,n,k)}}finally{M.remove()}};var U=F(v(),1);var j=F(v(),1),se=n=>n?.offsetWidth,G=n=>n.replace(/\s+$/,""),le=(n,t,e)=>{if(t===e.length-1)return j.default.createElement("span",{key:t},n);{let r=j.default.createElement("br",{key:`${t}br`});return n?[j.default.createElement("span",{key:t},n),r]:r}},ae=(n,t)=>{let e=document.createElement("div"),r="innerText"in window.HTMLElement.prototype?"innerText":"textContent";e.innerHTML=n?.innerHTML.replace(/\r\n|\r|\n/g,t)||"";let o=e[r],i=document.createElement("div");return i.innerHTML="foo<br/>bar",i[r]?.replace(/\r\n|\r/g,` `)!==`foo bar`&&(e.innerHTML=e.innerHTML.replace(/<br.*?[/]?>/gi,` `),o=e[r]),o||""},ce=({end:n,lastLineText:t,fullText:e,targetWidth:r,ellipsisWidth:o,measureWidth:i})=>{let s=t.length,u=Math.abs(n),k=u>s?0:s-u,a=t.slice(0,k),E=k===0?-s:n,l=e.slice(E),M=(g,d)=>Math.floor(i(g)+i(d)+o),x=M(a,l);if(x<r){for(;a.length<s&&a.length+l.length<e.length&&x<r;){let g=t[a.length],d=a+g,c=M(d,l);if(c<=r)a=d,x=c;else break}for(;l.length<e.length&&a.length+l.length<e.length&&x<r;){let d=e[e.length-l.length-1]+l,c=M(a,d);if(c<=r)l=d,x=c;else break}}for(;x>r&&(a.length>0||l.length>0);){let g=i(a),d=i(l),c=g+d,h=g/c,T=d/c;a.length>0&&l.length>0?h>=T?a=a.slice(0,a.length-1):l=l.slice(1):a.length>0?a=a.slice(0,a.length-1):l.length>0&&(l=l.slice(1)),x=M(a,l)}if(x<r){let g=r-x,d=a.length+l.length<e.length,c=d&&k>0?t[a.length]:null,h=d?e[e.length-l.length-1]:null;c&&i(c)<=g?a+=c:h&&i(h)<=g&&(l=h+l)}return{startFragment:a,endFragment:l}};var ue=({ellipsis:n,ellipsisRef:t,end:e,lines:r,measureWidth:o,middleTruncate:i,separator:s,targetWidth:u,textRef:k,trimWhitespace:a})=>{let E=[],l=[],M=ae(k,s),x=M.split(` `).map(c=>c.split(s)),g=se(t)||0,d=!0;for(let c=1;c<=r;c++){let h=x[0];if(h.length===0){E.push(),l.push(""),x.shift(),c--;continue}let T=h.join(s)||"",f=typeof T=="string"?T:"";if(o(f)<=u&&x.length===1){d=!1,E.push(T),l.push(f);break}if(c===r){let m=h.join(s),y=0,b=m.length-1;for(;y<=b;){let L=Math.floor((y+b)/2),H=m.slice(0,L+1);o(H)+g<=u?y=L+1:b=L-1}let N=m.slice(0,y);if(a)for(N=G(N);!N.length&&E.length;){let L=E.pop();l.pop(),L&&typeof L=="string"&&(N=G(L))}if(i&&e!==0){let{startFragment:L,endFragment:H}=ce({end:e,lastLineText:N,fullText:M,targetWidth:u,ellipsisWidth:g,measureWidth:o});f=`${L}${H}`,T=U.default.createElement("span",null,L,n,H)}else f=N,T=U.default.createElement("span",null,N,n)}else{let m=0,y=h.length-1;for(;m<=y;){let b=Math.floor((m+y)/2),N=h.slice(0,b+1).join(s);o(N)<=u?m=b+1:y=b-1}if(m===0){c=r-1;continue}f=h.slice(0,m).join(s),T=f,x[0].splice(0,m)}E.push(T),l.push(f)}return{didTruncate:d,resultLines:E,visibleText:l.join(` `),visibleTextLines:l}};var z=({children:n,ellipsis:t="\u2026",lines:e=1,trimWhitespace:r=!1,width:o=0,separator:i=" ",middle:s=!1,end:u=5,preserveMarkup:k=!1,onTruncate:a,...E})=>{let[l,M]=(0,p.useState)(),[x,g]=(0,p.useState)(),[d,c]=(0,p.useState)(0),[h,T]=(0,p.useState)(0),f=(0,p.useRef)(null),m=(0,p.useRef)(null),y=(0,p.useRef)(null);(0,p.useEffect)(()=>{m&&m.current&&m.current.parentNode&&m.current.parentNode.removeChild(m.current)},[d]);let b=(0,p.useCallback)(()=>{if(!f.current?.parentElement)return;let R=o||Math.floor(f.current.parentElement.getBoundingClientRect().width);if(!R)return window.requestAnimationFrame(()=>b());let w=window.getComputedStyle(f.current),A=[w.fontWeight,w.fontStyle,w.fontSize,w.fontFamily].join(" ");l&&(l.font=A,l.letterSpacing=w.letterSpacing),c(R)},[l,o]);(0,p.useEffect)(()=>{let R=document.createElement("canvas");M(R.getContext("2d"))},[]),(0,p.useEffect)(()=>(b(),window.addEventListener("resize",b),()=>{window.removeEventListener("resize",b),window.cancelAnimationFrame(h)}),[b,h]);let N=(0,p.useCallback)(R=>{typeof a=="function"&&T(window.requestAnimationFrame(()=>{a(R)}))},[a]),L=(0,p.useCallback)(R=>l?.measureText(R).width||0,[l]),H=(0,p.useMemo)(()=>!Number.isSafeInteger(e)||e<0?0:e,[e]),$=(0,p.useMemo)(()=>s?1:H,[H,s]),Q=(0,p.useMemo)(()=>{let R=Math.abs(u),w=Number.isFinite(R)?Math.floor(R):0;return w>0?-w:w},[u]);return(0,p.useEffect)(()=>{let R=!!(f.current&&d);if(typeof window>"u"||!R)return;if($<=0){g(n),N(!1);return}let w=ue({ellipsis:t,ellipsisRef:y.current,end:Q,lines:$,measureWidth:L,middleTruncate:s,separator:i,targetWidth:d,textRef:m.current,trimWhitespace:r});if(k&&!s){let A=ie({fallbackDidTruncate:w.didTruncate,fallbackVisibleTextLines:w.visibleTextLines,ellipsis:t,ellipsisNode:y.current,lines:$,node:m.current,rootNode:f.current,separator:i,trimWhitespace:r});g(A.didTruncate?A.result:n),N(A.didTruncate);return}g(w.resultLines.map(le)),N(w.didTruncate)},[n,t,Q,$,L,s,k,i,d,r,N]),p.default.createElement("span",{...E,ref:f},p.default.createElement("span",null,x),p.default.createElement("span",{ref:m},n),p.default.createElement("span",{ref:y,style:{position:"fixed",visibility:"hidden",top:0,left:0}},t))};var B=F(v(),1);var pe=(0,B.forwardRef)(({children:n,...t},e)=>{let{width:r,middle:o,lines:i,...s}=t;return B.default.createElement("div",{ref:e,style:{width:"100%"}},B.default.createElement(z,{...s,middle:!0},n))});pe.displayName="MiddleTruncate";var S=F(v(),1);var P=F(v(),1),K=({type:n,label:t,className:e,toggleLines:r})=>{let o=(0,P.useMemo)(()=>n==="more"?"\u2026 ":" ",[n]);return(0,P.isValidElement)(t)?t:P.default.createElement("span",null,o,P.default.createElement("a",{href:"#",className:e,onClick:r,"data-testid":`${n}-button`},t))};var me=(0,S.forwardRef)(({defaultExpanded:n=!1,expanded:t,lines:e=3,more:r="Expand",less:o="Collapse",anchorClass:i,onToggle:s,children:u,...k},a)=>{let{width:E,middle:l,end:M,ellipsis:x,...g}=k,[,d]=(0,S.useState)({}),c=(0,S.useCallback)(()=>d({}),[]),h=(0,S.useRef)(n),T=typeof t=="boolean",f=T?t:h.current,m=(0,S.useCallback)(y=>{y.preventDefault();let b=!f;T||(h.current=b,c()),s?.(b)},[f,T,s,c]);return(0,S.useImperativeHandle)(a,()=>({toggleLines:m})),S.default.createElement("div",{style:{width:"100%"}},S.default.createElement(z,{...g,lines:f?0:e,ellipsis:S.default.createElement(K,{type:"more",label:r,className:i,toggleLines:m})},u),f&&S.default.createElement(K,{type:"less",label:o,className:i,toggleLines:m}))});me.displayName="ShowMore";return be(He);})();