Last active
October 6, 2022 14:08
-
-
Save zaaack/9804e88aaff1624b38f06940c5523b9e to your computer and use it in GitHub Desktop.
react-shave.js (ellipsis)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import shave from 'shave' | |
import { h, Component } from 'preact' | |
import shallowCompare from 'shallow-compare' | |
type Props = { | |
line?: number, | |
text: string, | |
ellipsis?: string, | |
onEllipsisClick?: ?MouseEventListener, | |
} | |
export default class ReactShave extends Component { | |
props: Props = { | |
line: 3, | |
text: '', | |
ellipsis: '...', | |
} | |
_scope: HTMLElement | |
_lastEllipsisClick: ?MouseEventListener | |
shouldComponentUpdate(nextProps: Props, nextState: *) { | |
return shallowCompare(this, nextProps, nextState) | |
} | |
componentDidMount() { | |
this.update() | |
} | |
componentDidUpdate() { | |
this.update() | |
} | |
getMaxHeight() { | |
const { line } = this.props | |
const style = getComputedStyle(this._scope) | |
let lineh = style.getPropertyValue('line-height') | |
const fontSize = parseInt(style.getPropertyValue('font-size'), 10) | |
if ((!lineh && lineh !== 0) || String('normal|initial|inherit').indexOf(lineh) > -1) { | |
lineh = fontSize * 1.4 // 1.4, normal line-height of chrome, but safari has a bug, getComputedStyle(el)['line-height'] would return a wrong number 16px for font-size: 13px and is different from reality, so I just set back. | |
} else if (String(lineh).match(/^[\d.]*$/)) { | |
lineh = (fontSize * lineh) + 'px' | |
} | |
if (this._scope.style.lineHeight !== lineh) { | |
this._scope.style.lineHeight = String(lineh) | |
} | |
return parseFloat(lineh, 10) * (line + 0.5) // fix other round issue | |
} | |
updateRootHeight() { | |
const maxHeight = this.getMaxHeight() | |
if (this._scope.offsetHeight > maxHeight) { | |
(this._scope.parentElement: any).style.maxHeight = maxHeight + 'px' | |
} | |
} | |
update() { | |
const { ellipsis, onEllipsisClick } = this.props | |
// this.updateRootHeight() | |
setTimeout(() => { | |
this.updateRootHeight() | |
const maxHeight = this.getMaxHeight() | |
if (this._scope.offsetHeight > maxHeight) { | |
shave(this._scope, maxHeight, { | |
character: ellipsis, | |
spaces: false, | |
}) | |
} | |
const ellipsisEL = this._scope.querySelector('.js-shave-char') | |
if (this._lastEllipsisClick && ellipsisEL) { | |
ellipsisEL.removeEventListener('click', this._lastEllipsisClick) | |
} | |
if (ellipsisEL && onEllipsisClick) { | |
ellipsisEL.addEventListener('click', onEllipsisClick) | |
} | |
this._lastEllipsisClick = onEllipsisClick | |
}) | |
} | |
render() { | |
const { | |
text, onEllipsisClick, ellipsis, line, | |
...otherProps | |
} = this.props | |
return ( | |
<div style={{ overflow: 'hidden' }}> | |
<div ref={c => (this._scope = c)} {...otherProps}> | |
{text} | |
</div> | |
</div> | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment