about summary refs log tree commit diff
path: root/app/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript')
-rw-r--r--app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js41
-rw-r--r--app/javascript/styles/components.scss14
2 files changed, 50 insertions, 5 deletions
diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
index 3e0b290d6..c95b4a279 100644
--- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
@@ -1,6 +1,5 @@
 import React from 'react';
 import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
-import EmojiPicker from 'emojione-picker';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 
@@ -37,12 +36,20 @@ const dropdownTriggerStyle = {
   width: '24px'
 }
 
+let EmojiPicker; // load asynchronously
+
 class EmojiPickerDropdown extends React.PureComponent {
 
   constructor (props, context) {
     super(props, context);
     this.setRef = this.setRef.bind(this);
     this.handleChange = this.handleChange.bind(this);
+    this.onHideDropdown = this.onHideDropdown.bind(this);
+    this.onShowDropdown = this.onShowDropdown.bind(this);
+    this.state = {
+      active: false,
+      loading: false
+    };
   }
 
   setRef (c) {
@@ -54,6 +61,24 @@ class EmojiPickerDropdown extends React.PureComponent {
     this.props.onPickEmoji(data);
   }
 
+  onShowDropdown () {
+    this.setState({active: true});
+    if (!EmojiPicker) {
+      this.setState({loading: true});
+      import('emojione-picker').then(TheEmojiPicker => {
+        EmojiPicker = TheEmojiPicker.default;
+        this.setState({loading: false});
+      }).catch(err => {
+        // TODO: show the user an error?
+        this.setState({loading: false});
+      });
+    }
+  }
+
+  onHideDropdown () {
+    this.setState({active: false});
+  }
+
   render () {
     const { intl } = this.props;
 
@@ -92,14 +117,20 @@ class EmojiPickerDropdown extends React.PureComponent {
       }
     }
 
+    const { active, loading } = this.state;
+
     return (
-      <Dropdown ref={this.setRef} style={dropdownStyle}>
+      <Dropdown ref={this.setRef} style={dropdownStyle} onShow={this.onShowDropdown} onHide={this.onHideDropdown}>
         <DropdownTrigger className='emoji-button' title={intl.formatMessage(messages.emoji)} style={dropdownTriggerStyle}>
-          <img draggable="false" className="emojione" alt="🙂" src="/emoji/1f602.svg" />
+          <img draggable="false"
+               className={`emojione ${active && loading ? "pulse-loading" : ''}`}
+               alt="🙂" src="/emoji/1f602.svg" />
         </DropdownTrigger>
-
         <DropdownContent className='dropdown__left'>
-          <EmojiPicker emojione={settings} onChange={this.handleChange} searchPlaceholder={intl.formatMessage(messages.emoji_search)} categories={categories} search={true} />
+          {
+            this.state.active && !this.state.loading &&
+            (<EmojiPicker emojione={settings} onChange={this.handleChange} searchPlaceholder={intl.formatMessage(messages.emoji_search)} categories={categories} search={true} />)
+          }
         </DropdownContent>
       </Dropdown>
     );
diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss
index 93a3d7046..f2d6f988c 100644
--- a/app/javascript/styles/components.scss
+++ b/app/javascript/styles/components.scss
@@ -2141,6 +2141,20 @@ button.icon-button.active i.fa-retweet {
   background: radial-gradient(ellipse, rgba($color4, 0.23) 0%, rgba($color4, 0) 60%);
 }
 
+@keyframes pulse {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0.5;
+  }
+}
+
+.pulse-loading {
+  animation: pulse 1s ease-in-out infinite;
+  animation-direction: alternate;
+}
+
 .emoji-dialog {
   width: 245px;
   height: 270px;