diff --git a/src/components/emoji_reaction_picker/emoji_reaction_picker.js b/src/components/emoji_reaction_picker/emoji_reaction_picker.js
deleted file mode 100644
index 6b589079..00000000
--- a/src/components/emoji_reaction_picker/emoji_reaction_picker.js
+++ /dev/null
@@ -1,213 +0,0 @@
-import { defineAsyncComponent } from 'vue'
-import Checkbox from '../checkbox/checkbox.vue'
-import { library } from '@fortawesome/fontawesome-svg-core'
-import {
- faBoxOpen,
- faStickyNote,
- faSmileBeam
-} from '@fortawesome/free-solid-svg-icons'
-
-library.add(
- faBoxOpen,
- faStickyNote,
- faSmileBeam
-)
-
-// At widest, approximately 20 emoji are visible in a row,
-// loading 3 rows, could be overkill for narrow picker
-const LOAD_EMOJI_BY = 60
-
-// When to start loading new batch emoji, in pixels
-const LOAD_EMOJI_MARGIN = 64
-
-const filterByKeyword = (list, keyword = '') => {
- if (keyword === '') return list
-
- const keywordLowercase = keyword.toLowerCase()
- let orderedEmojiList = []
- for (const emoji of list) {
- const indexOfKeyword = emoji.displayText.toLowerCase().indexOf(keywordLowercase)
- if (indexOfKeyword > -1) {
- if (!Array.isArray(orderedEmojiList[indexOfKeyword])) {
- orderedEmojiList[indexOfKeyword] = []
- }
- orderedEmojiList[indexOfKeyword].push(emoji)
- }
- }
- return orderedEmojiList.flat()
-}
-
-const EmojiPicker = {
- props: {
- enableStickerPicker: {
- required: false,
- type: Boolean,
- default: false
- }
- },
- data () {
- return {
- keyword: '',
- activeGroup: 'custom',
- showingStickers: false,
- groupsScrolledClass: 'scrolled-top',
- keepOpen: false,
- customEmojiBufferSlice: LOAD_EMOJI_BY,
- customEmojiTimeout: null,
- customEmojiLoadAllConfirmed: false
- }
- },
- components: {
- StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
- Checkbox
- },
- methods: {
- onStickerUploaded (e) {
- this.$emit('sticker-uploaded', e)
- },
- onStickerUploadFailed (e) {
- this.$emit('sticker-upload-failed', e)
- },
- onEmoji (emoji) {
- const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
- this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
- },
- onScroll (e) {
- const target = (e && e.target) || this.$refs['emoji-groups']
- this.updateScrolledClass(target)
- this.scrolledGroup(target)
- this.triggerLoadMore(target)
- },
- highlight (key) {
- const ref = this.$refs['group-' + key]
- const top = ref.offsetTop
- this.setShowStickers(false)
- this.activeGroup = key
- this.$nextTick(() => {
- this.$refs['emoji-groups'].scrollTop = top + 1
- })
- },
- updateScrolledClass (target) {
- if (target.scrollTop <= 5) {
- this.groupsScrolledClass = 'scrolled-top'
- } else if (target.scrollTop >= target.scrollTopMax - 5) {
- this.groupsScrolledClass = 'scrolled-bottom'
- } else {
- this.groupsScrolledClass = 'scrolled-middle'
- }
- },
- triggerLoadMore (target) {
- const ref = this.$refs['group-end-custom']
- if (!ref) return
- const bottom = ref.offsetTop + ref.offsetHeight
-
- const scrollerBottom = target.scrollTop + target.clientHeight
- const scrollerTop = target.scrollTop
- const scrollerMax = target.scrollHeight
-
- // Loads more emoji when they come into view
- const approachingBottom = bottom - scrollerBottom < LOAD_EMOJI_MARGIN
- // Always load when at the very top in case there's no scroll space yet
- const atTop = scrollerTop < 5
- // Don't load when looking at unicode category or at the very bottom
- const bottomAboveViewport = bottom < scrollerTop || scrollerBottom === scrollerMax
- if (!bottomAboveViewport && (approachingBottom || atTop)) {
- this.loadEmoji()
- }
- },
- scrolledGroup (target) {
- const top = target.scrollTop + 5
- this.$nextTick(() => {
- this.emojisView.forEach(group => {
- const ref = this.$refs['group-' + group.id]
- if (ref.offsetTop <= top) {
- this.activeGroup = group.id
- }
- })
- })
- },
- loadEmoji () {
- const allLoaded = this.customEmojiBuffer.length === this.filteredEmoji.length
-
- if (allLoaded) {
- return
- }
-
- this.customEmojiBufferSlice += LOAD_EMOJI_BY
- },
- startEmojiLoad (forceUpdate = false) {
- if (!forceUpdate) {
- this.keyword = ''
- }
- this.$nextTick(() => {
- this.$refs['emoji-groups'].scrollTop = 0
- })
- const bufferSize = this.customEmojiBuffer.length
- const bufferPrefilledAll = bufferSize === this.filteredEmoji.length
- if (bufferPrefilledAll && !forceUpdate) {
- return
- }
- this.customEmojiBufferSlice = LOAD_EMOJI_BY
- },
- toggleStickers () {
- this.showingStickers = !this.showingStickers
- },
- setShowStickers (value) {
- this.showingStickers = value
- }
- },
- watch: {
- keyword () {
- this.customEmojiLoadAllConfirmed = false
- this.onScroll()
- this.startEmojiLoad(true)
- }
- },
- computed: {
- activeGroupView () {
- return this.showingStickers ? '' : this.activeGroup
- },
- stickersAvailable () {
- if (this.$store.state.instance.stickers) {
- return this.$store.state.instance.stickers.length > 0
- }
- return 0
- },
- filteredEmoji () {
- return filterByKeyword(
- this.$store.state.instance.customEmoji || [],
- this.keyword
- )
- },
- customEmojiBuffer () {
- return this.filteredEmoji.slice(0, this.customEmojiBufferSlice)
- },
- emojis () {
- const standardEmojis = this.$store.state.instance.emoji || []
- const customEmojis = this.customEmojiBuffer
-
- return [
- {
- id: 'custom',
- text: this.$t('emoji.custom'),
- icon: 'smile-beam',
- emojis: customEmojis
- },
- {
- id: 'standard',
- text: this.$t('emoji.unicode'),
- icon: 'box-open',
- emojis: filterByKeyword(standardEmojis, this.keyword)
- }
- ]
- },
- emojisView () {
- return this.emojis.filter(value => value.emojis.length > 0)
- },
- stickerPickerEnabled () {
- return (this.$store.state.instance.stickers || []).length !== 0
- }
- }
-}
-
-export default EmojiPicker
diff --git a/src/components/emoji_reaction_picker/emoji_reaction_picker.scss b/src/components/emoji_reaction_picker/emoji_reaction_picker.scss
deleted file mode 100644
index 2055e02e..00000000
--- a/src/components/emoji_reaction_picker/emoji_reaction_picker.scss
+++ /dev/null
@@ -1,186 +0,0 @@
-@import '../../_variables.scss';
-
-.emoji-picker {
- display: flex;
- flex-direction: column;
- position: absolute;
- right: 0;
- left: 0;
- margin: 0 !important;
- z-index: 100;
- background-color: $fallback--bg;
- background-color: var(--popover, $fallback--bg);
- color: $fallback--link;
- color: var(--popoverText, $fallback--link);
- --lightText: var(--popoverLightText, $fallback--faint);
- --faint: var(--popoverFaintText, $fallback--faint);
- --faintLink: var(--popoverFaintLink, $fallback--faint);
- --lightText: var(--popoverLightText, $fallback--lightText);
- --icon: var(--popoverIcon, $fallback--icon);
-
- .keep-open,
- .too-many-emoji {
- padding: 7px;
- line-height: normal;
- }
-
- .too-many-emoji {
- display: flex;
- flex-direction: column;
- }
-
- .keep-open-label {
- padding: 0 7px;
- display: flex;
- }
-
- .heading {
- display: flex;
- height: 32px;
- padding: 10px 7px 5px;
- }
-
- .content {
- display: flex;
- flex-direction: column;
- flex: 1 1 auto;
- min-height: 0px;
- }
-
- .emoji-tabs {
- flex-grow: 1;
- }
-
- .emoji-groups {
- min-height: 200px;
- }
-
- .additional-tabs {
- border-left: 1px solid;
- border-left-color: $fallback--icon;
- border-left-color: var(--icon, $fallback--icon);
- padding-left: 7px;
- flex: 0 0 auto;
- }
-
- .additional-tabs,
- .emoji-tabs {
- display: block;
- min-width: 0;
- flex-basis: auto;
- flex-shrink: 1;
-
- &-item {
- padding: 0 7px;
- cursor: pointer;
- font-size: 1.85em;
-
- &.disabled {
- opacity: 0.5;
- pointer-events: none;
- }
-
- &.active {
- border-bottom: 4px solid;
-
- svg {
- color: $fallback--lightText;
- color: var(--lightText, $fallback--lightText);
- }
- }
- }
- }
-
- .sticker-picker {
- flex: 1 1 auto
- }
-
- .stickers,
- .emoji {
- &-content {
- display: flex;
- flex-direction: column;
- flex: 1 1 auto;
- min-height: 0;
-
- &.hidden {
- opacity: 0;
- pointer-events: none;
- position: absolute;
- }
- }
- }
-
- .emoji {
- &-search {
- padding: 5px;
- flex: 0 0 auto;
-
- input {
- width: 100%;
- }
- }
-
- &-groups {
- flex: 1 1 1px;
- position: relative;
- overflow: auto;
- user-select: none;
- mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
- linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
- linear-gradient(to top, white, white);
- transition: mask-size 150ms;
- mask-size: 100% 20px, 100% 20px, auto;
- // Autoprefixed seem to ignore this one, and also syntax is different
- -webkit-mask-composite: xor;
- mask-composite: exclude;
- &.scrolled {
- &-top {
- mask-size: 100% 20px, 100% 0, auto;
- }
- &-bottom {
- mask-size: 100% 0, 100% 20px, auto;
- }
- }
- }
-
- &-group {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- padding-left: 5px;
- justify-content: left;
-
- &-title {
- font-size: 0.85em;
- width: 100%;
- margin: 0;
-
- &.disabled {
- display: none;
- }
- }
- }
-
- &-item {
- width: 32px;
- height: 32px;
- box-sizing: border-box;
- display: flex;
- font-size: 32px;
- align-items: center;
- justify-content: center;
- margin: 4px;
-
- cursor: pointer;
-
- img {
- object-fit: contain;
- max-width: 100%;
- max-height: 100%;
- }
- }
-
- }
-
-}
diff --git a/src/components/emoji_reaction_picker/emoji_reaction_picker.vue b/src/components/emoji_reaction_picker/emoji_reaction_picker.vue
deleted file mode 100644
index a24eeb7e..00000000
--- a/src/components/emoji_reaction_picker/emoji_reaction_picker.vue
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- {{ group.text }}
-
-
- {{ emoji.replacement }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js
index 9f415e11..ac939b26 100644
--- a/src/components/react_button/react_button.js
+++ b/src/components/react_button/react_button.js
@@ -1,5 +1,6 @@
import Popover from '../popover/popover.vue'
import EmojiReactionPicker from '../emoji_reaction_picker/emoji_reaction_picker.vue'
+import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
@@ -14,6 +15,7 @@ const ReactButton = {
},
components: {
Popover,
+ EmojiPicker,
EmojiReactionPicker
},
methods: {
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index afb9df4e..cc94f2fa 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -9,7 +9,8 @@
@show="focusInput"
>
-