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

View File

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

View File

@ -5,11 +5,38 @@ import Preview from './preview'
import Category from './category'
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) {
var { preview } = this.refs
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() {
var { perLine, emojiSize, sheetURL } = this.props
@ -18,20 +45,22 @@ export default class Picker extends React.Component {
Categories
</div>
<div ref="scroll" className='emoji-picker-scroll'>
<div ref="scroll" className='emoji-picker-scroll' onScroll={this.handleScroll.bind(this)}>
<input
type='text'
placeholder='Search'
className='emoji-picker-search'
/>
{data.categories.map((category) => {
{data.categories.map((category, i) => {
if (category.name == 'Skins') return null
return <Category
ref={`category-${i}`}
key={category.name}
name={category.name}
emojis={category.emojis}
perLine={perLine}
hasStickyPosition={this.hasStickyPosition}
emojiProps={{
size: emojiSize,
sheetURL: sheetURL,