Sticky categories label

release
Etienne Lemay 2016-05-31 12:35:08 -04:00
parent e108b00768
commit 21bb9eb63e
3 changed files with 96 additions and 20 deletions

View File

@ -8,7 +8,7 @@
font-size: 16px; font-size: 16px;
display: inline-block; display: inline-block;
color: #222427; color: #222427;
border: 1px solid rgba(0, 0, 0, .15); border: 1px solid #d9d9d9;
border-radius: 5px; border-radius: 5px;
} }
@ -28,8 +28,8 @@
.emoji-picker-scroll { .emoji-picker-scroll {
overflow: scroll; overflow: scroll;
max-height: 270px; max-height: 270px;
padding: 6px; padding: 0 6px 6px 6px;
border: solid rgba(0, 0, 0, .15); border: solid #d9d9d9;
border-width: 1px 0; border-width: 1px 0;
} }
@ -38,8 +38,9 @@
display: block; display: block;
width: 100%; width: 100%;
padding: .2em .6em; padding: .2em .6em;
margin-top: 6px;
border-radius: 25px; border-radius: 25px;
border: 1px solid rgba(0, 0, 0, .15); border: 1px solid #d9d9d9;
outline: 0; outline: 0;
} }
@ -48,8 +49,17 @@
} }
.emoji-picker-category-label { .emoji-picker-category-label {
position: relative;
position: -webkit-sticky;
top: 0;
}
.emoji-picker-category-label span {
display: block;
width: 100%;
font-weight: bold; font-weight: bold;
padding: 5px 6px; padding: 5px 6px;
background-color: #fff;
background-color: rgba(255, 255, 255, .95); background-color: rgba(255, 255, 255, .95);
} }

View File

@ -2,32 +2,67 @@ import React from 'react'
import Emoji from './emoji' import Emoji from './emoji'
export default class Category extends React.Component { export default class Category extends React.Component {
shouldComponentUpdate(props) { componentDidMount() {
if (props.perLine != this.props.perLine) { this.container = this.refs.container
return true this.label = this.refs.label
this.parent = this.container.parentNode
this.margin = 0
this.minMargin = 0
this.memoizeSize()
} }
for (let k in props.emojiProps) { componentDidUpdate() {
if (props.emojiProps[k] != this.props.emojiProps[k]) { this.memoizeSize()
return true
}
} }
return false memoizeSize() {
var { top, height } = this.container.getBoundingClientRect()
var { top: parentTop } = this.parent.getBoundingClientRect()
var { height: labelHeight } = this.label.getBoundingClientRect()
this.top = top - parentTop + this.parent.scrollTop
this.maxMargin = height - labelHeight
}
handleScroll(scrollTop) {
var margin = scrollTop - this.top
margin = margin < this.minMargin ? this.minMargin : margin
margin = margin > this.maxMargin ? this.maxMargin : margin
if (margin == this.margin) return
this.label.style.top = `${margin}px`
this.margin = margin
} }
render() { render() {
var { name, emojis, perLine, emojiProps } = this.props, var { name, emojis, perLine, hasStickyPosition, emojiProps } = this.props,
emojis = emojis.slice(0), emojis = emojis.slice(0),
lines = [], lines = [],
linesCount = Math.ceil(emojis.length / perLine) linesCount = Math.ceil(emojis.length / perLine),
labelStyles = {},
labelSpanStyles = {}
Array(linesCount).fill().forEach((_, i) => Array(linesCount).fill().forEach((_, i) =>
lines.push(emojis.splice(0, perLine)) lines.push(emojis.splice(0, perLine))
) )
return <div className='emoji-picker-category'> if (!hasStickyPosition) {
<div className='emoji-picker-category-label'>{name}</div> labelStyles = {
height: 28,
}
labelSpanStyles = {
position: 'absolute',
}
}
return <div ref='container' className='emoji-picker-category'>
<div style={labelStyles} data-name={name} className='emoji-picker-category-label'>
<span style={labelSpanStyles} ref='label'>{name}</span>
</div>
{lines.map((emojis, i) => {lines.map((emojis, i) =>
<div key={`line-${i}`}> <div key={`line-${i}`}>
{emojis.map((emoji) => {emojis.map((emoji) =>
@ -45,6 +80,7 @@ export default class Category extends React.Component {
Category.propTypes = { Category.propTypes = {
emojis: React.PropTypes.array, emojis: React.PropTypes.array,
hasStickyPosition: React.PropTypes.bool,
name: React.PropTypes.string.isRequired, name: React.PropTypes.string.isRequired,
perLine: React.PropTypes.number.isRequired, perLine: React.PropTypes.number.isRequired,
emojiProps: React.PropTypes.object.isRequired, emojiProps: React.PropTypes.object.isRequired,
@ -52,4 +88,5 @@ Category.propTypes = {
Category.defaultProps = { Category.defaultProps = {
emojis: [], emojis: [],
hasStickyPosition: true,
} }

View File

@ -5,11 +5,38 @@ import Preview from './preview'
import Category from './category' import Category from './category'
export default class Picker extends React.Component { export default class Picker extends React.Component {
componentWillMount() {
var stickyTestElement = document.createElement('div')
for (let prefix of ['', '-webkit-', '-ms-', '-moz-', '-o-']) {
stickyTestElement.style.position = `${prefix}sticky`
}
this.hasStickyPosition = !!stickyTestElement.style.position.length
}
componentDidUpdate() {
this.handleScroll()
}
handleEmojiOver(emoji) { handleEmojiOver(emoji) {
var { preview } = this.refs var { preview } = this.refs
preview.setState({ emoji: emoji }) preview.setState({ emoji: emoji })
} }
handleScroll() {
var target = this.refs.scroll,
scrollTop = target.scrollTop
if (!this.hasStickyPosition) {
Array(data.categories.length).fill().forEach((_, i) => {
var category = this.refs[`category-${i}`]
if (category) {
category.handleScroll(scrollTop)
}
})
}
}
render() { render() {
var { perLine, emojiSize, sheetURL } = this.props var { perLine, emojiSize, sheetURL } = this.props
@ -18,20 +45,22 @@ export default class Picker extends React.Component {
Categories Categories
</div> </div>
<div ref="scroll" className='emoji-picker-scroll'> <div ref="scroll" className='emoji-picker-scroll' onScroll={this.handleScroll.bind(this)}>
<input <input
type='text' type='text'
placeholder='Search' placeholder='Search'
className='emoji-picker-search' className='emoji-picker-search'
/> />
{data.categories.map((category) => { {data.categories.map((category, i) => {
if (category.name == 'Skins') return null if (category.name == 'Skins') return null
return <Category return <Category
ref={`category-${i}`}
key={category.name} key={category.name}
name={category.name} name={category.name}
emojis={category.emojis} emojis={category.emojis}
perLine={perLine} perLine={perLine}
hasStickyPosition={this.hasStickyPosition}
emojiProps={{ emojiProps={{
size: emojiSize, size: emojiSize,
sheetURL: sheetURL, sheetURL: sheetURL,