Skip to content

Instantly share code, notes, and snippets.

@zaaack
Last active October 6, 2022 14:08
Show Gist options
  • Save zaaack/9804e88aaff1624b38f06940c5523b9e to your computer and use it in GitHub Desktop.
Save zaaack/9804e88aaff1624b38f06940c5523b9e to your computer and use it in GitHub Desktop.
react-shave.js (ellipsis)
// @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