UNPKG

vue3-text-clamp

Version:

Vue3 component which allows you to ellipsis your multiline text.

2 lines (1 loc) 3.62 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue"),require("resize-detector")):"function"==typeof define&&define.amd?define(["exports","vue","resize-detector"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["text-clamp"]={},e.Vue,e.resizeDetector)}(this,(function(e,t,l){"use strict";const a=["aria-label"];var n=t.defineComponent({__name:"text-clamp",props:{text:{type:String,required:!0},maxHeight:{type:[String,Number],required:!1},maxLines:{type:Number,required:!1},expanded:{type:Boolean,required:!1,default:!1},location:{type:String,required:!1,default:"end"},ellipsis:{type:String,required:!1,default:"…"},autoResize:{type:Boolean,required:!1,default:!1}},emits:["clamp-change","update:expanded"],setup(e,{emit:n}){const o=e,i=t.ref(null),r=t.ref(null),d=t.ref(null),s=t.reactive({offset:0,localExpanded:!!o.expanded,unregisterResizeCallback:null}),u=t.computed((()=>{if(!s.localExpanded&&o.maxHeight)return"number"==typeof o?.maxHeight?`${o?.maxHeight}px`:o?.maxHeight})),c=()=>{d.value&&(d.value.textContent=_.value)},f=()=>{s.localExpanded||(c(),(m()||H.value)&&h())},p=()=>{o.text&&(s.offset=o.text.length,x(),o.autoResize&&i.value&&(l.addListener(i.value,f),s.unregisterResizeCallback=()=>{i.value&&l.removeListener(i.value,f)}),f())},x=()=>{s.unregisterResizeCallback?.()},m=()=>!(!o.maxLines&&!o.maxHeight)&&(!!i.value&&(!!(o.maxLines&&g()>o.maxLines)||!!(o.maxHeight&&i.value.scrollHeight>i.value.offsetHeight))),g=()=>r.value?Object.keys(Array.prototype.slice.call(r.value.getClientRects()).reduce(((e,{top:t,bottom:l})=>{const a=`${t}/${l}`;return e[a]||(e[a]=!0),e}),{})).length:0,h=(...e)=>{const[t=0,l=s.offset]=e;if(l-t<=3)return void y();const a=Math.floor((l+t)/2);v(a),m()?h(t,a):h(a,l)},v=e=>{s.offset=e,c()},y=()=>{b(),E()},b=()=>{for(;(!m()||g()<2)&&s.offset<o.text.length;)k(1)},E=()=>{for(;m()&&g()>1&&s.offset>0;)k(-1)},k=e=>{v(s.offset+e)},H=t.computed((()=>!!o.text&&s.offset!==o.text.length));t.watch((()=>H.value),(e=>{setTimeout((()=>{n("clamp-change",e)}),0)}),{immediate:!0});const _=t.computed((()=>H.value?z.value:o.text)),z=t.computed((()=>{if("start"===o.location)return o.ellipsis+(o.text.slice(-s.offset)||"").trim();if("middle"===o.location){const e=Math.floor(s.offset/2);return(o.text.slice(0,e)||"").trim()+o.ellipsis+(o.text.slice(-e)||"").trim()}return(o.text.slice(0,s.offset)||"").trim()+o.ellipsis})),R=()=>{s.localExpanded=!0},q=()=>{s.localExpanded=!1},w=()=>{s.localExpanded=!s.localExpanded};return t.watch((()=>o.expanded),(e=>{s.localExpanded=e})),t.watch((()=>s.localExpanded),(e=>{e?v(o.text.length):f(),o.expanded!==e&&n("update:expanded",e)})),t.watch((()=>[o.maxLines,o.maxHeight,o.ellipsis,o.location,H.value].join()),(()=>{t.nextTick((()=>{f()}))})),t.watch((()=>[o.text,o.autoResize].join()),(()=>{t.nextTick((()=>{p()}))})),t.onUnmounted((()=>{x()})),t.onMounted((()=>{p()})),(l,n)=>(t.openBlock(),t.createElementBlock("div",{ref_key:"textClampRef",ref:i,class:"text-clamp",style:t.normalizeStyle({overflow:"hidden",maxHeight:t.unref(u)})},[t.createElementVNode("span",{ref_key:"contentRef",ref:r},[t.renderSlot(l.$slots,"before",{expand:R,collapse:q,toggle:w,clamped:t.unref(H),expanded:s.localExpanded}),t.createElementVNode("span",{ref_key:"textRef",ref:d,"aria-label":e.text},null,8,a),t.renderSlot(l.$slots,"after",{expand:R,collapse:q,toggle:w,clamped:t.unref(H),expanded:s.localExpanded})],512)],4))}});n.__file="package/text-clamp.vue";const o=e=>(e.install=function(t){t.component(e.__name,e)},e),i=o(n);e.default=i,e.withInstall=o,Object.defineProperty(e,"__esModule",{value:!0})}));