about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js')
-rw-r--r--app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js118
1 files changed, 118 insertions, 0 deletions
diff --git a/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
new file mode 100644
index 000000000..1b7ae8904
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
@@ -0,0 +1,118 @@
+//  Package imports.
+import classNames from 'classnames';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+//  Components.
+import AccountContainer from 'flavours/glitch/containers/account_container';
+
+//  Utils.
+import { unicodeMapping } from 'flavours/glitch/util/emoji';
+import { assignHandlers } from 'flavours/glitch/util/react_helpers';
+
+//  Gets our asset host from the environment, if available.
+const assetHost = process.env.CDN_HOST || '';
+
+//  Handlers.
+const handlers = {
+
+  //  Handles a click on a suggestion.
+  handleClick (e) {
+    const {
+      index,
+      onClick,
+    } = this.props;
+    if (onClick) {
+      e.preventDefault();
+      e.stopPropagation();  //  Prevents following account links
+      onClick(index);
+    }
+  },
+
+  //  This prevents the focus from changing, which would mess with
+  //  our suggestion code.
+  handleMouseDown (e) {
+    e.preventDefault();
+  },
+};
+
+//  The component.
+export default class ComposerTextareaSuggestionsItem extends React.Component {
+
+  //  Constructor.
+  constructor (props) {
+    super(props);
+    assignHandlers(this, handlers);
+  }
+
+  //  Rendering.
+  render () {
+    const {
+      handleMouseDown,
+      handleClick,
+    } = this.handlers;
+    const {
+      selected,
+      suggestion,
+    } = this.props;
+    const computedClass = classNames('composer--textarea--suggestions--item', { selected });
+
+    //  If the suggestion is an object, then we render an emoji.
+    //  Otherwise, we render a hashtag if it starts with #, or an account.
+    let inner;
+    if (typeof suggestion === 'object') {
+      let url;
+      if (suggestion.custom) {
+        url = suggestion.imageUrl;
+      } else {
+        const mapping = unicodeMapping[suggestion.native] || unicodeMapping[suggestion.native.replace(/\uFE0F$/, '')];
+        if (mapping) {
+          url = `${assetHost}/emoji/${mapping.filename}.svg`;
+        }
+      }
+      if (url) {
+        inner = (
+          <div className='emoji'>
+            <img
+              alt={suggestion.native || suggestion.colons}
+              className='emojione'
+              src={url}
+            />
+            {suggestion.colons}
+          </div>
+        );
+      }
+    } else if (suggestion[0] === '#') {
+      inner = suggestion;
+    } else {
+      inner = (
+        <AccountContainer
+          id={suggestion}
+          small
+        />
+      );
+    }
+
+    //  The result.
+    return (
+      <div
+        className={computedClass}
+        onMouseDown={handleMouseDown}
+        onClickCapture={handleClick}  //  Jumps in front of contents
+        role='button'
+        tabIndex='0'
+      >
+        { inner }
+      </div>
+    );
+  }
+
+}
+
+//  Props.
+ComposerTextareaSuggestionsItem.propTypes = {
+  index: PropTypes.number,
+  onClick: PropTypes.func,
+  selected: PropTypes.bool,
+  suggestion: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
+};