Update theme handling [Fix #404]
- Defaults to “light” - “auto” picks light/dark based on `prefers-color-scheme: dark` media query (and actually updates automatically)dependabot/npm_and_yarn/websocket-extensions-0.1.4
parent
c41fc5ec7a
commit
d1138c00e8
|
@ -29,7 +29,6 @@ import { Picker } from 'emoji-mart'
|
||||||
| **autoFocus** | | `false` | Auto focus the search input when mounted |
|
| **autoFocus** | | `false` | Auto focus the search input when mounted |
|
||||||
| **color** | | `#ae65c5` | The top bar anchors select and hover color |
|
| **color** | | `#ae65c5` | The top bar anchors select and hover color |
|
||||||
| **emoji** | | `department_store` | The emoji shown when no emojis are hovered, set to an empty string to show nothing |
|
| **emoji** | | `department_store` | The emoji shown when no emojis are hovered, set to an empty string to show nothing |
|
||||||
| **darkMode** | | varies | Dark mode (boolean). `true` by default if the browser reports [`prefers-color-scheme: dark`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). |
|
|
||||||
| **include** | | `[]` | Only load included categories. Accepts [I18n categories keys](#i18n). Order will be respected, except for the `recent` category which will always be the first. |
|
| **include** | | `[]` | Only load included categories. Accepts [I18n categories keys](#i18n). Order will be respected, except for the `recent` category which will always be the first. |
|
||||||
| **exclude** | | `[]` | Don't load excluded categories. Accepts [I18n categories keys](#i18n). |
|
| **exclude** | | `[]` | Don't load excluded categories. Accepts [I18n categories keys](#i18n). |
|
||||||
| **custom** | | `[]` | [Custom emojis](#custom-emojis) |
|
| **custom** | | `[]` | [Custom emojis](#custom-emojis) |
|
||||||
|
@ -43,6 +42,7 @@ import { Picker } from 'emoji-mart'
|
||||||
| **i18n** | | [`{…}`](#i18n) | [An object](#i18n) containing localized strings |
|
| **i18n** | | [`{…}`](#i18n) | [An object](#i18n) containing localized strings |
|
||||||
| **native** | | `false` | Renders the native unicode emoji |
|
| **native** | | `false` | Renders the native unicode emoji |
|
||||||
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter', 'facebook'` |
|
| **set** | | `apple` | The emoji set: `'apple', 'google', 'twitter', 'facebook'` |
|
||||||
|
| **theme** | | `light` | The picker theme: `'auto', 'light', 'dark'` |
|
||||||
| **sheetSize** | | `64` | The emoji [sheet size](#sheet-sizes): `16, 20, 32, 64` |
|
| **sheetSize** | | `64` | The emoji [sheet size](#sheet-sizes): `16, 20, 32, 64` |
|
||||||
| **backgroundImageFn** | | ```((set, sheetSize) => …)``` | A Fn that returns that image sheet to use for emojis. Useful for avoiding a request if you have the sheet locally. |
|
| **backgroundImageFn** | | ```((set, sheetSize) => …)``` | A Fn that returns that image sheet to use for emojis. Useful for avoiding a request if you have the sheet locally. |
|
||||||
| **emojisToShowFilter** | | ```((emoji) => true)``` | A Fn to choose whether an emoji should be displayed or not |
|
| **emojisToShowFilter** | | ```((emoji) => true)``` | A Fn to choose whether an emoji should be displayed or not |
|
||||||
|
|
|
@ -1539,6 +1539,7 @@ var PickerPropTypes = {
|
||||||
showSkinTones: _propTypes["default"].bool,
|
showSkinTones: _propTypes["default"].bool,
|
||||||
emojiTooltip: EmojiPropTypes.tooltip,
|
emojiTooltip: EmojiPropTypes.tooltip,
|
||||||
useButton: EmojiPropTypes.useButton,
|
useButton: EmojiPropTypes.useButton,
|
||||||
|
theme: _propTypes["default"].oneOf(['auto', 'light', 'dark']),
|
||||||
include: _propTypes["default"].arrayOf(_propTypes["default"].string),
|
include: _propTypes["default"].arrayOf(_propTypes["default"].string),
|
||||||
exclude: _propTypes["default"].arrayOf(_propTypes["default"].string),
|
exclude: _propTypes["default"].arrayOf(_propTypes["default"].string),
|
||||||
recent: _propTypes["default"].arrayOf(_propTypes["default"].string),
|
recent: _propTypes["default"].arrayOf(_propTypes["default"].string),
|
||||||
|
@ -1602,6 +1603,7 @@ var PickerDefaultProps = {
|
||||||
emoji: 'department_store',
|
emoji: 'department_store',
|
||||||
color: '#ae65c5',
|
color: '#ae65c5',
|
||||||
set: EmojiDefaultProps.set,
|
set: EmojiDefaultProps.set,
|
||||||
|
theme: 'light',
|
||||||
skin: null,
|
skin: null,
|
||||||
defaultSkin: EmojiDefaultProps.skin,
|
defaultSkin: EmojiDefaultProps.skin,
|
||||||
"native": EmojiDefaultProps["native"],
|
"native": EmojiDefaultProps["native"],
|
||||||
|
@ -1610,7 +1612,6 @@ var PickerDefaultProps = {
|
||||||
emojisToShowFilter: null,
|
emojisToShowFilter: null,
|
||||||
showPreview: true,
|
showPreview: true,
|
||||||
showSkinTones: true,
|
showSkinTones: true,
|
||||||
darkMode: !!(typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: dark)').matches),
|
|
||||||
emojiTooltip: EmojiDefaultProps.tooltip,
|
emojiTooltip: EmojiDefaultProps.tooltip,
|
||||||
useButton: EmojiDefaultProps.useButton,
|
useButton: EmojiDefaultProps.useButton,
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
|
@ -2621,6 +2622,8 @@ function (_React$PureComponent) {
|
||||||
_this.setPreviewRef = _this.setPreviewRef.bind((0, _assertThisInitialized2["default"])(_this));
|
_this.setPreviewRef = _this.setPreviewRef.bind((0, _assertThisInitialized2["default"])(_this));
|
||||||
_this.handleSkinChange = _this.handleSkinChange.bind((0, _assertThisInitialized2["default"])(_this));
|
_this.handleSkinChange = _this.handleSkinChange.bind((0, _assertThisInitialized2["default"])(_this));
|
||||||
_this.handleKeyDown = _this.handleKeyDown.bind((0, _assertThisInitialized2["default"])(_this));
|
_this.handleKeyDown = _this.handleKeyDown.bind((0, _assertThisInitialized2["default"])(_this));
|
||||||
|
_this.handleDarkMatchMediaChange = _this.handleDarkMatchMediaChange.bind((0, _assertThisInitialized2["default"])(_this));
|
||||||
|
_this.state.theme = _this.getPreferredTheme();
|
||||||
return _this;
|
return _this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2650,6 +2653,10 @@ function (_React$PureComponent) {
|
||||||
this.SEARCH_CATEGORY.emojis = null;
|
this.SEARCH_CATEGORY.emojis = null;
|
||||||
clearTimeout(this.leaveTimeout);
|
clearTimeout(this.leaveTimeout);
|
||||||
clearTimeout(this.firstRenderTimeout);
|
clearTimeout(this.firstRenderTimeout);
|
||||||
|
|
||||||
|
if (this.darkMatchMedia) {
|
||||||
|
this.darkMatchMedia.removeListener(this.handleDarkMatchMediaChange);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "testStickyPosition",
|
key: "testStickyPosition",
|
||||||
|
@ -2661,6 +2668,27 @@ function (_React$PureComponent) {
|
||||||
});
|
});
|
||||||
this.hasStickyPosition = !!stickyTestElement.style.position.length;
|
this.hasStickyPosition = !!stickyTestElement.style.position.length;
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
key: "getPreferredTheme",
|
||||||
|
value: function getPreferredTheme() {
|
||||||
|
if (this.props.theme != 'auto') return this.props.theme;
|
||||||
|
if (typeof matchMedia !== 'function') return _sharedDefaultProps.PickerDefaultProps.theme;
|
||||||
|
|
||||||
|
if (!this.darkMatchMedia) {
|
||||||
|
this.darkMatchMedia = matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
this.darkMatchMedia.addListener(this.handleDarkMatchMediaChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.darkMatchMedia.media.match(/^not/)) return _sharedDefaultProps.PickerDefaultProps.theme;
|
||||||
|
return this.darkMatchMedia.matches ? 'dark' : 'light';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "handleDarkMatchMediaChange",
|
||||||
|
value: function handleDarkMatchMediaChange() {
|
||||||
|
this.setState({
|
||||||
|
theme: this.getPreferredTheme()
|
||||||
|
});
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "handleEmojiOver",
|
key: "handleEmojiOver",
|
||||||
value: function handleEmojiOver(emoji) {
|
value: function handleEmojiOver(emoji) {
|
||||||
|
@ -2972,14 +3000,15 @@ function (_React$PureComponent) {
|
||||||
skinEmoji = _this$props.skinEmoji,
|
skinEmoji = _this$props.skinEmoji,
|
||||||
notFound = _this$props.notFound,
|
notFound = _this$props.notFound,
|
||||||
notFoundEmoji = _this$props.notFoundEmoji,
|
notFoundEmoji = _this$props.notFoundEmoji,
|
||||||
darkMode = _this$props.darkMode,
|
_this$state = this.state,
|
||||||
skin = this.state.skin,
|
skin = _this$state.skin,
|
||||||
|
theme = _this$state.theme,
|
||||||
width = perLine * (emojiSize + 12) + 12 + 2 + (0, _utils.measureScrollbar)();
|
width = perLine * (emojiSize + 12) + 12 + 2 + (0, _utils.measureScrollbar)();
|
||||||
return _react["default"].createElement("section", {
|
return _react["default"].createElement("section", {
|
||||||
style: _objectSpread({
|
style: _objectSpread({
|
||||||
width: width
|
width: width
|
||||||
}, style),
|
}, style),
|
||||||
className: "emoji-mart ".concat(darkMode ? 'emoji-mart-dark' : ''),
|
className: "emoji-mart emoji-mart-".concat(theme),
|
||||||
"aria-label": title,
|
"aria-label": title,
|
||||||
onKeyDown: this.handleKeyDown
|
onKeyDown: this.handleKeyDown
|
||||||
}, _react["default"].createElement("div", {
|
}, _react["default"].createElement("div", {
|
||||||
|
@ -3708,6 +3737,7 @@ class Example extends __WEBPACK_IMPORTED_MODULE_1_react___default.a.Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
native: true,
|
native: true,
|
||||||
set: 'apple',
|
set: 'apple',
|
||||||
|
theme: 'auto',
|
||||||
emoji: 'point_up',
|
emoji: 'point_up',
|
||||||
title: 'Pick your emoji…',
|
title: 'Pick your emoji…',
|
||||||
custom: CUSTOM_EMOJIS,
|
custom: CUSTOM_EMOJIS,
|
||||||
|
@ -3747,28 +3777,17 @@ class Example extends __WEBPACK_IMPORTED_MODULE_1_react___default.a.Component {
|
||||||
}, props), set);
|
}, props), set);
|
||||||
})), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("div", {
|
})), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("div", {
|
||||||
className: "row-small sets"
|
className: "row-small sets"
|
||||||
}, "Theme:\xA0", __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("button", {
|
}, "Theme:\xA0", ['auto', 'light', 'dark'].map(theme => {
|
||||||
disabled: this.state.darkMode == undefined,
|
return __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("button", {
|
||||||
|
key: theme,
|
||||||
|
disabled: theme == this.state.theme,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
darkMode: undefined
|
theme
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, "auto"), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("button", {
|
}, theme);
|
||||||
disabled: this.state.darkMode == false,
|
})), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("div", {
|
||||||
onClick: () => {
|
|
||||||
this.setState({
|
|
||||||
darkMode: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, "light"), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("button", {
|
|
||||||
disabled: this.state.darkMode,
|
|
||||||
onClick: () => {
|
|
||||||
this.setState({
|
|
||||||
darkMode: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, "dark")), __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement("div", {
|
|
||||||
className: "row"
|
className: "row"
|
||||||
}, __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_3__dist__["Picker"], __WEBPACK_IMPORTED_MODULE_0__babel_runtime_helpers_extends___default()({}, this.state, {
|
}, __WEBPACK_IMPORTED_MODULE_1_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_3__dist__["Picker"], __WEBPACK_IMPORTED_MODULE_0__babel_runtime_helpers_extends___default()({}, this.state, {
|
||||||
onSelect: console.log
|
onSelect: console.log
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Example extends React.Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
native: true,
|
native: true,
|
||||||
set: 'apple',
|
set: 'apple',
|
||||||
|
theme: 'auto',
|
||||||
emoji: 'point_up',
|
emoji: 'point_up',
|
||||||
title: 'Pick your emoji…',
|
title: 'Pick your emoji…',
|
||||||
custom: CUSTOM_EMOJIS,
|
custom: CUSTOM_EMOJIS,
|
||||||
|
@ -88,30 +89,19 @@ class Example extends React.Component {
|
||||||
|
|
||||||
<div className="row-small sets">
|
<div className="row-small sets">
|
||||||
Theme:
|
Theme:
|
||||||
|
{['auto', 'light', 'dark'].map((theme) => {
|
||||||
|
return (
|
||||||
<button
|
<button
|
||||||
disabled={this.state.darkMode == undefined}
|
key={theme}
|
||||||
|
disabled={theme == this.state.theme}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.setState({ darkMode: undefined })
|
this.setState({ theme })
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
auto
|
{theme}
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
disabled={this.state.darkMode == false}
|
|
||||||
onClick={() => {
|
|
||||||
this.setState({ darkMode: false })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
light
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
disabled={this.state.darkMode}
|
|
||||||
onClick={() => {
|
|
||||||
this.setState({ darkMode: true })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
dark
|
|
||||||
</button>
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
|
|
@ -196,6 +196,9 @@ export default class NimblePicker extends React.PureComponent {
|
||||||
this.setPreviewRef = this.setPreviewRef.bind(this)
|
this.setPreviewRef = this.setPreviewRef.bind(this)
|
||||||
this.handleSkinChange = this.handleSkinChange.bind(this)
|
this.handleSkinChange = this.handleSkinChange.bind(this)
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this)
|
this.handleKeyDown = this.handleKeyDown.bind(this)
|
||||||
|
this.handleDarkMatchMediaChange = this.handleDarkMatchMediaChange.bind(this)
|
||||||
|
|
||||||
|
this.state.theme = this.getPreferredTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
@ -232,6 +235,10 @@ export default class NimblePicker extends React.PureComponent {
|
||||||
|
|
||||||
clearTimeout(this.leaveTimeout)
|
clearTimeout(this.leaveTimeout)
|
||||||
clearTimeout(this.firstRenderTimeout)
|
clearTimeout(this.firstRenderTimeout)
|
||||||
|
|
||||||
|
if (this.darkMatchMedia) {
|
||||||
|
this.darkMatchMedia.removeListener(this.handleDarkMatchMediaChange)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testStickyPosition() {
|
testStickyPosition() {
|
||||||
|
@ -246,6 +253,23 @@ export default class NimblePicker extends React.PureComponent {
|
||||||
this.hasStickyPosition = !!stickyTestElement.style.position.length
|
this.hasStickyPosition = !!stickyTestElement.style.position.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPreferredTheme() {
|
||||||
|
if (this.props.theme != 'auto') return this.props.theme
|
||||||
|
if (typeof matchMedia !== 'function') return PickerDefaultProps.theme
|
||||||
|
|
||||||
|
if (!this.darkMatchMedia) {
|
||||||
|
this.darkMatchMedia = matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
this.darkMatchMedia.addListener(this.handleDarkMatchMediaChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.darkMatchMedia.media.match(/^not/)) return PickerDefaultProps.theme
|
||||||
|
return this.darkMatchMedia.matches ? 'dark' : 'light'
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDarkMatchMediaChange() {
|
||||||
|
this.setState({ theme: this.getPreferredTheme() })
|
||||||
|
}
|
||||||
|
|
||||||
handleEmojiOver(emoji) {
|
handleEmojiOver(emoji) {
|
||||||
var { preview } = this
|
var { preview } = this
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
|
@ -529,15 +553,14 @@ export default class NimblePicker extends React.PureComponent {
|
||||||
skinEmoji,
|
skinEmoji,
|
||||||
notFound,
|
notFound,
|
||||||
notFoundEmoji,
|
notFoundEmoji,
|
||||||
darkMode,
|
|
||||||
} = this.props,
|
} = this.props,
|
||||||
{ skin } = this.state,
|
{ skin, theme } = this.state,
|
||||||
width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar()
|
width = perLine * (emojiSize + 12) + 12 + 2 + measureScrollbar()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
style={{ width: width, ...style }}
|
style={{ width: width, ...style }}
|
||||||
className={`emoji-mart ${darkMode ? 'emoji-mart-dark' : ''}`}
|
className={`emoji-mart emoji-mart-${theme}`}
|
||||||
aria-label={title}
|
aria-label={title}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
>
|
>
|
||||||
|
|
|
@ -24,6 +24,7 @@ const PickerDefaultProps = {
|
||||||
emoji: 'department_store',
|
emoji: 'department_store',
|
||||||
color: '#ae65c5',
|
color: '#ae65c5',
|
||||||
set: EmojiDefaultProps.set,
|
set: EmojiDefaultProps.set,
|
||||||
|
theme: 'light',
|
||||||
skin: null,
|
skin: null,
|
||||||
defaultSkin: EmojiDefaultProps.skin,
|
defaultSkin: EmojiDefaultProps.skin,
|
||||||
native: EmojiDefaultProps.native,
|
native: EmojiDefaultProps.native,
|
||||||
|
@ -32,10 +33,6 @@ const PickerDefaultProps = {
|
||||||
emojisToShowFilter: null,
|
emojisToShowFilter: null,
|
||||||
showPreview: true,
|
showPreview: true,
|
||||||
showSkinTones: true,
|
showSkinTones: true,
|
||||||
darkMode: !!(
|
|
||||||
typeof matchMedia === 'function' &&
|
|
||||||
matchMedia('(prefers-color-scheme: dark)').matches
|
|
||||||
),
|
|
||||||
emojiTooltip: EmojiDefaultProps.tooltip,
|
emojiTooltip: EmojiDefaultProps.tooltip,
|
||||||
useButton: EmojiDefaultProps.useButton,
|
useButton: EmojiDefaultProps.useButton,
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
|
|
|
@ -41,6 +41,7 @@ const PickerPropTypes = {
|
||||||
showSkinTones: PropTypes.bool,
|
showSkinTones: PropTypes.bool,
|
||||||
emojiTooltip: EmojiPropTypes.tooltip,
|
emojiTooltip: EmojiPropTypes.tooltip,
|
||||||
useButton: EmojiPropTypes.useButton,
|
useButton: EmojiPropTypes.useButton,
|
||||||
|
theme: PropTypes.oneOf(['auto', 'light', 'dark']),
|
||||||
include: PropTypes.arrayOf(PropTypes.string),
|
include: PropTypes.arrayOf(PropTypes.string),
|
||||||
exclude: PropTypes.arrayOf(PropTypes.string),
|
exclude: PropTypes.arrayOf(PropTypes.string),
|
||||||
recent: PropTypes.arrayOf(PropTypes.string),
|
recent: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
import data from '../data/all.json'
|
import data from '../data/all.json'
|
||||||
import '../css/emoji-mart.css'
|
import '../css/emoji-mart.css'
|
||||||
|
|
||||||
|
const THEMES = ['auto', 'light', 'dark']
|
||||||
const SETS = ['apple', 'google', 'twitter', 'facebook']
|
const SETS = ['apple', 'google', 'twitter', 'facebook']
|
||||||
const CUSTOM_EMOJIS = [
|
const CUSTOM_EMOJIS = [
|
||||||
{
|
{
|
||||||
|
@ -51,7 +52,7 @@ storiesOf('Picker', module)
|
||||||
onSelect={action('selected')}
|
onSelect={action('selected')}
|
||||||
onSkinChange={action('skin changed')}
|
onSkinChange={action('skin changed')}
|
||||||
native={boolean('Unicode', true)}
|
native={boolean('Unicode', true)}
|
||||||
darkMode={boolean('Dark mode', false)}
|
theme={select('Theme', THEMES, THEMES[0])}
|
||||||
set={select('Emoji pack', SETS, SETS[0])}
|
set={select('Emoji pack', SETS, SETS[0])}
|
||||||
emojiSize={number('Emoji size', 24)}
|
emojiSize={number('Emoji size', 24)}
|
||||||
perLine={number('Per line', 9)}
|
perLine={number('Per line', 9)}
|
||||||
|
|
Loading…
Reference in New Issue