Merge pull request #206 from Rena-Ryumae/rena/customnotfound

Not Found Component for emoji search
release
Etienne Lemay 2018-07-30 17:11:44 -04:00 committed by GitHub
commit 767b2fdcc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 94 additions and 21 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -50,6 +50,8 @@ import { Picker } from 'emoji-mart'
| **defaultSkin** | | `1` | Default skin color: `1, 2, 3, 4, 5, 6` | | **defaultSkin** | | `1` | Default skin color: `1, 2, 3, 4, 5, 6` |
| **style** | | | Inline styles applied to the root element. Useful for positioning | | **style** | | | Inline styles applied to the root element. Useful for positioning |
| **title** | | `Emoji Mart™` | The title shown when no emojis are hovered | | **title** | | `Emoji Mart™` | The title shown when no emojis are hovered |
| **notFoundEmoji** | | `sleuth_or_spy` | The emoji shown when there are no search results |
| **notFound** | | | [Not Found](#not-found) |
#### I18n #### I18n
```js ```js
@ -234,6 +236,17 @@ const customEmojis = [
<Picker custom={customEmojis} /> <Picker custom={customEmojis} />
``` ```
## Not Found
You can provide a custom Not Found object which will allow the appearance of the not found search results to change. In this case, we change the default 'sleuth_or_spy' emoji to Octocat when our search finds no results.
```js
import { Picker } from 'emoji-mart'
const notFound = () => <img src='https://assets-cdn.github.com/images/icons/emoji/octocat.png?v7' />
<Picker notFound={notFound} />
```
## Headless search ## Headless search
The `Picker` doesnt have to be mounted for you to take advantage of the advanced search results. The `Picker` doesnt have to be mounted for you to take advantage of the advanced search results.

View File

@ -160,6 +160,12 @@
padding-top: 70px; padding-top: 70px;
color: #858585; color: #858585;
} }
.emoji-mart-no-results-img {
display: block;
margin-left: auto;
margin-right: auto;
width: 50%;
}
.emoji-mart-no-results .emoji-mart-category-label { .emoji-mart-no-results .emoji-mart-category-label {
display: none; display: none;
} }

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import frequently from '../utils/frequently' import frequently from '../utils/frequently'
import { getData } from '../utils' import { getData } from '../utils'
import { NimbleEmoji } from '.' import { NimbleEmoji, NotFound } from '.'
export default class Category extends React.Component { export default class Category extends React.Component {
constructor(props) { constructor(props) {
@ -144,7 +144,15 @@ export default class Category extends React.Component {
} }
render() { render() {
var { id, name, hasStickyPosition, emojiProps, i18n } = this.props, var {
id,
name,
hasStickyPosition,
emojiProps,
i18n,
notFound,
notFoundEmoji,
} = this.props,
emojis = this.getEmojis(), emojis = this.getEmojis(),
labelStyles = {}, labelStyles = {},
labelSpanStyles = {}, labelSpanStyles = {},
@ -169,9 +177,7 @@ export default class Category extends React.Component {
return ( return (
<div <div
ref={this.setContainerRef} ref={this.setContainerRef}
className={`emoji-mart-category ${ className="emoji-mart-category"
emojis && !emojis.length ? 'emoji-mart-no-results' : ''
}`}
style={containerStyles} style={containerStyles}
> >
<div <div
@ -191,21 +197,13 @@ export default class Category extends React.Component {
{emojis && {emojis &&
!emojis.length && ( !emojis.length && (
<div> <NotFound
<div> i18n={i18n}
{NimbleEmoji({ notFound={notFound}
data: this.data, notFoundEmoji={notFoundEmoji}
...emojiProps, data={this.data}
size: 38, emojiProps={emojiProps}
emoji: 'sleuth_or_spy', />
onOver: null,
onLeave: null,
onClick: null,
})}
</div>
<div className="emoji-mart-no-results-label">{i18n.notfound}</div>
</div>
)} )}
</div> </div>
) )
@ -220,6 +218,8 @@ Category.propTypes = {
perLine: PropTypes.number.isRequired, perLine: PropTypes.number.isRequired,
emojiProps: PropTypes.object.isRequired, emojiProps: PropTypes.object.isRequired,
recent: PropTypes.arrayOf(PropTypes.string), recent: PropTypes.arrayOf(PropTypes.string),
notFound: PropTypes.func,
notFoundEmoji: PropTypes.string.isRequired,
} }
Category.defaultProps = { Category.defaultProps = {

View File

@ -1,6 +1,7 @@
export { default as Anchors } from './anchors' export { default as Anchors } from './anchors'
export { default as Category } from './category' export { default as Category } from './category'
export { default as Preview } from './preview' export { default as Preview } from './preview'
export { default as NotFound } from './not-found'
export { default as Search } from './search' export { default as Search } from './search'
export { default as Skins } from './skins' export { default as Skins } from './skins'

View File

@ -0,0 +1,32 @@
import React from 'react'
import PropTypes from 'prop-types'
import { NimbleEmoji } from '.'
export default class NotFound extends React.PureComponent {
render() {
const { data, emojiProps, i18n, notFound, notFoundEmoji } = this.props
const component = (notFound && notFound()) || (
<div className="emoji-mart-no-results">
{NimbleEmoji({
data: data,
...emojiProps,
size: 38,
emoji: notFoundEmoji,
onOver: null,
onLeave: null,
onClick: null,
})}
<div className="emoji-mart-no-results-label">{i18n.notfound}</div>
</div>
)
return component
}
}
NotFound.propTypes = {
notFound: PropTypes.func.isRequired,
notFoundString: PropTypes.string.isRequired,
emojiProps: PropTypes.object.isRequired,
}

View File

@ -467,6 +467,8 @@ export default class NimblePicker extends React.PureComponent {
exclude, exclude,
recent, recent,
autoFocus, autoFocus,
notFound,
notFoundEmoji,
} = this.props, } = this.props,
{ skin } = this.state, { skin } = this.state,
width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar() width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar()
@ -539,6 +541,8 @@ export default class NimblePicker extends React.PureComponent {
onLeave: this.handleEmojiLeave, onLeave: this.handleEmojiLeave,
onClick: this.handleEmojiClick, onClick: this.handleEmojiClick,
}} }}
notFound={notFound}
notFoundEmoji={notFoundEmoji}
/> />
) )
})} })}

View File

@ -71,6 +71,8 @@ const PickerPropTypes = {
imageUrl: PropTypes.string.isRequired, imageUrl: PropTypes.string.isRequired,
}), }),
), ),
notFound: PropTypes.func,
notFoundEmoji: PropTypes.string,
} }
const PickerDefaultProps = { const PickerDefaultProps = {
@ -96,6 +98,8 @@ const PickerDefaultProps = {
emojiTooltip: EmojiDefaultProps.tooltip, emojiTooltip: EmojiDefaultProps.tooltip,
autoFocus: false, autoFocus: false,
custom: [], custom: [],
notFound: () => {},
notFoundEmoji: 'sleuth_or_spy',
} }
export { export {

View File

@ -36,11 +36,24 @@ storiesOf('Picker', module)
perLine={number('Per line', 9)} perLine={number('Per line', 9)}
title={text('Idle text', 'Your Title Here')} title={text('Idle text', 'Your Title Here')}
emoji={text('Idle emoji', 'department_store')} emoji={text('Idle emoji', 'department_store')}
notFoundEmoji={text('Not found emoji', 'sleuth_or_spy')}
defaultSkin={number('Default skin tone', 1)} defaultSkin={number('Default skin tone', 1)}
color={color('Highlight color', '#ae65c5')} color={color('Highlight color', '#ae65c5')}
showPreview={boolean('Show preview', true)} showPreview={boolean('Show preview', true)}
showSkinTones={boolean('Show skin tones', true)} showSkinTones={boolean('Show skin tones', true)}
custom={CUSTOM_EMOJIS} custom={CUSTOM_EMOJIS}
/>))
.add('with a custom not found image', () => (
<Picker
notFound={
() => <img src='https://assets-cdn.github.com/images/icons/emoji/octocat.png?v7' />
}
/>))
.add('with a custom not found SVG', () => (
<Picker
notFound={
() => <svg aria-labelledby="simpleicons-jira-icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title id="simpleicons-jira-icon">Jira icon</title><path d="M23.323 11.33L13.001 1 12 0 4.225 7.775.67 11.33a.96.96 0 0 0 0 1.347l7.103 7.103L12 24l7.771-7.771.121-.121 3.431-3.431a.945.945 0 0 0 0-1.347zM12 15.551L8.449 12 12 8.453 15.548 12 12 15.551z"/></svg>
}
/> />
)); ));