@ohkit/text-ellipsis 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,2 +1,2 @@
1
- import t,{forwardRef as e,useState as n,useRef as o,useMemo as i,useCallback as l,useEffect as r}from"react";import{prefixClassname as a,useSyncPropsState as d,useRuntime as s,classNames as f,useCompatibleEffect as c,isSafari as u,assignRef as h}from"@ohkit/utils";import{Measure as v}from"@ohkit/measure";function p(){return p=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)({}).hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t},p.apply(null,arguments)}var g=a("ohkit-text-ellipsis__"),m=e(function(e,a){var m=e.className,C=e.style,x=e.lineHeight,w=void 0===x?"":x,F=e.lines,H=e.maskBgColor,b=void 0===H?"#fff":H,E=e.resetFoldWhenChildrenOrEllipsisChange,y=void 0!==E&&E,O=e.showTitleWhenFold,k=e.titleWhenFold,M=e.showFoldControl,W=void 0===M||M,B=e.foldText,S=void 0===B?"收起":B,L=e.unfoldText,N=void 0===L?"展开":L,P=e.uiType,T=void 0===P?"right":P,R=e.truncateMode,j=void 0===R?"line":R,q=e.maxHeight,z=e.controlPlacement,A=void 0===z?"center":z,_=e.whiteSpace,V=e.width,D=e.renderFoldButton,G=e.onEllipsisChange,I=e.onFoldChange,J=e.onStatusChange,K=e.onMouseEnter,Q=e.onMouseLeave,U=e.onPointerEnter,X=e.onPointerLeave,Y=e.onClick,Z=e.onFocus,$=e.content||e.children,tt=n(!1),et=tt[0],nt=tt[1],ot=n(!1),it=ot[0],lt=ot[1],rt=d(e,"fold",{defaultValue:!0,onChange:I}),at=rt[0],dt=rt[1],st=n(1),ft=st[0],ct=st[1],ut=n("string"==typeof w&&w.endsWith("px")?parseFloat(w):0),ht=ut[0],vt=ut[1],pt=n(F),gt=pt[0],mt=void 0===gt?0:gt,Ct=pt[1],xt=n(""),wt=xt[0],Ft=xt[1],Ht=s({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:et,defaultFold:at,fold:at,foldBtnWidth:ft,textContent:wt,onEllipsisChange:G,onFoldChange:I},["onEllipsisChange","fold","onFoldChange"])[0],bt=o(null),Et=o(null),yt=o(null),Ot=o(null),kt=i(function(){return p({lineHeight:it?"1.4":w||void 0},C)},[C,w,it]),Mt=i(function(){return{whiteSpace:_,width:V}},[_,V]),Wt=i(function(){var t="height"===j;if(!et||!(t||mt&&ht))return Mt;var e=!W||"bottom"!==T&&at?void 0:ht+"px";return p({},Mt,{minHeight:!t&&at?(mt-.2)*ht+"px":void 0,WebkitLineClamp:t?void 0:at?mt:void 0,maxHeight:t&&at?q||mt*ht||Ht.containerContentHeight||0:void 0,paddingBottom:e,boxSizing:e?"border-box":void 0})},[mt,ht,et,at,W,T,j,q,Mt]),Bt=i(function(){if(at){var t=ht,e="right"===T?Math.min(t/ft*100,80):60;return{boxSizing:"content-box",height:ht+"px",lineHeight:ht+"px",paddingTop:"bottom"===T?t+"px":void 0,paddingLeft:"right"===T?t+"px":void 0,background:"linear-gradient(to "+T+", "+b+(4===b.length?"0":"00")+", "+b+" "+e+"%, "+b+" 100%)"}}},[ht,b,at,T,ft]),St=l(function(){if(bt.current){var t=bt.current.style.width,e=window.getComputedStyle(bt.current).width;bt.current.style.width=parseFloat(e)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(function(){bt.current&&(bt.current.style.width=t)})}},[]),Lt=l(function(t,e){void 0===e&&(e=!Ht.fold),Ht.fold=e,dt(e)},[]),Nt=i(function(){/*#__PURE__*/return t.createElement("div",{className:f("btn-fold-wrapper","btn-fold-wrapper-"+T,"bottom"===T&&"placement-"+A),style:Bt,ref:Ot,onClick:Lt},D?D(at):/*#__PURE__*/t.createElement("div",{className:"btn-fold"},at?N:S))},[Bt,at,S,Lt,D,A,T,N]),Pt=l(function(t,e){void 0===t&&(t=Ht.ellipsis);var n=(void 0===e?{}:e).forceResetFold,o=void 0!==n&&n,i=Ht.ellipsis,l=Ht.fold,r=Ht.defaultFold;t!==i&&(nt(t),Ht.ellipsis=t,null==Ht.onEllipsisChange||Ht.onEllipsisChange(t)),y&&(o||!i&&t)&&l!==r&&Lt(void 0,r)},[Lt,$,y]),Tt=l(function(){var t=Et.current,e=yt.current;if(t&&e){Ht.contentOffsetHeight=t.offsetHeight;var n=window.getComputedStyle(e),o=parseFloat(n.paddingTop),i=parseFloat(n.paddingBottom),l=Ht.containerContentHeight=e.clientHeight-o-i,r=0;if(!r&&t){var a=(n||{}).lineHeight;a&&((r=parseFloat(a))||lt(!0))}if(ht===r||(vt(r),r))if("height"===j)Pt(Ht.contentOffsetHeight>(q||l));else if(F)mt!==F&&Ct(F),Pt(Ht.contentOffsetHeight>=(F+1)*Math.floor(r)-1);else if(Ht.contentOffsetHeight>l){var d=Math.floor(l/r)||1;mt!==d&&Ct(d),Pt(!0)}else Pt(!1)}},[F,ht,j,q,Pt]);c(function(){Pt(Ht.ellipsis,{forceResetFold:!0}),Tt()},[Tt,Pt]),r(function(){if(et&&Ot.current){var t=Ot.current.offsetWidth;t!==Ht.foldBtnWidth&&(Ht.foldBtnWidth=t,ct(t))}},[et,N,W]),r(function(){u&&St()},[at,St]);var Rt=l(function(){var t,e=(null==(t=Et.current)?void 0:t.textContent)||"";e!==Ht.textContent&&(Ht.textContent=e,Ft(e))},[]),jt=i(function(){return et&&at?"function"==typeof k?k(wt):k||wt:void 0},[k,et,at,wt]);return r(function(){Ht.inited&&(null==J||J({ellipsis:et,fold:at,title:jt}))},[J,at,et,jt]),r(function(){Ht.inited=!0},[]),/*#__PURE__*/t.createElement("div",{className:f(g("container"),m),style:kt,ref:function(t){h(yt,t),a&&h(a,t)},onMouseEnter:K,onMouseLeave:Q,onPointerEnter:U,onPointerLeave:X,onClick:Y,onFocus:Z},/*#__PURE__*/t.createElement(v,{offset:!0},function(e){var n=e.measureRef,o=(e.contentRect.offset||{}).height;return void 0!==o&&Math.abs(o-Ht.contentOffsetHeight)>1&&Tt(),/*#__PURE__*/t.createElement("div",{style:Mt,className:"content-shadow-dom",ref:function(t){h(n,t),h(Et,t),Rt()}},$)}),/*#__PURE__*/t.createElement("div",{className:"text-ellipsis-inner",title:O?jt:void 0,style:Wt,ref:bt},et&&W&&Nt,$))});export{m as TextEllipsis,g as c};
1
+ import t,{forwardRef as e,useState as n,useRef as o,useMemo as i,useCallback as r,useEffect as l}from"react";import{prefixClassname as a,classNames as d}from"@ohkit/prefix-classname";import{useSyncPropsState as f,useRuntime as s,useCompatibleEffect as c,assignRef as u}from"@ohkit/react-helper";import{isSafari as h}from"@ohkit/platform";import{Measure as p}from"@ohkit/measure";function v(){return v=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)({}).hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t},v.apply(null,arguments)}var g=a("ohkit-text-ellipsis__"),m=e(function(e,a){var m=e.className,C=e.style,x=e.lineHeight,w=void 0===x?"":x,F=e.lines,H=e.maskBgColor,b=void 0===H?"#fff":H,E=e.resetFoldWhenChildrenOrEllipsisChange,y=void 0!==E&&E,k=e.showTitleWhenFold,O=e.titleWhenFold,M=e.showFoldControl,W=void 0===M||M,B=e.foldText,S=void 0===B?"收起":B,L=e.unfoldText,N=void 0===L?"展开":L,P=e.uiType,T=void 0===P?"right":P,R=e.truncateMode,j=void 0===R?"line":R,q=e.maxHeight,z=e.controlPlacement,A=void 0===z?"center":z,_=e.whiteSpace,V=e.width,D=e.renderFoldButton,G=e.onEllipsisChange,I=e.onFoldChange,J=e.onStatusChange,K=e.onMouseEnter,Q=e.onMouseLeave,U=e.onPointerEnter,X=e.onPointerLeave,Y=e.onClick,Z=e.onFocus,$=e.content||e.children,tt=n(!1),et=tt[0],nt=tt[1],ot=n(!1),it=ot[0],rt=ot[1],lt=f(e,"fold",{defaultValue:!0,onChange:I}),at=lt[0],dt=lt[1],ft=n(1),st=ft[0],ct=ft[1],ut=n("string"==typeof w&&w.endsWith("px")?parseFloat(w):0),ht=ut[0],pt=ut[1],vt=n(F),gt=vt[0],mt=void 0===gt?0:gt,Ct=vt[1],xt=n(""),wt=xt[0],Ft=xt[1],Ht=s({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:et,defaultFold:at,fold:at,foldBtnWidth:st,textContent:wt,onEllipsisChange:G,onFoldChange:I},["onEllipsisChange","fold","onFoldChange"])[0],bt=o(null),Et=o(null),yt=o(null),kt=o(null),Ot=i(function(){return v({lineHeight:it?"1.4":w||void 0},C)},[C,w,it]),Mt=i(function(){return{whiteSpace:_,width:V}},[_,V]),Wt=i(function(){var t="height"===j;if(!et||!(t||mt&&ht))return Mt;var e=!W||"bottom"!==T&&at?void 0:ht+"px";return v({},Mt,{minHeight:!t&&at?(mt-.2)*ht+"px":void 0,WebkitLineClamp:t?void 0:at?mt:void 0,maxHeight:t&&at?q||mt*ht||Ht.containerContentHeight||0:void 0,paddingBottom:e,boxSizing:e?"border-box":void 0})},[mt,ht,et,at,W,T,j,q,Mt]),Bt=i(function(){if(at){var t=ht,e="right"===T?Math.min(t/st*100,80):60;return{boxSizing:"content-box",height:ht+"px",lineHeight:ht+"px",paddingTop:"bottom"===T?t+"px":void 0,paddingLeft:"right"===T?t+"px":void 0,background:"linear-gradient(to "+T+", "+b+(4===b.length?"0":"00")+", "+b+" "+e+"%, "+b+" 100%)"}}},[ht,b,at,T,st]),St=r(function(){if(bt.current){var t=bt.current.style.width,e=window.getComputedStyle(bt.current).width;bt.current.style.width=parseFloat(e)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(function(){bt.current&&(bt.current.style.width=t)})}},[]),Lt=r(function(t,e){void 0===e&&(e=!Ht.fold),Ht.fold=e,dt(e)},[]),Nt=i(function(){/*#__PURE__*/return t.createElement("div",{className:d("btn-fold-wrapper","btn-fold-wrapper-"+T,"bottom"===T&&"placement-"+A),style:Bt,ref:kt,onClick:Lt},D?D(at):/*#__PURE__*/t.createElement("div",{className:"btn-fold"},at?N:S))},[Bt,at,S,Lt,D,A,T,N]),Pt=r(function(t,e){void 0===t&&(t=Ht.ellipsis);var n=(void 0===e?{}:e).forceResetFold,o=void 0!==n&&n,i=Ht.ellipsis,r=Ht.fold,l=Ht.defaultFold;t!==i&&(nt(t),Ht.ellipsis=t,null==Ht.onEllipsisChange||Ht.onEllipsisChange(t)),y&&(o||!i&&t)&&r!==l&&Lt(void 0,l)},[Lt,$,y]),Tt=r(function(){var t=Et.current,e=yt.current;if(t&&e){Ht.contentOffsetHeight=t.offsetHeight;var n=window.getComputedStyle(e),o=parseFloat(n.paddingTop),i=parseFloat(n.paddingBottom),r=Ht.containerContentHeight=e.clientHeight-o-i,l=0;if(!l&&t){var a=(n||{}).lineHeight;a&&((l=parseFloat(a))||rt(!0))}if(ht===l||(pt(l),l))if("height"===j)Pt(Ht.contentOffsetHeight>(q||r));else if(F)mt!==F&&Ct(F),Pt(Ht.contentOffsetHeight>=(F+1)*Math.floor(l)-1);else if(Ht.contentOffsetHeight>r){var d=Math.floor(r/l)||1;mt!==d&&Ct(d),Pt(!0)}else Pt(!1)}},[F,ht,j,q,Pt]);c(function(){Pt(Ht.ellipsis,{forceResetFold:!0}),Tt()},[Tt,Pt]),l(function(){if(et&&kt.current){var t=kt.current.offsetWidth;t!==Ht.foldBtnWidth&&(Ht.foldBtnWidth=t,ct(t))}},[et,N,W]),l(function(){h&&St()},[at,St]);var Rt=r(function(){var t,e=(null==(t=Et.current)?void 0:t.textContent)||"";e!==Ht.textContent&&(Ht.textContent=e,Ft(e))},[]),jt=i(function(){return et&&at?"function"==typeof O?O(wt):O||wt:void 0},[O,et,at,wt]);return l(function(){Ht.inited&&(null==J||J({ellipsis:et,fold:at,title:jt}))},[J,at,et,jt]),l(function(){Ht.inited=!0},[]),/*#__PURE__*/t.createElement("div",{className:d(g("container"),m),style:Ot,ref:function(t){u(yt,t),a&&u(a,t)},onMouseEnter:K,onMouseLeave:Q,onPointerEnter:U,onPointerLeave:X,onClick:Y,onFocus:Z},/*#__PURE__*/t.createElement(p,{offset:!0},function(e){var n=e.measureRef,o=(e.contentRect.offset||{}).height;return void 0!==o&&Math.abs(o-Ht.contentOffsetHeight)>1&&Tt(),/*#__PURE__*/t.createElement("div",{style:Mt,className:"content-shadow-dom",ref:function(t){u(n,t),u(Et,t),Rt()}},$)}),/*#__PURE__*/t.createElement("div",{className:"text-ellipsis-inner",title:k?jt:void 0,style:Wt,ref:bt},et&&W&&Nt,$))});export{m as TextEllipsis,g as c};
2
2
  //# sourceMappingURL=index.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n isSafari,\n prefixClassname as p,\n classNames as cx,\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/utils\";\nimport { Measure } from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","TextEllipsis","forwardRef","props","ref","className","style","_props$lineHeight","lineHeight","lines","_props$maskBgColor","maskBgColor","_props$resetFoldWhenC","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","_props$showFoldContro","showFoldControl","_props$foldText","foldText","_props$unfoldText","unfoldText","_props$uiType","uiType","_props$truncateMode","truncateMode","maxHeight","_props$controlPlaceme","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","content","children","_useState","useState","ellipsis","setEllipsis","_useState2","getLineHeightFail","setGetLineHeightFail","_useSyncPropsState","useSyncPropsState","defaultValue","onChange","fold","setFold","_useState3","foldBtnWidth","setFoldBtnWidth","_useState4","endsWith","parseFloat","innerLineHeight","setInnerLineHeight","_useState5","_useState5$","innerLines","setInnerLines","_useState6","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","resetState","newEllipsis","_temp","_ref","_ref$forceResetFold","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","_ref3","measureRef","contentRect","abs"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n prefixClassname as p,\n classNames as cx,\n} from \"@ohkit/prefix-classname\";\nimport {\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/react-helper\";\nimport {isSafari} from \"@ohkit/platform\";\nimport {Measure} from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","TextEllipsis","forwardRef","props","ref","className","style","_props$lineHeight","lineHeight","lines","_props$maskBgColor","maskBgColor","_props$resetFoldWhenC","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","_props$showFoldContro","showFoldControl","_props$foldText","foldText","_props$unfoldText","unfoldText","_props$uiType","uiType","_props$truncateMode","truncateMode","maxHeight","_props$controlPlaceme","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","content","children","_useState","useState","ellipsis","setEllipsis","_useState2","getLineHeightFail","setGetLineHeightFail","_useSyncPropsState","useSyncPropsState","defaultValue","onChange","fold","setFold","_useState3","foldBtnWidth","setFoldBtnWidth","_useState4","endsWith","parseFloat","innerLineHeight","setInnerLineHeight","_useState5","_useState5$","innerLines","setInnerLines","_useState6","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","transparent","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","resetState","newEllipsis","_temp","_ref$forceResetFold","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","_ref3","measureRef","contentRect","abs"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var e=require("react"),t=require("@ohkit/utils"),n=require("@ohkit/measure");function i(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=/*#__PURE__*/i(e);function l(){return l=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)({}).hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},l.apply(null,arguments)}var a=t.prefixClassname("ohkit-text-ellipsis__"),r=e.forwardRef(function(i,r){var s=i.className,f=i.style,u=i.lineHeight,d=void 0===u?"":u,c=i.lines,h=i.maskBgColor,g=void 0===h?"#fff":h,p=i.resetFoldWhenChildrenOrEllipsisChange,v=void 0!==p&&p,m=i.showTitleWhenFold,C=i.titleWhenFold,x=i.showFoldControl,b=void 0===x||x,w=i.foldText,E=void 0===w?"收起":w,F=i.unfoldText,H=void 0===F?"展开":F,y=i.uiType,M=void 0===y?"right":y,S=i.truncateMode,k=void 0===S?"line":S,R=i.maxHeight,O=i.controlPlacement,W=void 0===O?"center":O,N=i.whiteSpace,B=i.width,P=i.renderFoldButton,T=i.onEllipsisChange,L=i.onFoldChange,q=i.onStatusChange,j=i.onMouseEnter,z=i.onMouseLeave,A=i.onPointerEnter,_=i.onPointerLeave,V=i.onClick,D=i.onFocus,G=i.content||i.children,I=e.useState(!1),J=I[0],K=I[1],Q=e.useState(!1),U=Q[0],X=Q[1],Y=t.useSyncPropsState(i,"fold",{defaultValue:!0,onChange:L}),Z=Y[0],$=Y[1],ee=e.useState(1),te=ee[0],ne=ee[1],ie=e.useState("string"==typeof d&&d.endsWith("px")?parseFloat(d):0),oe=ie[0],le=ie[1],ae=e.useState(c),re=ae[0],se=void 0===re?0:re,fe=ae[1],ue=e.useState(""),de=ue[0],ce=ue[1],he=t.useRuntime({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:J,defaultFold:Z,fold:Z,foldBtnWidth:te,textContent:de,onEllipsisChange:T,onFoldChange:L},["onEllipsisChange","fold","onFoldChange"])[0],ge=e.useRef(null),pe=e.useRef(null),ve=e.useRef(null),me=e.useRef(null),Ce=e.useMemo(function(){return l({lineHeight:U?"1.4":d||void 0},f)},[f,d,U]),xe=e.useMemo(function(){return{whiteSpace:N,width:B}},[N,B]),be=e.useMemo(function(){var e="height"===k;if(!J||!(e||se&&oe))return xe;var t=!b||"bottom"!==M&&Z?void 0:oe+"px";return l({},xe,{minHeight:!e&&Z?(se-.2)*oe+"px":void 0,WebkitLineClamp:e?void 0:Z?se:void 0,maxHeight:e&&Z?R||se*oe||he.containerContentHeight||0:void 0,paddingBottom:t,boxSizing:t?"border-box":void 0})},[se,oe,J,Z,b,M,k,R,xe]),we=e.useMemo(function(){if(Z){var e=oe,t="right"===M?Math.min(e/te*100,80):60;return{boxSizing:"content-box",height:oe+"px",lineHeight:oe+"px",paddingTop:"bottom"===M?e+"px":void 0,paddingLeft:"right"===M?e+"px":void 0,background:"linear-gradient(to "+M+", "+g+(4===g.length?"0":"00")+", "+g+" "+t+"%, "+g+" 100%)"}}},[oe,g,Z,M,te]),Ee=e.useCallback(function(){if(ge.current){var e=ge.current.style.width,t=window.getComputedStyle(ge.current).width;ge.current.style.width=parseFloat(t)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(function(){ge.current&&(ge.current.style.width=e)})}},[]),Fe=e.useCallback(function(e,t){void 0===t&&(t=!he.fold),he.fold=t,$(t)},[]),He=e.useMemo(function(){/*#__PURE__*/return o.default.createElement("div",{className:t.classNames("btn-fold-wrapper","btn-fold-wrapper-"+M,"bottom"===M&&"placement-"+W),style:we,ref:me,onClick:Fe},P?P(Z):/*#__PURE__*/o.default.createElement("div",{className:"btn-fold"},Z?H:E))},[we,Z,E,Fe,P,W,M,H]),ye=e.useCallback(function(e,t){void 0===e&&(e=he.ellipsis);var n=(void 0===t?{}:t).forceResetFold,i=void 0!==n&&n,o=he.ellipsis,l=he.fold,a=he.defaultFold;e!==o&&(K(e),he.ellipsis=e,null==he.onEllipsisChange||he.onEllipsisChange(e)),v&&(i||!o&&e)&&l!==a&&Fe(void 0,a)},[Fe,G,v]),Me=e.useCallback(function(){var e=pe.current,t=ve.current;if(e&&t){he.contentOffsetHeight=e.offsetHeight;var n=window.getComputedStyle(t),i=parseFloat(n.paddingTop),o=parseFloat(n.paddingBottom),l=he.containerContentHeight=t.clientHeight-i-o,a=0;if(!a&&e){var r=(n||{}).lineHeight;r&&((a=parseFloat(r))||X(!0))}if(oe===a||(le(a),a))if("height"===k)ye(he.contentOffsetHeight>(R||l));else if(c)se!==c&&fe(c),ye(he.contentOffsetHeight>=(c+1)*Math.floor(a)-1);else if(he.contentOffsetHeight>l){var s=Math.floor(l/a)||1;se!==s&&fe(s),ye(!0)}else ye(!1)}},[c,oe,k,R,ye]);t.useCompatibleEffect(function(){ye(he.ellipsis,{forceResetFold:!0}),Me()},[Me,ye]),e.useEffect(function(){if(J&&me.current){var e=me.current.offsetWidth;e!==he.foldBtnWidth&&(he.foldBtnWidth=e,ne(e))}},[J,H,b]),e.useEffect(function(){t.isSafari&&Ee()},[Z,Ee]);var Se=e.useCallback(function(){var e,t=(null==(e=pe.current)?void 0:e.textContent)||"";t!==he.textContent&&(he.textContent=t,ce(t))},[]),ke=e.useMemo(function(){return J&&Z?"function"==typeof C?C(de):C||de:void 0},[C,J,Z,de]);return e.useEffect(function(){he.inited&&(null==q||q({ellipsis:J,fold:Z,title:ke}))},[q,Z,J,ke]),e.useEffect(function(){he.inited=!0},[]),/*#__PURE__*/o.default.createElement("div",{className:t.classNames(a("container"),s),style:Ce,ref:function(e){t.assignRef(ve,e),r&&t.assignRef(r,e)},onMouseEnter:j,onMouseLeave:z,onPointerEnter:A,onPointerLeave:_,onClick:V,onFocus:D},/*#__PURE__*/o.default.createElement(n.Measure,{offset:!0},function(e){var n=e.measureRef,i=(e.contentRect.offset||{}).height;return void 0!==i&&Math.abs(i-he.contentOffsetHeight)>1&&Me(),/*#__PURE__*/o.default.createElement("div",{style:xe,className:"content-shadow-dom",ref:function(e){t.assignRef(n,e),t.assignRef(pe,e),Se()}},G)}),/*#__PURE__*/o.default.createElement("div",{className:"text-ellipsis-inner",title:m?ke:void 0,style:be,ref:ge},J&&b&&He,G))});exports.TextEllipsis=r,exports.c=a;
1
+ var e=require("react"),t=require("@ohkit/prefix-classname"),n=require("@ohkit/react-helper"),i=require("@ohkit/platform"),o=require("@ohkit/measure");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/l(e);function a(){return a=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)({}).hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},a.apply(null,arguments)}var s=t.prefixClassname("ohkit-text-ellipsis__"),f=e.forwardRef(function(l,f){var u=l.className,d=l.style,c=l.lineHeight,h=void 0===c?"":c,p=l.lines,g=l.maskBgColor,v=void 0===g?"#fff":g,m=l.resetFoldWhenChildrenOrEllipsisChange,C=void 0!==m&&m,x=l.showTitleWhenFold,b=l.titleWhenFold,w=l.showFoldControl,E=void 0===w||w,F=l.foldText,H=void 0===F?"收起":F,y=l.unfoldText,k=void 0===y?"展开":y,M=l.uiType,S=void 0===M?"right":M,R=l.truncateMode,O=void 0===R?"line":R,W=l.maxHeight,N=l.controlPlacement,q=void 0===N?"center":N,B=l.whiteSpace,P=l.width,T=l.renderFoldButton,L=l.onEllipsisChange,j=l.onFoldChange,z=l.onStatusChange,A=l.onMouseEnter,_=l.onMouseLeave,V=l.onPointerEnter,D=l.onPointerLeave,G=l.onClick,I=l.onFocus,J=l.content||l.children,K=e.useState(!1),Q=K[0],U=K[1],X=e.useState(!1),Y=X[0],Z=X[1],$=n.useSyncPropsState(l,"fold",{defaultValue:!0,onChange:j}),ee=$[0],te=$[1],ne=e.useState(1),ie=ne[0],oe=ne[1],le=e.useState("string"==typeof h&&h.endsWith("px")?parseFloat(h):0),re=le[0],ae=le[1],se=e.useState(p),fe=se[0],ue=void 0===fe?0:fe,de=se[1],ce=e.useState(""),he=ce[0],pe=ce[1],ge=n.useRuntime({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:Q,defaultFold:ee,fold:ee,foldBtnWidth:ie,textContent:he,onEllipsisChange:L,onFoldChange:j},["onEllipsisChange","fold","onFoldChange"])[0],ve=e.useRef(null),me=e.useRef(null),Ce=e.useRef(null),xe=e.useRef(null),be=e.useMemo(function(){return a({lineHeight:Y?"1.4":h||void 0},d)},[d,h,Y]),we=e.useMemo(function(){return{whiteSpace:B,width:P}},[B,P]),Ee=e.useMemo(function(){var e="height"===O;if(!Q||!(e||ue&&re))return we;var t=!E||"bottom"!==S&&ee?void 0:re+"px";return a({},we,{minHeight:!e&&ee?(ue-.2)*re+"px":void 0,WebkitLineClamp:e?void 0:ee?ue:void 0,maxHeight:e&&ee?W||ue*re||ge.containerContentHeight||0:void 0,paddingBottom:t,boxSizing:t?"border-box":void 0})},[ue,re,Q,ee,E,S,O,W,we]),Fe=e.useMemo(function(){if(ee){var e=re,t="right"===S?Math.min(e/ie*100,80):60;return{boxSizing:"content-box",height:re+"px",lineHeight:re+"px",paddingTop:"bottom"===S?e+"px":void 0,paddingLeft:"right"===S?e+"px":void 0,background:"linear-gradient(to "+S+", "+v+(4===v.length?"0":"00")+", "+v+" "+t+"%, "+v+" 100%)"}}},[re,v,ee,S,ie]),He=e.useCallback(function(){if(ve.current){var e=ve.current.style.width,t=window.getComputedStyle(ve.current).width;ve.current.style.width=parseFloat(t)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(function(){ve.current&&(ve.current.style.width=e)})}},[]),ye=e.useCallback(function(e,t){void 0===t&&(t=!ge.fold),ge.fold=t,te(t)},[]),ke=e.useMemo(function(){/*#__PURE__*/return r.default.createElement("div",{className:t.classNames("btn-fold-wrapper","btn-fold-wrapper-"+S,"bottom"===S&&"placement-"+q),style:Fe,ref:xe,onClick:ye},T?T(ee):/*#__PURE__*/r.default.createElement("div",{className:"btn-fold"},ee?k:H))},[Fe,ee,H,ye,T,q,S,k]),Me=e.useCallback(function(e,t){void 0===e&&(e=ge.ellipsis);var n=(void 0===t?{}:t).forceResetFold,i=void 0!==n&&n,o=ge.ellipsis,l=ge.fold,r=ge.defaultFold;e!==o&&(U(e),ge.ellipsis=e,null==ge.onEllipsisChange||ge.onEllipsisChange(e)),C&&(i||!o&&e)&&l!==r&&ye(void 0,r)},[ye,J,C]),Se=e.useCallback(function(){var e=me.current,t=Ce.current;if(e&&t){ge.contentOffsetHeight=e.offsetHeight;var n=window.getComputedStyle(t),i=parseFloat(n.paddingTop),o=parseFloat(n.paddingBottom),l=ge.containerContentHeight=t.clientHeight-i-o,r=0;if(!r&&e){var a=(n||{}).lineHeight;a&&((r=parseFloat(a))||Z(!0))}if(re===r||(ae(r),r))if("height"===O)Me(ge.contentOffsetHeight>(W||l));else if(p)ue!==p&&de(p),Me(ge.contentOffsetHeight>=(p+1)*Math.floor(r)-1);else if(ge.contentOffsetHeight>l){var s=Math.floor(l/r)||1;ue!==s&&de(s),Me(!0)}else Me(!1)}},[p,re,O,W,Me]);n.useCompatibleEffect(function(){Me(ge.ellipsis,{forceResetFold:!0}),Se()},[Se,Me]),e.useEffect(function(){if(Q&&xe.current){var e=xe.current.offsetWidth;e!==ge.foldBtnWidth&&(ge.foldBtnWidth=e,oe(e))}},[Q,k,E]),e.useEffect(function(){i.isSafari&&He()},[ee,He]);var Re=e.useCallback(function(){var e,t=(null==(e=me.current)?void 0:e.textContent)||"";t!==ge.textContent&&(ge.textContent=t,pe(t))},[]),Oe=e.useMemo(function(){return Q&&ee?"function"==typeof b?b(he):b||he:void 0},[b,Q,ee,he]);return e.useEffect(function(){ge.inited&&(null==z||z({ellipsis:Q,fold:ee,title:Oe}))},[z,ee,Q,Oe]),e.useEffect(function(){ge.inited=!0},[]),/*#__PURE__*/r.default.createElement("div",{className:t.classNames(s("container"),u),style:be,ref:function(e){n.assignRef(Ce,e),f&&n.assignRef(f,e)},onMouseEnter:A,onMouseLeave:_,onPointerEnter:V,onPointerLeave:D,onClick:G,onFocus:I},/*#__PURE__*/r.default.createElement(o.Measure,{offset:!0},function(e){var t=e.measureRef,i=(e.contentRect.offset||{}).height;return void 0!==i&&Math.abs(i-ge.contentOffsetHeight)>1&&Se(),/*#__PURE__*/r.default.createElement("div",{style:we,className:"content-shadow-dom",ref:function(e){n.assignRef(t,e),n.assignRef(me,e),Re()}},J)}),/*#__PURE__*/r.default.createElement("div",{className:"text-ellipsis-inner",title:x?Oe:void 0,style:Ee,ref:ve},Q&&E&&ke,J))});exports.TextEllipsis=f,exports.c=s;
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n isSafari,\n prefixClassname as p,\n classNames as cx,\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/utils\";\nimport { Measure } from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","prefixClassname","TextEllipsis","forwardRef","props","ref","className","style","_props$lineHeight","lineHeight","lines","_props$maskBgColor","maskBgColor","_props$resetFoldWhenC","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","_props$showFoldContro","showFoldControl","_props$foldText","foldText","_props$unfoldText","unfoldText","_props$uiType","uiType","_props$truncateMode","truncateMode","maxHeight","_props$controlPlaceme","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","content","children","_useState","useState","ellipsis","setEllipsis","_useState2","getLineHeightFail","setGetLineHeightFail","_useSyncPropsState","useSyncPropsState","defaultValue","onChange","fold","setFold","_useState3","foldBtnWidth","setFoldBtnWidth","_useState4","endsWith","parseFloat","innerLineHeight","setInnerLineHeight","_useState5","_useState5$","innerLines","setInnerLines","_useState6","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","classNames","resetState","newEllipsis","_temp","_ref","_ref$forceResetFold","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","_ref3","measureRef","contentRect","abs"],"mappings":"qYA4Ba,IAAAA,EAAIC,EAACC,gBAAC,yBA+HNC,EAAeC,EAAAA,WAA8C,SAACC,EAAOC,GAChF,IACEC,EA6BEF,EA7BFE,UACAC,EA4BEH,EA5BFG,MAAKC,EA4BHJ,EA3BFK,WAAAA,OAAU,IAAAD,EAAG,GAAEA,EACfE,EA0BEN,EA1BFM,MAAKC,EA0BHP,EAzBFQ,YAAAA,OAAW,IAAAD,EAAG,OAAMA,EAEZE,EAuBNT,EAtBFU,sCAAAA,OAAwC,IAAHD,GAAQA,EAC7CE,EAqBEX,EArBFW,kBACAC,EAoBEZ,EApBFY,cAAaC,EAoBXb,EAnBFc,gBAAAA,OAAe,IAAAD,GAAOA,EAAAE,EAmBpBf,EAlBFgB,SAAAA,OAAQ,IAAAD,EAAG,KAAIA,EAAAE,EAkBbjB,EAjBFkB,WAAAA,OAAa,IAAHD,EAAG,KAAIA,EAAAE,EAiBfnB,EAhBFoB,OAAAA,OAAS,IAAHD,EAAG,QAAOA,EAAAE,EAgBdrB,EAfFsB,aAAAA,OAAe,IAAHD,EAAG,OAAMA,EACrBE,EAcEvB,EAdFuB,UAASC,EAcPxB,EAbFyB,iBAAAA,OAAmB,IAAHD,EAAG,SAAQA,EAC3BE,EAYE1B,EAZF0B,WACAC,EAWE3B,EAXF2B,MACAC,EAUE5B,EAVF4B,iBACAC,EASE7B,EATF6B,iBACAC,EAQE9B,EARF8B,aACAC,EAOE/B,EAPF+B,eACAC,EAMEhC,EANFgC,aACAC,EAKEjC,EALFiC,aACAC,EAIElC,EAJFkC,eACAC,EAGEnC,EAHFmC,eACAC,EAEEpC,EAFFoC,QACAC,EACErC,EADFqC,QAEIC,EADFtC,EAxBFuC,SAwBEvC,EAvBFwC,SA0BFC,EAAgCC,EAAQA,UAAC,GAAlCC,EAAQF,EAAA,GAAEG,EAAWH,EAAA,GAC5BI,EAAkDH,EAAQA,UAAC,GAApDI,EAAiBD,EAAA,GAAEE,EAAoBF,EAAA,GAE9CG,EAAwBC,EAAiBA,kBAACjD,EAAO,OAAQ,CAACkD,cAAc,EAAMC,SAAUrB,IAAjFsB,EAAIJ,EAAEK,GAAAA,EAAOL,EACpB,GAAAM,GAAwCZ,EAAQA,SAAC,GAA1Ca,GAAYD,GAAEE,GAAAA,GAAeF,GACpC,GAAAG,GAA8Cf,EAAAA,SACtB,iBAAfrC,GAA2BA,EAAWqD,SAAS,MAClDC,WAAWtD,GACX,GAHCuD,GAAeH,GAAA,GAAEI,GAAkBJ,GAK1C,GAAAK,GAAwCpB,EAAQA,SAACpC,GAAMyD,GAAAD,GAAhDE,GAAAA,QAAa,IAAHD,GAAG,EAACA,GAAEE,GAAaH,GAEpC,GAAAI,GAAsCxB,EAAAA,SAAS,IAAxCyB,GAAWD,GAAEE,GAAAA,GAAcF,GAElC,GAAOG,GAAWC,EAAAA,WAAW,CAC3BC,QAAQ,EACRC,oBAAqB,EACrBC,uBAAwB,EACxB9B,SAAAA,EACA+B,YAAatB,EACbA,KAAAA,EACAG,aAAAA,GACAY,YAAAA,GACAtC,iBAAAA,EACAC,aAAAA,GACC,CAAC,mBAAoB,OAAQ,iBAEhC,GAAM6C,GAAaC,EAAAA,OAAuB,MACpCC,GAAaD,EAAAA,OAAuB,MACpCE,GAAeF,EAAAA,OAAuB,MACtCG,GAAgBH,EAAAA,OAAuB,MAEvCI,GAAiBC,EAAAA,QAAQ,WAC7B,OAAAC,EACE7E,CAAAA,WAAYyC,EACR,MACAzC,QAA0B8E,GAC3BhF,EAEP,EAAG,CAACA,EAAOE,EAAYyC,IAEjBsC,GAAkBH,EAAOA,QAAC,WAC9B,MAAO,CACLvD,WAAAA,EACAC,MAAAA,EAEJ,EAAG,CAACD,EAAYC,IAEV0D,GAAYJ,EAAOA,QAAC,WACxB,IACMK,EAAgC,WAAjBhE,EACrB,IAAKqB,KAAa2C,GAFJtB,IAEgCJ,IAC5C,OAAOwB,GAET,IAAMG,GAAgBzE,GAA+B,WAAXM,GAAwBgC,OAAiC+B,EAAtBvB,GAAsBuB,KACnG,OAAAD,EAAA,CAAA,EACKE,GAAe,CAElBI,WAAYF,GAAgBlC,GAThBY,GASmC,IAAOJ,GAAe,UAAOuB,EAI5EM,gBAAiBH,OAAeH,EAAY/B,EAbhCY,QAa+CmB,EAC3D5D,UAAW+D,GAAgBlC,EAAQ7B,GAdvByC,GAc4CJ,IAAmBS,GAAQI,wBAA0B,OAAKU,EAClHI,cAAAA,EACAG,UAAWH,EAAgB,kBAAwBJ,GAEvD,EAAG,CAACnB,GAAYJ,GAAiBjB,EAAUS,EAAMtC,EAAiBM,EAAQE,EAAcC,EAAW6D,KAG7FO,GAAWV,EAAAA,QAAQ,WACvB,GAAK7B,EAAL,CAIA,IAAMwC,EAAUhC,GAEViC,EAAmB,UAAXzE,EAAqB0E,KAAKC,IAAKH,EAAUrC,GAAgB,IAAK,IAAM,GAKlF,MAAO,CACLmC,UAAW,cACXM,OAAWpC,GAAmB,KAC9BvD,WAAeuD,GAAe,KAC9BqC,WAAuB,WAAX7E,EAAyBwE,EAAcT,UAAAA,EACnDe,YAAwB,UAAX9E,EAAwBwE,EAAO,UAAOT,EAEnDgB,WAAU,sBAAwB/E,EAAM,KAVnBZ,GACE,IAAvBA,EAAY4F,OAAe,IAAM,MASuB,KAAK5F,EAAW,IAAIqF,EAAK,MAAMrF,EAAW,SAhBnG,CAkBH,EAAG,CAACoD,GAAiBpD,EAAa4C,EAAMhC,EAAQmC,KAE1C8C,GAAgBC,EAAWA,YAAC,WAEhC,GAAI3B,GAAW4B,QAAS,CACtB,IAAMC,EAAkB7B,GAAW4B,QAAQpG,MAAMwB,MAC3C8E,EAAaC,OAAOC,iBAAiBhC,GAAW4B,SAAS5E,MAE/DgD,GAAW4B,QAAQpG,MAAMwB,MAAWgC,WAAW8C,GAAc,GAAO,KACxC,MAA5BC,OAAOE,uBAAPF,OAAOE,sBAAwB,WACzBjC,GAAW4B,UACb5B,GAAW4B,QAAQpG,MAAMwB,MAAQ6E,EAErC,EACD,CACH,EAAG,IAEGK,GAAmBP,EAAWA,YAClC,SAACQ,EAAkC1D,QAAAA,IAAAA,IAAAA,GAAQiB,GAAQjB,MACjDiB,GAAQjB,KAAOA,EACfC,EAAQD,EACZ,EAAG,IAEG2D,GAAa9B,EAAOA,QAAC,wBACzB,OACE+B,EAAAA,QAAAC,cACE/G,MAAAA,CAAAA,UAAWgH,EAAEC,WACX,mBACoB/F,oBAAAA,EACT,WAAXA,GAAoCK,aAAAA,GAEtCtB,MAAOwF,GACP1F,IAAK8E,GACL3C,QAASyE,IAERjF,EACCA,EAAiBwB,gBAEjB4D,EAAAA,QAAAC,cAAA,MAAA,CAAK/G,UAAW,YAAakD,EAAOlC,EAAaF,GAIzD,EAAG,CACD2E,GACAvC,EACApC,EACA6F,GACAjF,EACAH,EACAL,EACAF,IAIIkG,GAAad,EAAWA,YAAC,SAACe,EAAWC,QAAXD,IAAAA,IAAAA,EAAchD,GAAQ1B,UAAQ4E,IAExDC,QAAF,IAF0DF,EAE1D,CAAA,EAAEA,GADJG,eAAAA,OAAiB,IAAHD,GAAQA,EAEf7E,EAAwC0B,GAAxC1B,SAAgB+E,EAAwBrD,GAA9BjB,KAAesB,EAAeL,GAAfK,YAC5B2C,IAAgB1E,IAClBC,EAAYyE,GACZhD,GAAQ1B,SAAW0E,EACnBhD,MAAAA,GAAQxC,kBAARwC,GAAQxC,iBAAmBwF,IAI3B3G,IACI+G,IAAoB9E,GAAY0E,IACjCK,IAAYhD,GAEfmC,QAAiB1B,EAAWT,EAEhC,EAAG,CAACmC,GAAkBvE,EAAc5B,IAE9BiH,GAAerB,EAAAA,YAAY,WAC/B,IAAMsB,EAAU/C,GAAW0B,QACrBsB,EAAe/C,GAAayB,QAClC,GAAKqB,GAAYC,EAAjB,CAGAxD,GAAQG,oBAAsBoD,EAAQE,aACtC,IAAM9C,EAAiB0B,OAAOC,iBAAiBkB,GACzC5B,EAAatC,WAAWqB,EAAeiB,YACvCV,EAAgB5B,WAAWqB,EAAeO,eAC1Cd,EAAyBJ,GAAQI,uBAAyBoD,EAAaE,aAAe9B,EAAaV,EAGrGyC,EAAiB,EAErB,IAAKA,GAAkBJ,EAAS,CAC9B,IAAOvH,GAAc2E,GAAkB,CAAA,GAAhC3E,WACHA,KAEF2H,EAAiBrE,WAAWtD,KAE1B0C,GAAqB,GAG1B,CAED,GAAIa,KAAoBoE,IACtBnE,GAAmBmE,GACdA,GAOP,GAFsC,WAAjB1G,EAGnB8F,GAAW/C,GAAQG,qBAAuBjD,GAAakD,SAKzD,GAAKnE,EAWC0D,KAAe1D,GACjB2D,GAAc3D,GAId8G,GAAW/C,GAAQG,sBAAwBlE,EAAQ,GAAKwF,KAAKmC,MAAMD,GAAkB,QAfvF,GAAI3D,GAAQG,oBAAsBC,EAAwB,CACtD,IAAMyD,EAAcpC,KAAKmC,MAAMxD,EAAyBuD,IAAmB,EACvEhE,KAAekE,GACjBjE,GAAciE,GAEhBd,IAAW,EACd,MACCA,IAAW,EA5Cd,CAsDH,EAAG,CAAC9G,EAAOsD,GAAiBtC,EAAcC,EAAW6F,KAIrDe,EAAmBA,oBAAC,WAClBf,GAAW/C,GAAQ1B,SAAU,CAC3B8E,gBAAgB,IAElBE,IACF,EAAG,CAACA,GAAcP,KAGlBgB,EAASA,UAAC,WACR,GAAIzF,GAAYoC,GAAcwB,QAAS,CACrC,IAAO8B,EAAetD,GAAcwB,QAA7B8B,YACHA,IAAgBhE,GAAQd,eAC1Bc,GAAQd,aAAe8E,EACvB7E,GAAgB6E,GAEnB,CACH,EAAG,CAAC1F,EAAUzB,EAAYJ,IAC1BsH,EAASA,UAAC,WACJE,EAAAA,UACFjC,IAEJ,EAAG,CAACjD,EAAMiD,KACV,IAAMkC,GAAoBjC,EAAAA,YAAY,WAAK,IAAAkC,EACnCC,GAAiBD,OAAAA,EAAA3D,GAAW0B,cAAXiC,EAAAA,EAAoBrE,cAAe,GACtDsE,IAAmBpE,GAAQF,cAC7BE,GAAQF,YAAcsE,EACtBrE,GAAeqE,GAEnB,EAAG,IACGC,GAAazD,EAAAA,QAAQ,WACvB,OAAOtC,GAAYS,EACW,mBAAlBxC,EACNA,EAAcuD,IACdvD,GAAiBuD,QACnBgB,CACR,EAAG,CAACvE,EAAe+B,EAAUS,EAAMe,KAkBnC,OAjBAiE,EAASA,UAAC,WACJ/D,GAAQE,SACI,MAAdxC,GAAAA,EAAiB,CACbY,SAAAA,EACAS,KAAAA,EACAuF,MAAOD,KAGf,EAAG,CAAC3G,EAAgBqB,EAAMT,EAAU+F,KACpCN,EAAAA,UAAU,WACR/D,GAAQE,QAAS,CACnB,EAAG,iBAODyC,EAAA,QAAAC,cACE/G,MAAAA,CAAAA,UAAWgH,EAAAA,WAAGvH,EAAE,aAAcO,GAC9BC,MAAO6E,GACP/E,IAAK,SAAC2I,GACJC,EAAAA,UAAU/D,GAAc8D,GACxB3I,GAAO4I,EAASA,UAAC5I,EAAK2I,EACxB,EACA5G,aAAcA,EACdC,aAAcA,EACdC,eAAgBA,EAChBC,eAAgBA,EAChBC,QAASA,EACTC,QAASA,gBAGT2E,EAAAA,QAAAC,cAAC6B,EAAAA,QAAO,CAACC,QAAM,GACZ,SAAAC,GAA8B,IAA5BC,EAAUD,EAAVC,WAEMjD,GAFiBgD,EAAXE,YAEgBH,QAAU,CAAE,GAAlC/C,OAIP,YAHeb,IAAXa,GAAwBF,KAAKqD,IAAInD,EAAS3B,GAAQG,qBAAuB,GAC3EmD,kBAEKX,EAAAA,QAAAC,cAAA,MAAA,CAAK9G,MAAOiF,GAAiBlF,UAAW,qBAAsBD,IAAK,SAAC2I,GACzEC,EAASA,UAACI,EAAYL,GACtBC,EAAAA,UAAUhE,GAAY+D,GACtBL,IACF,GACGjG,EAEL,gBAMF0E,EAAA,QAAAC,cAAA,MAAA,CACE/G,UAAW,sBACXyI,MAAOhI,EAAoB+H,QAAavD,EACxChF,MAAOkF,GACPpF,IAAK0E,IAIJhC,GAAY7B,GAAmBiG,GAC/BzE,GAIT"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n prefixClassname as p,\n classNames as cx,\n} from \"@ohkit/prefix-classname\";\nimport {\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/react-helper\";\nimport {isSafari} from \"@ohkit/platform\";\nimport {Measure} from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","prefixClassname","TextEllipsis","forwardRef","props","ref","className","style","_props$lineHeight","lineHeight","lines","_props$maskBgColor","maskBgColor","_props$resetFoldWhenC","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","_props$showFoldContro","showFoldControl","_props$foldText","foldText","_props$unfoldText","unfoldText","_props$uiType","uiType","_props$truncateMode","truncateMode","maxHeight","_props$controlPlaceme","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","content","children","_useState","useState","ellipsis","setEllipsis","_useState2","getLineHeightFail","setGetLineHeightFail","_useSyncPropsState","useSyncPropsState","defaultValue","onChange","fold","setFold","_useState3","foldBtnWidth","setFoldBtnWidth","_useState4","endsWith","parseFloat","innerLineHeight","setInnerLineHeight","_useState5","_useState5$","innerLines","setInnerLines","_useState6","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","transparent","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","classNames","resetState","newEllipsis","_temp","_ref$forceResetFold","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","_ref3","measureRef","contentRect","abs"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e,{forwardRef as t,useState as n,useRef as o,useMemo as i,useCallback as l,useEffect as r}from"react";import{prefixClassname as s,useSyncPropsState as a,useRuntime as d,classNames as c,useCompatibleEffect as f,isSafari as h,assignRef as u}from"@ohkit/utils";import{Measure as p}from"@ohkit/measure";function g(){return g=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)({}).hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},g.apply(null,arguments)}const m=s("ohkit-text-ellipsis__"),v=t((t,s)=>{const{className:v,style:C,lineHeight:x="",lines:w,maskBgColor:F="#fff",content:H,children:b,resetFoldWhenChildrenOrEllipsisChange:E=!1,showTitleWhenFold:y,titleWhenFold:$,showFoldControl:O=!0,foldText:k="收起",unfoldText:M="展开",uiType:W="right",truncateMode:B="line",maxHeight:S,controlPlacement:L="center",whiteSpace:N,width:P,renderFoldButton:T,onEllipsisChange:R,onFoldChange:j,onStatusChange:q,onMouseEnter:z,onMouseLeave:A,onPointerEnter:_,onPointerLeave:V,onClick:D,onFocus:G}=t,I=H||b,[J,K]=n(!1),[Q,U]=n(!1),[X,Y]=a(t,"fold",{defaultValue:!0,onChange:j}),[Z,ee]=n(1),[te,ne]=n("string"==typeof x&&x.endsWith("px")?parseFloat(x):0),[oe=0,ie]=n(w),[le,re]=n(""),[se]=d({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:J,defaultFold:X,fold:X,foldBtnWidth:Z,textContent:le,onEllipsisChange:R,onFoldChange:j},["onEllipsisChange","fold","onFoldChange"]),ae=o(null),de=o(null),ce=o(null),fe=o(null),he=i(()=>g({lineHeight:Q?"1.4":x||void 0},C),[C,x,Q]),ue=i(()=>({whiteSpace:N,width:P}),[N,P]),pe=i(()=>{const e="height"===B;if(!J||!(e||oe&&te))return ue;const t=!O||"bottom"!==W&&X?void 0:`${te}px`;return g({},ue,{minHeight:!e&&X?(oe-.2)*te+"px":void 0,WebkitLineClamp:e?void 0:X?oe:void 0,maxHeight:e&&X?S||oe*te||se.containerContentHeight||0:void 0,paddingBottom:t,boxSizing:t?"border-box":void 0})},[oe,te,J,X,O,W,B,S,ue]),ge=i(()=>{if(!X)return;const e=te,t="right"===W?Math.min(e/Z*100,80):60;return{boxSizing:"content-box",height:`${te}px`,lineHeight:`${te}px`,paddingTop:"bottom"===W?`${e}px`:void 0,paddingLeft:"right"===W?`${e}px`:void 0,background:`linear-gradient(to ${W}, ${F}${4===F.length?"0":"00"}, ${F} ${t}%, ${F} 100%)`}},[te,F,X,W,Z]),me=l(()=>{if(ae.current){const e=ae.current.style.width,t=window.getComputedStyle(ae.current).width;ae.current.style.width=parseFloat(t)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(()=>{ae.current&&(ae.current.style.width=e)})}},[]),ve=l((e,t=!se.fold)=>{se.fold=t,Y(t)},[]),Ce=i(()=>/*#__PURE__*/e.createElement("div",{className:c("btn-fold-wrapper",`btn-fold-wrapper-${W}`,"bottom"===W&&`placement-${L}`),style:ge,ref:fe,onClick:ve},T?T(X):/*#__PURE__*/e.createElement("div",{className:"btn-fold"},X?M:k)),[ge,X,k,ve,T,L,W,M]),xe=l((e=se.ellipsis,{forceResetFold:t=!1}={})=>{const{ellipsis:n,fold:o,defaultFold:i}=se;e!==n&&(K(e),se.ellipsis=e,null==se.onEllipsisChange||se.onEllipsisChange(e)),E&&(t||!n&&e)&&o!==i&&ve(void 0,i)},[ve,I,E]),we=l(()=>{const e=de.current,t=ce.current;if(!e||!t)return;se.contentOffsetHeight=e.offsetHeight;const n=window.getComputedStyle(t),o=parseFloat(n.paddingTop),i=parseFloat(n.paddingBottom),l=se.containerContentHeight=t.clientHeight-o-i;let r=0;if(!r&&e){const{lineHeight:e}=n||{};e&&(r=parseFloat(e),r||U(!0))}if(te===r||(ne(r),r))if("height"===B)xe(se.contentOffsetHeight>(S||l));else if(w)oe!==w&&ie(w),xe(se.contentOffsetHeight>=(w+1)*Math.floor(r)-1);else if(se.contentOffsetHeight>l){const e=Math.floor(l/r)||1;oe!==e&&ie(e),xe(!0)}else xe(!1)},[w,te,B,S,xe]);f(()=>{xe(se.ellipsis,{forceResetFold:!0}),we()},[we,xe]),r(()=>{if(J&&fe.current){const{offsetWidth:e}=fe.current;e!==se.foldBtnWidth&&(se.foldBtnWidth=e,ee(e))}},[J,M,O]),r(()=>{h&&me()},[X,me]);const Fe=l(()=>{var e;const t=(null==(e=de.current)?void 0:e.textContent)||"";t!==se.textContent&&(se.textContent=t,re(t))},[]),He=i(()=>J&&X?"function"==typeof $?$(le):$||le:void 0,[$,J,X,le]);return r(()=>{se.inited&&(null==q||q({ellipsis:J,fold:X,title:He}))},[q,X,J,He]),r(()=>{se.inited=!0},[]),/*#__PURE__*/e.createElement("div",{className:c(m("container"),v),style:he,ref:e=>{u(ce,e),s&&u(s,e)},onMouseEnter:z,onMouseLeave:A,onPointerEnter:_,onPointerLeave:V,onClick:D,onFocus:G},/*#__PURE__*/e.createElement(p,{offset:!0},({measureRef:t,contentRect:n})=>{const{height:o}=n.offset||{};return void 0!==o&&Math.abs(o-se.contentOffsetHeight)>1&&we(),/*#__PURE__*/e.createElement("div",{style:ue,className:"content-shadow-dom",ref:e=>{u(t,e),u(de,e),Fe()}},I)}),/*#__PURE__*/e.createElement("div",{className:"text-ellipsis-inner",title:y?He:void 0,style:pe,ref:ae},J&&O&&Ce,I))});export{v as TextEllipsis,m as c};
1
+ import e,{forwardRef as t,useState as n,useRef as o,useMemo as i,useCallback as l,useEffect as r}from"react";import{prefixClassname as s,classNames as a}from"@ohkit/prefix-classname";import{useSyncPropsState as d,useRuntime as c,useCompatibleEffect as f,assignRef as h}from"@ohkit/react-helper";import{isSafari as p}from"@ohkit/platform";import{Measure as u}from"@ohkit/measure";function g(){return g=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)({}).hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},g.apply(null,arguments)}const m=s("ohkit-text-ellipsis__"),v=t((t,s)=>{const{className:v,style:C,lineHeight:x="",lines:w,maskBgColor:F="#fff",content:H,children:b,resetFoldWhenChildrenOrEllipsisChange:E=!1,showTitleWhenFold:y,titleWhenFold:$,showFoldControl:k=!0,foldText:O="收起",unfoldText:M="展开",uiType:W="right",truncateMode:B="line",maxHeight:S,controlPlacement:L="center",whiteSpace:N,width:P,renderFoldButton:T,onEllipsisChange:R,onFoldChange:j,onStatusChange:q,onMouseEnter:z,onMouseLeave:A,onPointerEnter:_,onPointerLeave:V,onClick:D,onFocus:G}=t,I=H||b,[J,K]=n(!1),[Q,U]=n(!1),[X,Y]=d(t,"fold",{defaultValue:!0,onChange:j}),[Z,ee]=n(1),[te,ne]=n("string"==typeof x&&x.endsWith("px")?parseFloat(x):0),[oe=0,ie]=n(w),[le,re]=n(""),[se]=c({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:J,defaultFold:X,fold:X,foldBtnWidth:Z,textContent:le,onEllipsisChange:R,onFoldChange:j},["onEllipsisChange","fold","onFoldChange"]),ae=o(null),de=o(null),ce=o(null),fe=o(null),he=i(()=>g({lineHeight:Q?"1.4":x||void 0},C),[C,x,Q]),pe=i(()=>({whiteSpace:N,width:P}),[N,P]),ue=i(()=>{const e="height"===B;if(!J||!(e||oe&&te))return pe;const t=!k||"bottom"!==W&&X?void 0:`${te}px`;return g({},pe,{minHeight:!e&&X?(oe-.2)*te+"px":void 0,WebkitLineClamp:e?void 0:X?oe:void 0,maxHeight:e&&X?S||oe*te||se.containerContentHeight||0:void 0,paddingBottom:t,boxSizing:t?"border-box":void 0})},[oe,te,J,X,k,W,B,S,pe]),ge=i(()=>{if(!X)return;const e=te,t="right"===W?Math.min(e/Z*100,80):60;return{boxSizing:"content-box",height:`${te}px`,lineHeight:`${te}px`,paddingTop:"bottom"===W?`${e}px`:void 0,paddingLeft:"right"===W?`${e}px`:void 0,background:`linear-gradient(to ${W}, ${F}${4===F.length?"0":"00"}, ${F} ${t}%, ${F} 100%)`}},[te,F,X,W,Z]),me=l(()=>{if(ae.current){const e=ae.current.style.width,t=window.getComputedStyle(ae.current).width;ae.current.style.width=parseFloat(t)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(()=>{ae.current&&(ae.current.style.width=e)})}},[]),ve=l((e,t=!se.fold)=>{se.fold=t,Y(t)},[]),Ce=i(()=>/*#__PURE__*/e.createElement("div",{className:a("btn-fold-wrapper",`btn-fold-wrapper-${W}`,"bottom"===W&&`placement-${L}`),style:ge,ref:fe,onClick:ve},T?T(X):/*#__PURE__*/e.createElement("div",{className:"btn-fold"},X?M:O)),[ge,X,O,ve,T,L,W,M]),xe=l((e=se.ellipsis,{forceResetFold:t=!1}={})=>{const{ellipsis:n,fold:o,defaultFold:i}=se;e!==n&&(K(e),se.ellipsis=e,null==se.onEllipsisChange||se.onEllipsisChange(e)),E&&(t||!n&&e)&&o!==i&&ve(void 0,i)},[ve,I,E]),we=l(()=>{const e=de.current,t=ce.current;if(!e||!t)return;se.contentOffsetHeight=e.offsetHeight;const n=window.getComputedStyle(t),o=parseFloat(n.paddingTop),i=parseFloat(n.paddingBottom),l=se.containerContentHeight=t.clientHeight-o-i;let r=0;if(!r&&e){const{lineHeight:e}=n||{};e&&(r=parseFloat(e),r||U(!0))}if(te===r||(ne(r),r))if("height"===B)xe(se.contentOffsetHeight>(S||l));else if(w)oe!==w&&ie(w),xe(se.contentOffsetHeight>=(w+1)*Math.floor(r)-1);else if(se.contentOffsetHeight>l){const e=Math.floor(l/r)||1;oe!==e&&ie(e),xe(!0)}else xe(!1)},[w,te,B,S,xe]);f(()=>{xe(se.ellipsis,{forceResetFold:!0}),we()},[we,xe]),r(()=>{if(J&&fe.current){const{offsetWidth:e}=fe.current;e!==se.foldBtnWidth&&(se.foldBtnWidth=e,ee(e))}},[J,M,k]),r(()=>{p&&me()},[X,me]);const Fe=l(()=>{var e;const t=(null==(e=de.current)?void 0:e.textContent)||"";t!==se.textContent&&(se.textContent=t,re(t))},[]),He=i(()=>J&&X?"function"==typeof $?$(le):$||le:void 0,[$,J,X,le]);return r(()=>{se.inited&&(null==q||q({ellipsis:J,fold:X,title:He}))},[q,X,J,He]),r(()=>{se.inited=!0},[]),/*#__PURE__*/e.createElement("div",{className:a(m("container"),v),style:he,ref:e=>{h(ce,e),s&&h(s,e)},onMouseEnter:z,onMouseLeave:A,onPointerEnter:_,onPointerLeave:V,onClick:D,onFocus:G},/*#__PURE__*/e.createElement(u,{offset:!0},({measureRef:t,contentRect:n})=>{const{height:o}=n.offset||{};return void 0!==o&&Math.abs(o-se.contentOffsetHeight)>1&&we(),/*#__PURE__*/e.createElement("div",{style:pe,className:"content-shadow-dom",ref:e=>{h(t,e),h(de,e),Fe()}},I)}),/*#__PURE__*/e.createElement("div",{className:"text-ellipsis-inner",title:y?He:void 0,style:ue,ref:ae},J&&k&&Ce,I))});export{v as TextEllipsis,m as c};
2
2
  //# sourceMappingURL=index.modern.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.modern.mjs","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n isSafari,\n prefixClassname as p,\n classNames as cx,\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/utils\";\nimport { Measure } from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","TextEllipsis","forwardRef","props","ref","className","style","lineHeight","lines","maskBgColor","content","children","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","showFoldControl","foldText","unfoldText","uiType","truncateMode","maxHeight","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","ellipsis","setEllipsis","useState","getLineHeightFail","setGetLineHeightFail","fold","setFold","useSyncPropsState","defaultValue","onChange","foldBtnWidth","setFoldBtnWidth","innerLineHeight","setInnerLineHeight","endsWith","parseFloat","innerLines","setInnerLines","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","resetState","newEllipsis","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","measureRef","contentRect","abs"],"mappings":"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"}
1
+ {"version":3,"file":"index.modern.mjs","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n prefixClassname as p,\n classNames as cx,\n} from \"@ohkit/prefix-classname\";\nimport {\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/react-helper\";\nimport {isSafari} from \"@ohkit/platform\";\nimport {Measure} from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","TextEllipsis","forwardRef","props","ref","className","style","lineHeight","lines","maskBgColor","content","children","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","showFoldControl","foldText","unfoldText","uiType","truncateMode","maxHeight","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","ellipsis","setEllipsis","useState","getLineHeightFail","setGetLineHeightFail","fold","setFold","useSyncPropsState","defaultValue","onChange","foldBtnWidth","setFoldBtnWidth","innerLineHeight","setInnerLineHeight","endsWith","parseFloat","innerLines","setInnerLines","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","resetState","newEllipsis","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","measureRef","contentRect","abs"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("@ohkit/utils"),require("@ohkit/measure")):"function"==typeof define&&define.amd?define(["exports","react","@ohkit/utils","@ohkit/measure"],t):t((e||self).textEllipsis={},e.react,e.utils,e.measure)}(this,function(e,t,n,i){function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var l=/*#__PURE__*/o(t);function s(){return s=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)({}).hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},s.apply(null,arguments)}var a=n.prefixClassname("ohkit-text-ellipsis__"),r=t.forwardRef(function(e,o){var r=e.className,f=e.style,u=e.lineHeight,d=void 0===u?"":u,c=e.lines,h=e.maskBgColor,p=void 0===h?"#fff":h,g=e.resetFoldWhenChildrenOrEllipsisChange,v=void 0!==g&&g,m=e.showTitleWhenFold,C=e.titleWhenFold,x=e.showFoldControl,b=void 0===x||x,w=e.foldText,E=void 0===w?"收起":w,y=e.unfoldText,F=void 0===y?"展开":y,H=e.uiType,k=void 0===H?"right":H,M=e.truncateMode,S=void 0===M?"line":M,R=e.maxHeight,O=e.controlPlacement,T=void 0===O?"center":O,W=e.whiteSpace,N=e.width,B=e.renderFoldButton,P=e.onEllipsisChange,L=e.onFoldChange,q=e.onStatusChange,j=e.onMouseEnter,z=e.onMouseLeave,A=e.onPointerEnter,_=e.onPointerLeave,V=e.onClick,D=e.onFocus,G=e.content||e.children,I=t.useState(!1),J=I[0],K=I[1],Q=t.useState(!1),U=Q[0],X=Q[1],Y=n.useSyncPropsState(e,"fold",{defaultValue:!0,onChange:L}),Z=Y[0],$=Y[1],ee=t.useState(1),te=ee[0],ne=ee[1],ie=t.useState("string"==typeof d&&d.endsWith("px")?parseFloat(d):0),oe=ie[0],le=ie[1],se=t.useState(c),ae=se[0],re=void 0===ae?0:ae,fe=se[1],ue=t.useState(""),de=ue[0],ce=ue[1],he=n.useRuntime({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:J,defaultFold:Z,fold:Z,foldBtnWidth:te,textContent:de,onEllipsisChange:P,onFoldChange:L},["onEllipsisChange","fold","onFoldChange"])[0],pe=t.useRef(null),ge=t.useRef(null),ve=t.useRef(null),me=t.useRef(null),Ce=t.useMemo(function(){return s({lineHeight:U?"1.4":d||void 0},f)},[f,d,U]),xe=t.useMemo(function(){return{whiteSpace:W,width:N}},[W,N]),be=t.useMemo(function(){var e="height"===S;if(!J||!(e||re&&oe))return xe;var t=!b||"bottom"!==k&&Z?void 0:oe+"px";return s({},xe,{minHeight:!e&&Z?(re-.2)*oe+"px":void 0,WebkitLineClamp:e?void 0:Z?re:void 0,maxHeight:e&&Z?R||re*oe||he.containerContentHeight||0:void 0,paddingBottom:t,boxSizing:t?"border-box":void 0})},[re,oe,J,Z,b,k,S,R,xe]),we=t.useMemo(function(){if(Z){var e=oe,t="right"===k?Math.min(e/te*100,80):60;return{boxSizing:"content-box",height:oe+"px",lineHeight:oe+"px",paddingTop:"bottom"===k?e+"px":void 0,paddingLeft:"right"===k?e+"px":void 0,background:"linear-gradient(to "+k+", "+p+(4===p.length?"0":"00")+", "+p+" "+t+"%, "+p+" 100%)"}}},[oe,p,Z,k,te]),Ee=t.useCallback(function(){if(pe.current){var e=pe.current.style.width,t=window.getComputedStyle(pe.current).width;pe.current.style.width=parseFloat(t)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(function(){pe.current&&(pe.current.style.width=e)})}},[]),ye=t.useCallback(function(e,t){void 0===t&&(t=!he.fold),he.fold=t,$(t)},[]),Fe=t.useMemo(function(){/*#__PURE__*/return l.default.createElement("div",{className:n.classNames("btn-fold-wrapper","btn-fold-wrapper-"+k,"bottom"===k&&"placement-"+T),style:we,ref:me,onClick:ye},B?B(Z):/*#__PURE__*/l.default.createElement("div",{className:"btn-fold"},Z?F:E))},[we,Z,E,ye,B,T,k,F]),He=t.useCallback(function(e,t){void 0===e&&(e=he.ellipsis);var n=(void 0===t?{}:t).forceResetFold,i=void 0!==n&&n,o=he.ellipsis,l=he.fold,s=he.defaultFold;e!==o&&(K(e),he.ellipsis=e,null==he.onEllipsisChange||he.onEllipsisChange(e)),v&&(i||!o&&e)&&l!==s&&ye(void 0,s)},[ye,G,v]),ke=t.useCallback(function(){var e=ge.current,t=ve.current;if(e&&t){he.contentOffsetHeight=e.offsetHeight;var n=window.getComputedStyle(t),i=parseFloat(n.paddingTop),o=parseFloat(n.paddingBottom),l=he.containerContentHeight=t.clientHeight-i-o,s=0;if(!s&&e){var a=(n||{}).lineHeight;a&&((s=parseFloat(a))||X(!0))}if(oe===s||(le(s),s))if("height"===S)He(he.contentOffsetHeight>(R||l));else if(c)re!==c&&fe(c),He(he.contentOffsetHeight>=(c+1)*Math.floor(s)-1);else if(he.contentOffsetHeight>l){var r=Math.floor(l/s)||1;re!==r&&fe(r),He(!0)}else He(!1)}},[c,oe,S,R,He]);n.useCompatibleEffect(function(){He(he.ellipsis,{forceResetFold:!0}),ke()},[ke,He]),t.useEffect(function(){if(J&&me.current){var e=me.current.offsetWidth;e!==he.foldBtnWidth&&(he.foldBtnWidth=e,ne(e))}},[J,F,b]),t.useEffect(function(){n.isSafari&&Ee()},[Z,Ee]);var Me=t.useCallback(function(){var e,t=(null==(e=ge.current)?void 0:e.textContent)||"";t!==he.textContent&&(he.textContent=t,ce(t))},[]),Se=t.useMemo(function(){return J&&Z?"function"==typeof C?C(de):C||de:void 0},[C,J,Z,de]);return t.useEffect(function(){he.inited&&(null==q||q({ellipsis:J,fold:Z,title:Se}))},[q,Z,J,Se]),t.useEffect(function(){he.inited=!0},[]),/*#__PURE__*/l.default.createElement("div",{className:n.classNames(a("container"),r),style:Ce,ref:function(e){n.assignRef(ve,e),o&&n.assignRef(o,e)},onMouseEnter:j,onMouseLeave:z,onPointerEnter:A,onPointerLeave:_,onClick:V,onFocus:D},/*#__PURE__*/l.default.createElement(i.Measure,{offset:!0},function(e){var t=e.measureRef,i=(e.contentRect.offset||{}).height;return void 0!==i&&Math.abs(i-he.contentOffsetHeight)>1&&ke(),/*#__PURE__*/l.default.createElement("div",{style:xe,className:"content-shadow-dom",ref:function(e){n.assignRef(t,e),n.assignRef(ge,e),Me()}},G)}),/*#__PURE__*/l.default.createElement("div",{className:"text-ellipsis-inner",title:m?Se:void 0,style:be,ref:pe},J&&b&&Fe,G))});e.TextEllipsis=r,e.c=a});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("@ohkit/prefix-classname"),require("@ohkit/react-helper"),require("@ohkit/platform"),require("@ohkit/measure")):"function"==typeof define&&define.amd?define(["exports","react","@ohkit/prefix-classname","@ohkit/react-helper","@ohkit/platform","@ohkit/measure"],t):t((e||self).textEllipsis={},e.react,e.prefixClassname,e.reactHelper,e.platform,e.measure)}(this,function(e,t,n,i,o,l){function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/a(t);function s(){return s=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)({}).hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},s.apply(null,arguments)}var f=n.prefixClassname("ohkit-text-ellipsis__"),u=t.forwardRef(function(e,a){var u=e.className,d=e.style,c=e.lineHeight,h=void 0===c?"":c,p=e.lines,g=e.maskBgColor,v=void 0===g?"#fff":g,m=e.resetFoldWhenChildrenOrEllipsisChange,C=void 0!==m&&m,x=e.showTitleWhenFold,b=e.titleWhenFold,w=e.showFoldControl,E=void 0===w||w,y=e.foldText,F=void 0===y?"收起":y,k=e.unfoldText,H=void 0===k?"展开":k,M=e.uiType,S=void 0===M?"right":M,R=e.truncateMode,O=void 0===R?"line":R,T=e.maxHeight,W=e.controlPlacement,N=void 0===W?"center":W,q=e.whiteSpace,B=e.width,P=e.renderFoldButton,L=e.onEllipsisChange,j=e.onFoldChange,z=e.onStatusChange,A=e.onMouseEnter,_=e.onMouseLeave,V=e.onPointerEnter,D=e.onPointerLeave,G=e.onClick,I=e.onFocus,J=e.content||e.children,K=t.useState(!1),Q=K[0],U=K[1],X=t.useState(!1),Y=X[0],Z=X[1],$=i.useSyncPropsState(e,"fold",{defaultValue:!0,onChange:j}),ee=$[0],te=$[1],ne=t.useState(1),ie=ne[0],oe=ne[1],le=t.useState("string"==typeof h&&h.endsWith("px")?parseFloat(h):0),ae=le[0],re=le[1],se=t.useState(p),fe=se[0],ue=void 0===fe?0:fe,de=se[1],ce=t.useState(""),he=ce[0],pe=ce[1],ge=i.useRuntime({inited:!1,contentOffsetHeight:0,containerContentHeight:0,ellipsis:Q,defaultFold:ee,fold:ee,foldBtnWidth:ie,textContent:he,onEllipsisChange:L,onFoldChange:j},["onEllipsisChange","fold","onFoldChange"])[0],ve=t.useRef(null),me=t.useRef(null),Ce=t.useRef(null),xe=t.useRef(null),be=t.useMemo(function(){return s({lineHeight:Y?"1.4":h||void 0},d)},[d,h,Y]),we=t.useMemo(function(){return{whiteSpace:q,width:B}},[q,B]),Ee=t.useMemo(function(){var e="height"===O;if(!Q||!(e||ue&&ae))return we;var t=!E||"bottom"!==S&&ee?void 0:ae+"px";return s({},we,{minHeight:!e&&ee?(ue-.2)*ae+"px":void 0,WebkitLineClamp:e?void 0:ee?ue:void 0,maxHeight:e&&ee?T||ue*ae||ge.containerContentHeight||0:void 0,paddingBottom:t,boxSizing:t?"border-box":void 0})},[ue,ae,Q,ee,E,S,O,T,we]),ye=t.useMemo(function(){if(ee){var e=ae,t="right"===S?Math.min(e/ie*100,80):60;return{boxSizing:"content-box",height:ae+"px",lineHeight:ae+"px",paddingTop:"bottom"===S?e+"px":void 0,paddingLeft:"right"===S?e+"px":void 0,background:"linear-gradient(to "+S+", "+v+(4===v.length?"0":"00")+", "+v+" "+t+"%, "+v+" 100%)"}}},[ae,v,ee,S,ie]),Fe=t.useCallback(function(){if(ve.current){var e=ve.current.style.width,t=window.getComputedStyle(ve.current).width;ve.current.style.width=parseFloat(t)-.1+"px",null==window.requestAnimationFrame||window.requestAnimationFrame(function(){ve.current&&(ve.current.style.width=e)})}},[]),ke=t.useCallback(function(e,t){void 0===t&&(t=!ge.fold),ge.fold=t,te(t)},[]),He=t.useMemo(function(){/*#__PURE__*/return r.default.createElement("div",{className:n.classNames("btn-fold-wrapper","btn-fold-wrapper-"+S,"bottom"===S&&"placement-"+N),style:ye,ref:xe,onClick:ke},P?P(ee):/*#__PURE__*/r.default.createElement("div",{className:"btn-fold"},ee?H:F))},[ye,ee,F,ke,P,N,S,H]),Me=t.useCallback(function(e,t){void 0===e&&(e=ge.ellipsis);var n=(void 0===t?{}:t).forceResetFold,i=void 0!==n&&n,o=ge.ellipsis,l=ge.fold,a=ge.defaultFold;e!==o&&(U(e),ge.ellipsis=e,null==ge.onEllipsisChange||ge.onEllipsisChange(e)),C&&(i||!o&&e)&&l!==a&&ke(void 0,a)},[ke,J,C]),Se=t.useCallback(function(){var e=me.current,t=Ce.current;if(e&&t){ge.contentOffsetHeight=e.offsetHeight;var n=window.getComputedStyle(t),i=parseFloat(n.paddingTop),o=parseFloat(n.paddingBottom),l=ge.containerContentHeight=t.clientHeight-i-o,a=0;if(!a&&e){var r=(n||{}).lineHeight;r&&((a=parseFloat(r))||Z(!0))}if(ae===a||(re(a),a))if("height"===O)Me(ge.contentOffsetHeight>(T||l));else if(p)ue!==p&&de(p),Me(ge.contentOffsetHeight>=(p+1)*Math.floor(a)-1);else if(ge.contentOffsetHeight>l){var s=Math.floor(l/a)||1;ue!==s&&de(s),Me(!0)}else Me(!1)}},[p,ae,O,T,Me]);i.useCompatibleEffect(function(){Me(ge.ellipsis,{forceResetFold:!0}),Se()},[Se,Me]),t.useEffect(function(){if(Q&&xe.current){var e=xe.current.offsetWidth;e!==ge.foldBtnWidth&&(ge.foldBtnWidth=e,oe(e))}},[Q,H,E]),t.useEffect(function(){o.isSafari&&Fe()},[ee,Fe]);var Re=t.useCallback(function(){var e,t=(null==(e=me.current)?void 0:e.textContent)||"";t!==ge.textContent&&(ge.textContent=t,pe(t))},[]),Oe=t.useMemo(function(){return Q&&ee?"function"==typeof b?b(he):b||he:void 0},[b,Q,ee,he]);return t.useEffect(function(){ge.inited&&(null==z||z({ellipsis:Q,fold:ee,title:Oe}))},[z,ee,Q,Oe]),t.useEffect(function(){ge.inited=!0},[]),/*#__PURE__*/r.default.createElement("div",{className:n.classNames(f("container"),u),style:be,ref:function(e){i.assignRef(Ce,e),a&&i.assignRef(a,e)},onMouseEnter:A,onMouseLeave:_,onPointerEnter:V,onPointerLeave:D,onClick:G,onFocus:I},/*#__PURE__*/r.default.createElement(l.Measure,{offset:!0},function(e){var t=e.measureRef,n=(e.contentRect.offset||{}).height;return void 0!==n&&Math.abs(n-ge.contentOffsetHeight)>1&&Se(),/*#__PURE__*/r.default.createElement("div",{style:we,className:"content-shadow-dom",ref:function(e){i.assignRef(t,e),i.assignRef(me,e),Re()}},J)}),/*#__PURE__*/r.default.createElement("div",{className:"text-ellipsis-inner",title:x?Oe:void 0,style:Ee,ref:ve},Q&&E&&He,J))});e.TextEllipsis=u,e.c=f});
2
2
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n isSafari,\n prefixClassname as p,\n classNames as cx,\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/utils\";\nimport { Measure } from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","prefixClassname","TextEllipsis","forwardRef","props","ref","className","style","_props$lineHeight","lineHeight","lines","_props$maskBgColor","maskBgColor","_props$resetFoldWhenC","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","_props$showFoldContro","showFoldControl","_props$foldText","foldText","_props$unfoldText","unfoldText","_props$uiType","uiType","_props$truncateMode","truncateMode","maxHeight","_props$controlPlaceme","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","content","children","_useState","useState","ellipsis","setEllipsis","_useState2","getLineHeightFail","setGetLineHeightFail","_useSyncPropsState","useSyncPropsState","defaultValue","onChange","fold","setFold","_useState3","foldBtnWidth","setFoldBtnWidth","_useState4","endsWith","parseFloat","innerLineHeight","setInnerLineHeight","_useState5","_useState5$","innerLines","setInnerLines","_useState6","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","classNames","resetState","newEllipsis","_temp","_ref","_ref$forceResetFold","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","_ref3","measureRef","contentRect","abs"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/index.tsx"],"sourcesContent":["/**\n * @file 文本截断显示组件\n * @description 基于React封装一个文本截断显示组件,富文本(仅文字样式,图片和表格效果不一定好)同普通文本处理一致\n * @author <wuqiuyang305@126.com>\n */\n\nimport React, {\n forwardRef,\n useState,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n PropsWithChildren,\n MouseEvent,\n} from \"react\";\nimport {\n prefixClassname as p,\n classNames as cx,\n} from \"@ohkit/prefix-classname\";\nimport {\n assignRef,\n useRuntime,\n useCompatibleEffect,\n useSyncPropsState,\n} from \"@ohkit/react-helper\";\nimport {isSafari} from \"@ohkit/platform\";\nimport {Measure} from \"@ohkit/measure\";\nimport \"./style.scss\";\n\nexport const c = p(\"ohkit-text-ellipsis__\");\n\ninterface ITextEllipsis\n extends Pick<\n React.DOMAttributes<HTMLDivElement>,\n | \"onMouseEnter\"\n | \"onMouseLeave\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onClick\"\n > {\n /**\n * 自定义样式类名,会附加到根元素上\n */\n className?: string;\n /**\n * 自定义样式\n */\n style?: React.CSSProperties;\n /**\n * right | bottom 展开按钮在右下侧还是底部\n * @default right\n */\n uiType?: \"right\" | \"bottom\";\n /**\n * 截断模式 (若某些浏览器不支持 webkitLineClamp,可降级切换为 height 模式)\n * @default line\n */\n truncateMode?: \"line\" | \"height\";\n /**\n * truncateMode === \"height\" 时生效\n * 最大高度(number > 0),没传或者传入无效值不限制,尝试取 lines * lineHeight,若仍无效 自动截断到容器的最大高度\n * 单位: px\n */\n maxHeight?: number;\n /**\n * (单位:px)未传入或无效(0也视为无效)则自动取当前文本的行高\n */\n lineHeight?: React.CSSProperties[\"lineHeight\"];\n /**\n * truncateMode === \"line\" 时生效\n * 超过几行折叠(number > 0), 没传或者传入无效值不限制,自动截断到容器的最大高度\n */\n lines?: number;\n /**\n * 展开按钮蒙层背景色(仅支持16进制表示)\n * @default #fff\n */\n maskBgColor?: string;\n /**\n * text|ReactNode 与children任传一个\n */\n content?: React.ReactNode;\n /**\n * 当 content or children or ellipsis 变化时,重置 fold 状态 \n * @default false\n */\n resetFoldWhenChildrenOrEllipsisChange?: boolean;\n /**\n * 折叠状态\n * @default true\n */\n fold?: boolean;\n /**\n * 显示展开控制按钮\n * @default true\n */\n showFoldControl?: boolean;\n /**\n * 展开按钮位置 uiType='bottom'时有效\n * @default center\n */\n controlPlacement?: 'left' | 'center' | 'right';\n /**\n * 展开按钮文字\n * @default 收起\n */\n foldText?: string;\n /**\n * 展开按钮文字\n * @default 展开\n */\n unfoldText?: string;\n /**\n * 折叠状态下是否显示title属性\n * @default false\n */\n showTitleWhenFold?: boolean;\n /**\n * 折叠状态自定义title属性内容\n */\n titleWhenFold?: string | ((title: string) => string);\n /**\n * 是否保留换行\n */\n whiteSpace?: React.CSSProperties['whiteSpace'];\n /**\n * 容器宽度(默认自适应内容)\n * 应用场景:whiteSpace='pre*' 时,支持展示换行符,自适应内容可能导致控制按钮位置不确定\n */\n width?: React.CSSProperties['width'];\n /**\n * 自定义渲染展开按钮\n */\n renderFoldButton?: (fold: boolean) => React.ReactNode;\n /**\n * @param fold 折叠状态,true 折叠,false 展开\n */\n onFoldChange?: (fold: boolean) => void;\n /**\n * @param ellipsis 是否截断,true 截断,false 未截断\n */\n onEllipsisChange?: (ellipsis: boolean) => void;\n /**\n * 关键状态变更触发\n * @param status\n */\n onStatusChange?: (status: {\n fold: boolean;\n ellipsis: boolean;\n title?: string;\n }) => void;\n}\n\nexport type TextEllipsisProps = PropsWithChildren<ITextEllipsis>;\n\nexport const TextEllipsis = forwardRef<HTMLDivElement, TextEllipsisProps>((props, ref) => {\n const {\n className,\n style,\n lineHeight = \"\",\n lines,\n maskBgColor = \"#fff\",\n content,\n children,\n resetFoldWhenChildrenOrEllipsisChange = false,\n showTitleWhenFold,\n titleWhenFold,\n showFoldControl = true,\n foldText = \"收起\",\n unfoldText = \"展开\",\n uiType = \"right\",\n truncateMode = \"line\",\n maxHeight,\n controlPlacement = 'center',\n whiteSpace,\n width,\n renderFoldButton,\n onEllipsisChange,\n onFoldChange,\n onStatusChange,\n onMouseEnter,\n onMouseLeave,\n onPointerEnter,\n onPointerLeave,\n onClick,\n onFocus,\n } = props;\n const finalContent = content || children;\n // 是否截断\n const [ellipsis, setEllipsis] = useState(false);\n const [getLineHeightFail, setGetLineHeightFail] = useState(false);\n // 折叠状态\n const [fold, setFold] = useSyncPropsState(props, 'fold', {defaultValue: true, onChange: onFoldChange});\n const [foldBtnWidth, setFoldBtnWidth] = useState(1);\n const [innerLineHeight, setInnerLineHeight] = useState(\n typeof lineHeight === \"string\" && lineHeight.endsWith(\"px\")\n ? parseFloat(lineHeight)\n : 0\n );\n const [innerLines = 0, setInnerLines] = useState(lines);\n // children提取的纯文本\n const [textContent, setTextContent] = useState('');\n\n const [runtime] = useRuntime({\n inited: false, // mounted\n contentOffsetHeight: 0, // 内容节点offsetHeight\n containerContentHeight: 0, // 容器内容高度 = 容器高 - 上下padding\n ellipsis,\n defaultFold: fold, // 记录一下默认的折叠状态,用于 reset fold\n fold,\n foldBtnWidth,\n textContent,\n onEllipsisChange,\n onFoldChange,\n }, ['onEllipsisChange', 'fold', 'onFoldChange']);\n\n const contentRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const btnWrapperRef = useRef<HTMLDivElement>(null);\n\n const containerStyle = useMemo(() => {\n return {\n lineHeight: getLineHeightFail // 未传入且获取 lineHeight(px) 失败,则设置 default lineHeight: 1.4(em)\n ? \"1.4\" // more brower normal default lineHeight\n : lineHeight ? lineHeight : undefined,\n ...style,\n };\n }, [style, lineHeight, getLineHeightFail]);\n\n const commonWrapStyle = useMemo(() => {\n return {\n whiteSpace,\n width,\n };\n }, [whiteSpace, width])\n // 容器样式\n const wrapStyle = useMemo(() => {\n const lines = innerLines;\n const isHeightMode = truncateMode === 'height';\n if (!ellipsis || !isHeightMode && (!lines || !innerLineHeight)) {\n return commonWrapStyle;\n }\n const paddingBottom = showFoldControl && (uiType === \"bottom\" || !fold) ? `${innerLineHeight}px` : undefined;\n return {\n ...commonWrapStyle,\n // HACK: 兼容safari 15+ 富文本折叠高度丢失问题\n minHeight: !isHeightMode && fold ? `${(lines - 0.2) * innerLineHeight}px` : undefined,\n // Note: safari 对WebkitLineClamp支持太差劲 判断浏览器优雅降级为高度截断方案?目前先交给用户去判断,自行选择truncateMode\n // WebkitLineClamp: isSafari ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n // maxHeight: isSafari && fold ? lines * innerLineHeight : undefined,\n WebkitLineClamp: isHeightMode ? undefined : fold ? lines : undefined, // 利用-webkit-line-clamp截断方案\n maxHeight: isHeightMode && fold ? (maxHeight || lines * innerLineHeight || runtime.containerContentHeight || 0) : undefined,\n paddingBottom,\n boxSizing: paddingBottom ? 'border-box' as const : undefined,\n };\n }, [innerLines, innerLineHeight, ellipsis, fold, showFoldControl, uiType, truncateMode, maxHeight, commonWrapStyle]);\n\n // 展开|收起 按钮样式\n const btnStyle = useMemo(() => {\n if (!fold) {\n return;\n }\n // 按钮padding,取行高\n const padding = innerLineHeight;\n // 蒙层透明度所占比例\n const ratio = uiType === \"right\" ? Math.min((padding / foldBtnWidth) * 100, 80) : 60;\n // 16进制透明色(考虑简写方式), 不直接使用css的transparent是因为safari的表现是灰色\n const transparent = `${maskBgColor}${\n maskBgColor.length === 4 ? \"0\" : \"00\"\n }`;\n return {\n boxSizing: 'content-box' as const,\n height: `${innerLineHeight}px`,\n lineHeight: `${innerLineHeight}px`,\n paddingTop: uiType === \"bottom\" ? `${padding}px` : undefined,\n paddingLeft: uiType === \"right\" ? `${padding}px` : undefined,\n // 渐变蒙层\n background: `linear-gradient(to ${uiType}, ${transparent}, ${maskBgColor} ${ratio}%, ${maskBgColor} 100%)`,\n };\n }, [innerLineHeight, maskBgColor, fold, uiType, foldBtnWidth]);\n\n const reorganizeDom = useCallback(() => {\n // Note: safari 中仅改变 WebkitLineClamp 没触发重排,调整微小宽度以触发\n if (contentRef.current) {\n const orginStyleWidth = contentRef.current.style.width;\n const orginWidth = window.getComputedStyle(contentRef.current).width;\n // console.log('orginWidth, orginStyleWidth:', orginWidth, orginStyleWidth);\n contentRef.current.style.width = `${parseFloat(orginWidth) - 0.1}px`;\n window.requestAnimationFrame?.(() => {\n if (contentRef.current) {\n contentRef.current.style.width = orginStyleWidth;\n }\n });\n }\n }, []);\n\n const handleFoldChange = useCallback(\n (evt?: MouseEvent<HTMLDivElement>, fold = !runtime.fold) => {\n runtime.fold = fold;\n setFold(fold);\n }, []);\n\n const ButtonComp = useMemo(() => {\n return (\n <div\n className={cx(\n \"btn-fold-wrapper\",\n `btn-fold-wrapper-${uiType}`,\n uiType === \"bottom\" && `placement-${controlPlacement}`\n )}\n style={btnStyle}\n ref={btnWrapperRef}\n onClick={handleFoldChange}\n >\n {renderFoldButton ? (\n renderFoldButton(fold)\n ) : (\n <div className={\"btn-fold\"}>{fold ? unfoldText : foldText}</div>\n )}\n </div>\n );\n }, [\n btnStyle,\n fold,\n foldText,\n handleFoldChange,\n renderFoldButton,\n controlPlacement,\n uiType,\n unfoldText,\n ]);\n\n // 重置状态\n const resetState = useCallback((newEllipsis = runtime.ellipsis, {\n forceResetFold = false, // 强制重置fold 比如child变化时\n } = {}) => {\n const {ellipsis, fold: preFold, defaultFold} = runtime;\n if (newEllipsis !== ellipsis) {\n setEllipsis(newEllipsis);\n runtime.ellipsis = newEllipsis;\n runtime.onEllipsisChange?.(newEllipsis);\n }\n // 从未截断状态切换为截断状态时,自动折叠(即:出现展开按钮)\n if (\n resetFoldWhenChildrenOrEllipsisChange\n && (forceResetFold || !ellipsis && newEllipsis)\n && preFold !== defaultFold\n ) {\n handleFoldChange(undefined, defaultFold);\n }\n }, [handleFoldChange, finalContent, resetFoldWhenChildrenOrEllipsisChange]);\n\n const calcEllipsis = useCallback(() => {\n const wrapDom = wrapperRef.current;\n const containerDom = containerRef.current;\n if (!wrapDom || !containerDom) {\n return;\n }\n runtime.contentOffsetHeight = wrapDom.offsetHeight;\n const containerStyle = window.getComputedStyle(containerDom);\n const paddingTop = parseFloat(containerStyle.paddingTop);\n const paddingBottom = parseFloat(containerStyle.paddingBottom);\n const containerContentHeight = runtime.containerContentHeight = containerDom.clientHeight - paddingTop - paddingBottom;\n\n // 计算真实行高\n let realLineHeight = 0;\n // 若外部未传入, 尝试读取当前文本的行高。\n if (!realLineHeight && wrapDom) {\n const {lineHeight} = containerStyle || {};\n if (lineHeight) {\n // 未设置行高的为 normal\n realLineHeight = parseFloat(lineHeight);\n if (!realLineHeight) {\n setGetLineHeightFail(true);\n }\n }\n }\n // lineHeight同步到innerLineHeight\n if (innerLineHeight !== realLineHeight) {\n setInnerLineHeight(realLineHeight);\n if (!realLineHeight) {\n return;\n }\n }\n\n const isHeightMode = truncateMode === 'height';\n // 高度截断模式,比较简单 直接判断是否超出容器高度\n if (isHeightMode) {\n resetState(runtime.contentOffsetHeight > (maxHeight || containerContentHeight));\n return;\n }\n\n // 行数截断模式,需要利用行高计算是否超出容器高度\n if (!lines) {\n if (runtime.contentOffsetHeight > containerContentHeight) {\n const adjustLines = Math.floor(containerContentHeight / realLineHeight) || 1;\n if (innerLines !== adjustLines) {\n setInnerLines(adjustLines);\n }\n resetState(true);\n } else {\n resetState(false);\n }\n } else {\n if (innerLines !== lines) {\n setInnerLines(lines);\n }\n // console.log('contentOffsetHeight, realLineHeight', runtime.contentOffsetHeight, realLineHeight);\n // 允许误差1px(行高为小数时, safari计算行高*行数和实践总高有差异,故将行高向下取整兼容)\n resetState(runtime.contentOffsetHeight >= (lines + 1) * Math.floor(realLineHeight) - 1);\n }\n }, [lines, innerLineHeight, truncateMode, maxHeight, resetState]);\n\n // 监听内容高度,是否需要折叠\n // 用useLayoutEffect方式闪屏显示\n useCompatibleEffect(() => {\n resetState(runtime.ellipsis, {\n forceResetFold: true,\n });\n calcEllipsis();\n }, [calcEllipsis, resetState]);\n\n // 监听\"展开\"按钮宽度变化\n useEffect(() => {\n if (ellipsis && btnWrapperRef.current) {\n const {offsetWidth} = btnWrapperRef.current;\n if (offsetWidth !== runtime.foldBtnWidth) {\n runtime.foldBtnWidth = offsetWidth;\n setFoldBtnWidth(offsetWidth);\n }\n }\n }, [ellipsis, unfoldText, showFoldControl]);\n useEffect(() => {\n if (isSafari) {\n reorganizeDom();\n }\n }, [fold, reorganizeDom]);\n const updateTextContent = useCallback(() => {\n const newTextContent = wrapperRef.current?.textContent || '';\n if (newTextContent !== runtime.textContent) {\n runtime.textContent = newTextContent;\n setTextContent(newTextContent);\n }\n }, []);\n const hoverTitle = useMemo(() => {\n return ellipsis && fold\n ? (typeof titleWhenFold === 'function'\n ? titleWhenFold(textContent)\n : titleWhenFold || textContent)\n : undefined;\n }, [titleWhenFold, ellipsis, fold, textContent]);\n useEffect(() => {\n if (runtime.inited) { \n onStatusChange?.({\n ellipsis,\n fold,\n title: hoverTitle\n });\n }\n }, [onStatusChange, fold, ellipsis, hoverTitle]);\n useEffect(() => {\n runtime.inited = true;\n }, []);\n // 高度自适应,容器高度变化时重新计算高度(容器也需要包装Measure,TODO: 待开发 hooks -> useMeasure, 使得观测dom尺寸的方式更简洁)\n // if (!maxHeight && !lines) {\n // calcEllipsis();\n // }\n // console.log('[render TextEllipsis]: ellipsis fold wrapStyle: ', ellipsis, fold, wrapStyle);\n return (\n <div\n className={cx(c(\"container\"), className)}\n style={containerStyle}\n ref={(r) => {\n assignRef(containerRef, r);\n ref && assignRef(ref, r);\n }}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onFocus={onFocus}\n >\n {/* 此dom仅用于计算高度 用.text-ellipsis-inner计算 在不重新初始化情况下切换文本时高度计算有问题 */}\n <Measure offset>\n {({measureRef, contentRect}) => {\n // console.log('contentRect:', contentRect.offset?.height, runtime.contentOffsetHeight);\n const {height} = contentRect.offset || {};\n if (height !== undefined && Math.abs(height - runtime.contentOffsetHeight) > 1) {\n calcEllipsis();\n }\n return <div style={commonWrapStyle} className={\"content-shadow-dom\"} ref={(r) => {\n assignRef(measureRef, r);\n assignRef(wrapperRef, r);\n updateTextContent();\n }}>\n {finalContent}\n </div>\n }}\n </Measure>\n {/* <div className={\"content-shadow-dom\"} ref={wrapperRef}>\n {finalContent}\n </div> */}\n {/* 主文本显示 */}\n <div\n className={\"text-ellipsis-inner\"}\n title={showTitleWhenFold ? hoverTitle : undefined}\n style={wrapStyle}\n ref={contentRef}\n >\n {/* {finalContent} */}\n {/* firefox >= 133 绝对定位的按钮放文本后面也会被截断隐藏!! , 放文本前面可解决 */}\n {ellipsis && showFoldControl && ButtonComp}\n {finalContent}\n </div>\n </div>\n );\n});\n"],"names":["c","p","prefixClassname","TextEllipsis","forwardRef","props","ref","className","style","_props$lineHeight","lineHeight","lines","_props$maskBgColor","maskBgColor","_props$resetFoldWhenC","resetFoldWhenChildrenOrEllipsisChange","showTitleWhenFold","titleWhenFold","_props$showFoldContro","showFoldControl","_props$foldText","foldText","_props$unfoldText","unfoldText","_props$uiType","uiType","_props$truncateMode","truncateMode","maxHeight","_props$controlPlaceme","controlPlacement","whiteSpace","width","renderFoldButton","onEllipsisChange","onFoldChange","onStatusChange","onMouseEnter","onMouseLeave","onPointerEnter","onPointerLeave","onClick","onFocus","finalContent","content","children","_useState","useState","ellipsis","setEllipsis","_useState2","getLineHeightFail","setGetLineHeightFail","_useSyncPropsState","useSyncPropsState","defaultValue","onChange","fold","setFold","_useState3","foldBtnWidth","setFoldBtnWidth","_useState4","endsWith","parseFloat","innerLineHeight","setInnerLineHeight","_useState5","_useState5$","innerLines","setInnerLines","_useState6","textContent","setTextContent","runtime","useRuntime","inited","contentOffsetHeight","containerContentHeight","defaultFold","contentRef","useRef","wrapperRef","containerRef","btnWrapperRef","containerStyle","useMemo","_extends","undefined","commonWrapStyle","wrapStyle","isHeightMode","paddingBottom","minHeight","WebkitLineClamp","boxSizing","btnStyle","padding","ratio","Math","min","height","paddingTop","paddingLeft","background","transparent","length","reorganizeDom","useCallback","current","orginStyleWidth","orginWidth","window","getComputedStyle","requestAnimationFrame","handleFoldChange","evt","ButtonComp","React","createElement","cx","classNames","resetState","newEllipsis","_temp","_ref$forceResetFold","forceResetFold","preFold","calcEllipsis","wrapDom","containerDom","offsetHeight","clientHeight","realLineHeight","floor","adjustLines","useCompatibleEffect","useEffect","offsetWidth","isSafari","updateTextContent","_wrapperRef$current","newTextContent","hoverTitle","title","r","assignRef","Measure","offset","_ref3","measureRef","contentRect","abs"],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
  * @author <wuqiuyang305@126.com>
5
5
  */
6
6
  import React, { PropsWithChildren } from "react";
7
- import { classNames as cx } from "@ohkit/utils";
7
+ import { classNames as cx } from "@ohkit/prefix-classname";
8
8
  import "./style.scss";
9
9
  export declare const c: (...arg: cx.ArgumentArray) => string;
10
10
  interface ITextEllipsis extends Pick<React.DOMAttributes<HTMLDivElement>, "onMouseEnter" | "onMouseLeave" | "onPointerEnter" | "onPointerLeave" | "onFocus" | "onClick"> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohkit/text-ellipsis",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "text ellipsis for react",
5
5
  "keywords": [
6
6
  "text ellipsis"
@@ -32,8 +32,10 @@
32
32
  "clean": "rm -rf dist"
33
33
  },
34
34
  "dependencies": {
35
- "@ohkit/measure": "0.0.3",
36
- "@ohkit/utils": "0.0.3"
35
+ "@ohkit/measure": "^0.0.3",
36
+ "@ohkit/platform": "0.0.3",
37
+ "@ohkit/prefix-classname": "0.0.3",
38
+ "@ohkit/react-helper": "0.0.4"
37
39
  },
38
40
  "devDependencies": {
39
41
  "react": "^18.3.1",
@@ -43,5 +45,5 @@
43
45
  "react": ">=16.8.0",
44
46
  "react-dom": ">=16.8.0"
45
47
  },
46
- "gitHead": "0b9cb51d650f932fca8d4365dad030951ee84cdf"
48
+ "gitHead": "3fb061e6a6bf7ccd9f26f0339080da0a4df02075"
47
49
  }
package/src/index.tsx CHANGED
@@ -15,15 +15,17 @@ import React, {
15
15
  MouseEvent,
16
16
  } from "react";
17
17
  import {
18
- isSafari,
19
18
  prefixClassname as p,
20
19
  classNames as cx,
20
+ } from "@ohkit/prefix-classname";
21
+ import {
21
22
  assignRef,
22
23
  useRuntime,
23
24
  useCompatibleEffect,
24
25
  useSyncPropsState,
25
- } from "@ohkit/utils";
26
- import { Measure } from "@ohkit/measure";
26
+ } from "@ohkit/react-helper";
27
+ import {isSafari} from "@ohkit/platform";
28
+ import {Measure} from "@ohkit/measure";
27
29
  import "./style.scss";
28
30
 
29
31
  export const c = p("ohkit-text-ellipsis__");