From f1d5bc00956e0e64ad30a955cf672fa7e1f890de Mon Sep 17 00:00:00 2001 From: Rena Ryumae Date: Thu, 5 Jul 2018 17:00:57 -0400 Subject: [PATCH 1/6] 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) From 175d08a6122783345ba2c8671b7368ee1bf88666 Mon Sep 17 00:00:00 2001 From: Etienne Lemay Date: Fri, 10 Aug 2018 14:01:52 -0400 Subject: [PATCH 2/6] =?UTF-8?q?Set=20`.emoji-mart-skin-text`=20width=20in?= =?UTF-8?q?=20px=20So=20that=20it=20doesn=E2=80=99t=20change=20width=20whi?= =?UTF-8?q?le=20transitioning.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/emoji-mart.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/emoji-mart.css b/css/emoji-mart.css index b64dfff..da6f36a 100644 --- a/css/emoji-mart.css +++ b/css/emoji-mart.css @@ -325,7 +325,7 @@ color: #888; font-size: 11px; padding: 5px 2px; - width: 30%; + width: 95px; height: 40px; border-radius: 10%; background-color: #fff; From 9b523425c6fd9b2c73c4c04b9c7b6e06503cf22e Mon Sep 17 00:00:00 2001 From: Etienne Lemay Date: Fri, 10 Aug 2018 14:02:33 -0400 Subject: [PATCH 3/6] :lipstick: --- src/components/picker/nimble-picker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/picker/nimble-picker.js b/src/components/picker/nimble-picker.js index 0f8c244..bbb6026 100644 --- a/src/components/picker/nimble-picker.js +++ b/src/components/picker/nimble-picker.js @@ -14,7 +14,7 @@ import { Anchors, Category, Preview, Search } from '..' const I18N = { search: 'Search', notfound: 'No Emoji Found', - skintext: 'Choose your default skin tone ', + skintext: 'Choose your default skin tone', categories: { search: 'Search Results', recent: 'Frequently Used', From 83bd22dffd18fe093f30f0f9e3031e107988320b Mon Sep 17 00:00:00 2001 From: Etienne Lemay Date: Fri, 10 Aug 2018 14:10:55 -0400 Subject: [PATCH 4/6] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 55e00d7..b11570f 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ import { Picker } from 'emoji-mart' | **emojiTooltip** | | `false` | Show emojis short name when hovering (title) | | **skin** | | | Forces skin color: `1, 2, 3, 4, 5, 6` | | **defaultSkin** | | `1` | Default skin color: `1, 2, 3, 4, 5, 6` | +| **skinIcon** | | | The emoji used to pick a skin tone. Uses an emoji-less skin tone picker by default | | **style** | | | Inline styles applied to the root element. Useful for positioning | | **title** | | `Emoji Mart™` | The title shown when no emojis are hovered | | **notFoundEmoji** | | `sleuth_or_spy` | The emoji shown when there are no search results | @@ -58,6 +59,7 @@ import { Picker } from 'emoji-mart' ```js search: 'Search', notfound: 'No Emoji Found', +skintext: 'Choose your default skin tone', categories: { search: 'Search Results', recent: 'Frequently Used', From 2c060c56bc83276fbe68e7e8fcda9ddc79851fea Mon Sep 17 00:00:00 2001 From: Etienne Lemay Date: Fri, 10 Aug 2018 14:11:28 -0400 Subject: [PATCH 5/6] =?UTF-8?q?Rename=20=E2=80=9CskinIcon=E2=80=9D=20=3D>?= =?UTF-8?q?=20=E2=80=9CskinEmoji=E2=80=9D=20More=20consistent=20with=20oth?= =?UTF-8?q?er=20props?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/components/picker/nimble-picker.js | 4 ++-- src/components/preview.js | 6 +++--- src/components/skins-emoji.js | 6 +++--- src/utils/shared-props.js | 4 ++-- stories/index.js | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b11570f..d1b3900 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ import { Picker } from 'emoji-mart' | **emojiTooltip** | | `false` | Show emojis short name when hovering (title) | | **skin** | | | Forces skin color: `1, 2, 3, 4, 5, 6` | | **defaultSkin** | | `1` | Default skin color: `1, 2, 3, 4, 5, 6` | -| **skinIcon** | | | The emoji used to pick a skin tone. Uses an emoji-less skin tone picker by default | +| **skinEmoji** | | | The emoji used to pick a skin tone. Uses an emoji-less skin tone picker by default | | **style** | | | Inline styles applied to the root element. Useful for positioning | | **title** | | `Emoji Mart™` | The title shown when no emojis are hovered | | **notFoundEmoji** | | `sleuth_or_spy` | The emoji shown when there are no search results | diff --git a/src/components/picker/nimble-picker.js b/src/components/picker/nimble-picker.js index 3960fee..d7d85cf 100644 --- a/src/components/picker/nimble-picker.js +++ b/src/components/picker/nimble-picker.js @@ -472,7 +472,7 @@ export default class NimblePicker extends React.PureComponent { exclude, recent, autoFocus, - skinIcon, + skinEmoji, notFound, notFoundEmoji, } = this.props, @@ -576,7 +576,7 @@ export default class NimblePicker extends React.PureComponent { skinsProps={{ skin: skin, onChange: this.handleSkinChange, - skinIcon: skinIcon, + skinEmoji: skinEmoji, }} i18n={this.i18n} /> diff --git a/src/components/preview.js b/src/components/preview.js index f01c26b..c6f7b20 100644 --- a/src/components/preview.js +++ b/src/components/preview.js @@ -84,15 +84,15 @@ export default class Preview extends React.PureComponent { {showSkinTones && (
- {skinsProps.skinIcon ? ( + {skinsProps.skinEmoji ? ( diff --git a/src/components/skins-emoji.js b/src/components/skins-emoji.js index 8699120..192f3b9 100644 --- a/src/components/skins-emoji.js +++ b/src/components/skins-emoji.js @@ -11,7 +11,7 @@ export default class SkinsEmoji extends Skins { } render() { - const { skin, emojiProps, data, skinIcon, i18n } = this.props + const { skin, emojiProps, data, skinEmoji, i18n } = this.props const { opened } = this.state const skinToneNodes = [] @@ -30,7 +30,7 @@ export default class SkinsEmoji extends Skins { className={`emoji-mart-skin-tone-${skinTone}`} > {NimbleEmoji({ - emoji: skinIcon, + emoji: skinEmoji, data: data, skin: skinTone, backgroundImageFn: emojiProps.backgroundImageFn, @@ -62,7 +62,7 @@ SkinsEmoji.propTypes = { skin: PropTypes.number.isRequired, emojiProps: PropTypes.object.isRequired, skinTone: PropTypes.number, - skinIcon: PropTypes.string.isRequired, + skinEmoji: PropTypes.string.isRequired, i18n: PropTypes.object, } diff --git a/src/utils/shared-props.js b/src/utils/shared-props.js index 820d99c..8a83752 100644 --- a/src/utils/shared-props.js +++ b/src/utils/shared-props.js @@ -75,7 +75,7 @@ const PickerPropTypes = { imageUrl: PropTypes.string.isRequired, }), ), - skinIcon: PropTypes.string, + skinEmoji: PropTypes.string, notFound: PropTypes.func, notFoundEmoji: PropTypes.string, icons: PropTypes.object, @@ -104,7 +104,7 @@ const PickerDefaultProps = { emojiTooltip: EmojiDefaultProps.tooltip, autoFocus: false, custom: [], - skinIcon: '', + skinEmoji: '', notFound: () => {}, notFoundEmoji: 'sleuth_or_spy', icons: {}, diff --git a/stories/index.js b/stories/index.js index a6ba2c9..89e6b0d 100644 --- a/stories/index.js +++ b/stories/index.js @@ -184,7 +184,7 @@ storiesOf('Picker', module) )) From 94e7b2d8784258b0f530c8d46871946016a948f3 Mon Sep 17 00:00:00 2001 From: Etienne Lemay Date: Fri, 10 Aug 2018 14:14:18 -0400 Subject: [PATCH 6/6] :lipstick: --- stories/index.js | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/stories/index.js b/stories/index.js index 89e6b0d..3cb54d4 100644 --- a/stories/index.js +++ b/stories/index.js @@ -32,7 +32,7 @@ const CUSTOM_EMOJIS = [ storiesOf('Picker', module) .addDecorator(withKnobs) - .add('default', () => ( + .add('Default', () => ( )) - .add('with a custom not found image', () => ( + + .add('Custom “Not found” component', () => ( ( )} /> )) - .add('with a custom not found SVG', () => ( - ( - - Jira icon - - - )} - /> - )) - .add('with-custom-icons', () => ( + + .add('Custom category icons', () => ( )) - .add('custom-skin-icon', () => ( + + .add('Custom skin emoji', () => ( ( + .add('Default', () => ( { + .add('Default', () => { let results = emojiIndex.search(text('Search', 'christmas'), { custom: CUSTOM_EMOJIS, })