From f1d5bc00956e0e64ad30a955cf672fa7e1f890de Mon Sep 17 00:00:00 2001 From: Rena Ryumae Date: Thu, 5 Jul 2018 17:00:57 -0400 Subject: [PATCH] Custom emoji for skin tone selector Currently, the skin tone selector is a row of colored dots We propose creating a skinIcon field that uses the emoji-mart dots on default but otherwise uses the emoji passed in by the user --- css/emoji-mart.css | 76 ++++++++++++++++++++++++-- src/components/index.js | 2 + src/components/picker/nimble-picker.js | 4 ++ src/components/preview.js | 26 ++++++++- src/components/skins-dot.js | 50 +++++++++++++++++ src/components/skins-emoji.js | 72 ++++++++++++++++++++++++ src/components/skins.js | 42 +------------- src/utils/shared-props.js | 2 + stories/index.js | 8 ++- 9 files changed, 234 insertions(+), 48 deletions(-) create mode 100644 src/components/skins-dot.js create mode 100644 src/components/skins-emoji.js diff --git a/css/emoji-mart.css b/css/emoji-mart.css index 93e62d7..b64dfff 100644 --- a/css/emoji-mart.css +++ b/css/emoji-mart.css @@ -181,6 +181,11 @@ text-align: right; } +.emoji-mart-preview-skins.custom { + right: 10px; + text-align: right; +} + .emoji-mart-preview-name { font-size: 14px; } @@ -223,12 +228,18 @@ background-color: #fff; } -.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch { +.emoji-mart-skin-swatches.custom { + font-size: 0; + border: none; + background-color: #fff; +} + +.emoji-mart-skin-swatches.opened .emoji-mart-skin-swatch { width: 16px; padding: 0 2px; } -.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch-selected:after { +.emoji-mart-skin-swatches.opened .emoji-mart-skin-swatch.selected:after { opacity: .75; } @@ -248,12 +259,13 @@ .emoji-mart-skin-swatch:nth-child(5) { transition-delay: .12s } .emoji-mart-skin-swatch:nth-child(6) { transition-delay: .15s } -.emoji-mart-skin-swatch-selected { +.emoji-mart-skin-swatch.selected { position: relative; width: 16px; padding: 0 2px; } -.emoji-mart-skin-swatch-selected:after { + +.emoji-mart-skin-swatch.selected:after { content: ""; position: absolute; top: 50%; left: 50%; @@ -266,9 +278,63 @@ transition: opacity .2s ease-out; } +.emoji-mart-skin-swatch.custom { + display: inline-block; + width: 0; + height: 38px; + overflow: hidden; + vertical-align: middle; + transition-property: width, height; + transition-duration: .125s; + transition-timing-function: ease-out; + cursor: default; +} + +.emoji-mart-skin-swatch.custom.selected { + position: relative; + width: 36px; + height: 38px; + padding: 0 2px 0 0; +} + +.emoji-mart-skin-swatch.custom.selected:after { + content: ""; + width: 0; + height: 0; +} + +.emoji-mart-skin-swatches.custom .emoji-mart-skin-swatch.custom:hover { + background-color: #f4f4f4; + border-radius: 10%; +} + +.emoji-mart-skin-swatches.custom.opened .emoji-mart-skin-swatch.custom { + width: 36px; + height: 38px; + padding: 0 2px 0 0; +} + +.emoji-mart-skin-swatches.custom.opened .emoji-mart-skin-swatch.custom.selected:after { + opacity: .75; +} + +.emoji-mart-skin-text.opened { + display: inline-block; + vertical-align: middle; + text-align: left; + color: #888; + font-size: 11px; + padding: 5px 2px; + width: 30%; + height: 40px; + border-radius: 10%; + background-color: #fff; +} + .emoji-mart-skin { display: inline-block; - width: 100%; padding-top: 100%; + width: 100%; + padding-top: 100%; max-width: 12px; border-radius: 100%; } diff --git a/src/components/index.js b/src/components/index.js index 2f59995..6b02d17 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -3,6 +3,8 @@ export { default as Category } from './category' export { default as Preview } from './preview' export { default as Search } from './search' export { default as Skins } from './skins' +export { default as SkinsEmoji } from './skins-emoji' +export { default as SkinsDot } from './skins-dot' export { default as Emoji } from './emoji/emoji' export { default as NimbleEmoji } from './emoji/nimble-emoji' diff --git a/src/components/picker/nimble-picker.js b/src/components/picker/nimble-picker.js index 20586e1..0f8c244 100644 --- a/src/components/picker/nimble-picker.js +++ b/src/components/picker/nimble-picker.js @@ -14,6 +14,7 @@ import { Anchors, Category, Preview, Search } from '..' const I18N = { search: 'Search', notfound: 'No Emoji Found', + skintext: 'Choose your default skin tone ', categories: { search: 'Search Results', recent: 'Frequently Used', @@ -467,6 +468,7 @@ export default class NimblePicker extends React.PureComponent { exclude, recent, autoFocus, + skinIcon, } = this.props, { skin } = this.state, width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar() @@ -563,7 +565,9 @@ export default class NimblePicker extends React.PureComponent { skinsProps={{ skin: skin, onChange: this.handleSkinChange, + skinIcon: skinIcon, }} + i18n={this.i18n} /> )} diff --git a/src/components/preview.js b/src/components/preview.js index a484055..f01c26b 100644 --- a/src/components/preview.js +++ b/src/components/preview.js @@ -2,7 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import { getData } from '../utils' -import { NimbleEmoji, Skins } from '.' +import { NimbleEmoji, SkinsEmoji, SkinsDot } from '.' export default class Preview extends React.PureComponent { constructor(props) { @@ -20,6 +20,7 @@ export default class Preview extends React.PureComponent { showSkinTones, title, emoji: idleEmoji, + i18n, } = this.props if (emoji) { @@ -81,8 +82,27 @@ export default class Preview extends React.PureComponent { {showSkinTones && ( -
- +
+ {skinsProps.skinIcon ? ( + + ) : ( + + )}
)}
diff --git a/src/components/skins-dot.js b/src/components/skins-dot.js new file mode 100644 index 0000000..bc923ff --- /dev/null +++ b/src/components/skins-dot.js @@ -0,0 +1,50 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { Skins } from '.' + +export default class SkinsDot extends Skins { + constructor(props) { + super(props) + + this.handleClick = this.handleClick.bind(this) + } + + render() { + const { skin, i18n } = this.props + const { opened } = this.state + const skinToneNodes = [] + + for (let skinTone = 1; skinTone <= 6; skinTone++) { + const selected = skinTone === skin + skinToneNodes.push( + + + , + ) + } + + return ( +
+ {skinToneNodes} +
+ ) + } +} + +SkinsDot.propTypes = { + onChange: PropTypes.func, + skin: PropTypes.number.isRequired, + i18n: PropTypes.object, +} + +SkinsDot.defaultProps = { + onChange: () => {}, +} diff --git a/src/components/skins-emoji.js b/src/components/skins-emoji.js new file mode 100644 index 0000000..8699120 --- /dev/null +++ b/src/components/skins-emoji.js @@ -0,0 +1,72 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { NimbleEmoji, Skins } from '.' + +export default class SkinsEmoji extends Skins { + constructor(props) { + super(props) + + this.handleClick = this.handleClick.bind(this) + } + + render() { + const { skin, emojiProps, data, skinIcon, i18n } = this.props + const { opened } = this.state + const skinToneNodes = [] + + for (let skinTone = 1; skinTone <= 6; skinTone++) { + const selected = skinTone === skin + skinToneNodes.push( + + + {NimbleEmoji({ + emoji: skinIcon, + data: data, + skin: skinTone, + backgroundImageFn: emojiProps.backgroundImageFn, + native: emojiProps.native, + set: emojiProps.set, + sheetSize: emojiProps.sheetSize, + size: 23, + })} + + , + ) + } + + return ( +
+
+ {i18n.skintext} +
+ {skinToneNodes} +
+ ) + } +} + +SkinsEmoji.propTypes = { + onChange: PropTypes.func, + skin: PropTypes.number.isRequired, + emojiProps: PropTypes.object.isRequired, + skinTone: PropTypes.number, + skinIcon: PropTypes.string.isRequired, + i18n: PropTypes.object, +} + +SkinsEmoji.defaultProps = { + onChange: () => {}, + skinTone: null, +} diff --git a/src/components/skins.js b/src/components/skins.js index 1430c50..51942bb 100644 --- a/src/components/skins.js +++ b/src/components/skins.js @@ -1,15 +1,14 @@ import React from 'react' import PropTypes from 'prop-types' +import { NimbleEmoji } from '.' + export default class Skins extends React.PureComponent { constructor(props) { super(props) - this.state = { opened: false, } - - this.handleClick = this.handleClick.bind(this) } handleClick(e) { @@ -27,42 +26,7 @@ export default class Skins extends React.PureComponent { } render() { - const { skin } = this.props - const { opened } = this.state - - const skinToneNodes = [] - - for (let i = 0; i < 6; i++) { - const skinTone = i + 1 - const selected = skinTone == skin - - skinToneNodes.push( - - - , - ) - } - - return ( -
-
- {skinToneNodes} -
-
- ) + return null } } diff --git a/src/utils/shared-props.js b/src/utils/shared-props.js index 3bb8083..454a921 100644 --- a/src/utils/shared-props.js +++ b/src/utils/shared-props.js @@ -71,6 +71,7 @@ const PickerPropTypes = { imageUrl: PropTypes.string.isRequired, }), ), + skinIcon: PropTypes.string, } const PickerDefaultProps = { @@ -96,6 +97,7 @@ const PickerDefaultProps = { emojiTooltip: EmojiDefaultProps.tooltip, autoFocus: false, custom: [], + skinIcon: '', } export { diff --git a/stories/index.js b/stories/index.js index b0798ec..e6a3188 100644 --- a/stories/index.js +++ b/stories/index.js @@ -41,7 +41,13 @@ storiesOf('Picker', module) showPreview={boolean('Show preview', true)} showSkinTones={boolean('Show skin tones', true)} custom={CUSTOM_EMOJIS} - /> + />)) + .add('custom-skin-icon', () => ( + )); storiesOf('Emoji', module)