vue3-clamp
Version:
Clamping multiline text with ease.
2 lines (1 loc) • 4.3 kB
JavaScript
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("resize-detector"),require("vue")):"function"==typeof define&&define.amd?define(["resize-detector","vue"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).VueClamp=e(t.resizeDetector,t.Vue)}(this,(function(t,e){"use strict";return{name:"vue3-clamp",props:{tag:{type:String,default:"div"},autoresize:{type:Boolean,default:!1},maxLines:Number,maxHeight:[String,Number],ellipsis:{type:String,default:"…"},location:{type:String,default:"end",validator:function(t){return-1!==["start","middle","end"].indexOf(t)}},expanded:Boolean},data:function(){return{offset:null,text:this.getText(),localExpanded:!!this.expanded}},computed:{clampedText:function(){if("start"===this.location)return this.ellipsis+(this.text.slice(-this.offset)||"").trim();if("middle"===this.location){var t=Math.floor(this.offset/2);return(this.text.slice(0,t)||"").trim()+this.ellipsis+(this.text.slice(-t)||"").trim()}return(this.text.slice(0,this.offset)||"").trim()+this.ellipsis},isClamped:function(){return!!this.text&&this.offset!==this.text.length},realText:function(){return this.isClamped?this.clampedText:this.text},realMaxHeight:function(){if(this.localExpanded)return null;var t=this.maxHeight;return t?"number"==typeof t?t+"px":t:null}},watch:{expanded:function(t){this.localExpanded=t},localExpanded:function(t){t?this.clampAt(this.text.length):this.update(),this.expanded!==t&&this.$emit("update:expanded",t)},isClamped:{handler:function(t){var e=this;this.$nextTick((function(){return e.$emit("clampchange",t)}))},immediate:!0}},mounted:function(){this.init(),this.$watch((function(t){return[t.maxLines,t.maxHeight,t.ellipsis,t.isClamped,t.location].join()}),this.update),this.$watch((function(t){return[t.tag,t.text,t.autoresize].join()}),this.init)},updated:function(){this.text=this.getText(),this.applyChange()},beforeUnmount:function(){this.cleanUp()},methods:{init:function(){var e=this;this.$slots.default&&(this.offset=this.text.length,this.cleanUp(),this.autoresize&&(t.addListener(this.$el,this.update),this.unregisterResizeCallback=function(){t.removeListener(e.$el,e.update)}),this.update())},update:function(){this.localExpanded||(this.applyChange(),(this.isOverflow()||this.isClamped)&&this.search())},expand:function(){this.localExpanded=!0},collapse:function(){this.localExpanded=!1},toggle:function(){this.localExpanded=!this.localExpanded},getLines:function(){return Object.keys(Array.prototype.slice.call(this.$refs.content.getClientRects()).reduce((function(t,e){var i=e.top+"/"+e.bottom;return t[i]||(t[i]=!0),t}),{})).length},isOverflow:function(){return!(!this.maxLines&&!this.maxHeight)&&(!!(this.maxLines&&this.getLines()>this.maxLines)||!!(this.maxHeight&&this.$el.scrollHeight>this.$el.offsetHeight))},getText:function(){var t=(this.$slots.default()||[]).filter((function(t){return!t.tag&&!t.isComment}))[0];return t?t.children.trim():""},moveEdge:function(t){this.clampAt(this.offset+t)},clampAt:function(t){this.offset=t,this.applyChange()},applyChange:function(){this.$refs.text.textContent=this.realText},stepToFit:function(){this.fill(),this.clamp()},fill:function(){for(;(!this.isOverflow()||this.getLines()<2)&&this.offset<this.text.length;)this.moveEdge(1)},clamp:function(){for(;this.isOverflow()&&this.getLines()>1&&this.offset>0;)this.moveEdge(-1)},search:function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];var i=t[0];void 0===i&&(i=0);var s=t[1];if(void 0===s&&(s=this.offset),s-i<=3)this.stepToFit();else{var n=Math.floor((s+i)/2);this.clampAt(n),this.isOverflow()?this.search(i,n):this.search(n,s)}},cleanUp:function(){this.unregisterResizeCallback&&this.unregisterResizeCallback()}},render:function(){var t=[e.h("span",{ref:"text",attrs:{"aria-label":this.text.trim()}},this.realText)],i={expand:this.expand,collapse:this.collapse,toggle:this.toggle,clamped:this.isClamped,expanded:this.localExpanded},s=this.$slots.before;(s="function"==typeof s?s(i):s)&&t.unshift.apply(t,Array.isArray(s)?s:[s]);var n=this.$slots.after;(n="function"==typeof n?n(i):n)&&t.push.apply(t,Array.isArray(n)?n:[n]);var a=[e.h("span",{style:{boxShadow:"transparent 0 0"},ref:"content"},t)];return e.h(this.tag,{style:{maxHeight:this.realMaxHeight,overflow:"hidden"}},a)}}}));