From 78081836dfa40abdb587dcbca59d339a27e23fb2 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Sat, 24 Dec 2022 12:43:30 -0500
Subject: Remove lozad code

---
 src/components/emoji_picker/emoji_picker.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index ff56d637..d0b7fe8f 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -104,9 +104,9 @@
                 >{{ emoji.replacement }}</span>
                 <still-image
                   v-else
-                  :ref="setEmojiRef(group.id + emoji.displayText)"
                   class="emoji-picker-emoji -custom"
-                  :data-src="emoji.imageUrl"
+                  loading="lazy"
+                  :src="emoji.imageUrl"
                   :data-emoji-name="group.id + emoji.displayText"
                 />
               </span>
-- 
cgit v1.2.3-70-g09d2


From afd7f5fabe58dc08a5a6e35e923e2e8fd71926dc Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Sat, 24 Dec 2022 13:48:36 -0500
Subject: Use virtual scrolling for emoji picker

---
 package.json                                  |  1 +
 src/boot/after_store.js                       |  3 +
 src/components/emoji_picker/emoji_picker.js   | 33 ++++-------
 src/components/emoji_picker/emoji_picker.scss |  1 +
 src/components/emoji_picker/emoji_picker.vue  | 79 +++++++++++++++------------
 yarn.lock                                     | 24 ++++++++
 6 files changed, 83 insertions(+), 58 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/package.json b/package.json
index 231a93ad..a32f93a4 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
     "vue-i18n": "9.2.2",
     "vue-router": "4.1.6",
     "vue-template-compiler": "2.7.14",
+    "vue-virtual-scroller": "^2.0.0-beta.7",
     "vuex": "4.1.0"
   },
   "devDependencies": {
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 7a4672b6..1fa9dd2a 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -1,6 +1,8 @@
 import { createApp } from 'vue'
 import { createRouter, createWebHistory } from 'vue-router'
 import vClickOutside from 'click-outside-vue3'
+import VueVirtualScroller from 'vue-virtual-scroller'
+import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
 
 import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
 
@@ -397,6 +399,7 @@ const afterStoreSetup = async ({ store, i18n }) => {
 
   app.use(vClickOutside)
   app.use(VBodyScrollLock)
+  app.use(VueVirtualScroller)
 
   app.component('FAIcon', FontAwesomeIcon)
   app.component('FALayers', FontAwesomeLayers)
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 68240fd8..c87dea7e 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -143,22 +143,13 @@ const EmojiPicker = {
       }
       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)
+    onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) {
+      const current = this.filteredEmojiGroups[visibleStartIndex].id
+      this.scrolledGroup(current)
     },
-    scrolledGroup (target) {
-      const top = target.scrollTop + 5
-      this.$nextTick(() => {
-        this.allEmojiGroups.forEach(group => {
-          const ref = this.groupRefs['group-' + group.id]
-          if (ref && ref.offsetTop <= top) {
-            this.activeGroup = group.id
-          }
-        })
-        this.scrollHeader()
-      })
+    scrolledGroup (groupId) {
+      this.activeGroup = groupId
+      this.scrollHeader()
     },
     scrollHeader () {
       // Scroll the active tab's header into view
@@ -177,14 +168,9 @@ const EmojiPicker = {
         setScroll(right + margin - headerCont.clientWidth)
       }
     },
-    highlight (key) {
-      const ref = this.groupRefs['group-' + key]
-      const top = ref.offsetTop
+    highlight (index) {
       this.setShowStickers(false)
-      this.activeGroup = key
-      this.$nextTick(() => {
-        this.$refs['emoji-groups'].scrollTop = top + 1
-      })
+      this.$refs['emoji-groups'].scrollToItem(index)
     },
     updateScrolledClass (target) {
       if (target.scrollTop <= 5) {
@@ -238,6 +224,9 @@ const EmojiPicker = {
     }
   },
   computed: {
+    minItemSize () {
+      return 32
+    },
     activeGroupView () {
       return this.showingStickers ? '' : this.activeGroup
     },
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index 53363ec1..dda12197 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -74,6 +74,7 @@ $emoji-picker-emoji-size: 32px;
   }
 
   .emoji-groups {
+    height: 100%;
     min-height: 200px;
   }
 
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index d0b7fe8f..15cdb704 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -13,7 +13,7 @@
           class="emoji-tabs"
         >
           <span
-            v-for="group in filteredEmojiGroups"
+            v-for="(group, index) in filteredEmojiGroups"
             :ref="setGroupRef('group-header-' + group.id)"
             :key="group.id"
             class="emoji-tabs-item"
@@ -21,7 +21,7 @@
               active: activeGroupView === group.id
             }"
             :title="group.text"
-            @click.prevent="highlight(group.id)"
+            @click.prevent="highlight(index)"
           >
             <span
               v-if="group.image"
@@ -74,45 +74,52 @@
               @input="$event.target.composing = false"
             >
           </div>
-          <div
+          <DynamicScroller
             ref="emoji-groups"
             class="emoji-groups"
             :class="groupsScrolledClass"
-            @scroll="onScroll"
+            :min-item-size="minItemSize"
+            :items="filteredEmojiGroups"
+            @update="onScroll"
           >
-            <div
-              v-for="group in filteredEmojiGroups"
-              :key="group.id"
-              class="emoji-group"
-            >
-              <h6
-                :ref="setGroupRef('group-' + group.id)"
-                class="emoji-group-title"
-              >
-                {{ group.text }}
-              </h6>
-              <span
-                v-for="emoji in group.emojis"
-                :key="group.id + emoji.displayText"
-                :title="maybeLocalizedEmojiName(emoji)"
-                class="emoji-item"
-                @click.stop.prevent="onEmoji(emoji)"
+            <template #default="{ item: group, index, active }">
+              <DynamicScrollerItem
+                :item="group"
+                :active="active"
+                :data-index="index"
+                :size-dependencies="[group.emojis.length]"
               >
-                <span
-                  v-if="!emoji.imageUrl"
-                  class="emoji-picker-emoji -unicode"
-                >{{ emoji.replacement }}</span>
-                <still-image
-                  v-else
-                  class="emoji-picker-emoji -custom"
-                  loading="lazy"
-                  :src="emoji.imageUrl"
-                  :data-emoji-name="group.id + emoji.displayText"
-                />
-              </span>
-              <span :ref="setGroupRef('group-end-' + group.id)" />
-            </div>
-          </div>
+                <div
+                  class="emoji-group"
+                >
+                  <h6
+                    class="emoji-group-title"
+                  >
+                    {{ group.text }}
+                  </h6>
+                  <span
+                    v-for="emoji in group.emojis"
+                    :key="group.id + emoji.displayText"
+                    :title="maybeLocalizedEmojiName(emoji)"
+                    class="emoji-item"
+                    @click.stop.prevent="onEmoji(emoji)"
+                  >
+                    <span
+                      v-if="!emoji.imageUrl"
+                      class="emoji-picker-emoji -unicode"
+                    >{{ emoji.replacement }}</span>
+                    <still-image
+                      v-else
+                      class="emoji-picker-emoji -custom"
+                      loading="lazy"
+                      :src="emoji.imageUrl"
+                      :data-emoji-name="group.id + emoji.displayText"
+                    />
+                  </span>
+                </div>
+              </DynamicScrollerItem>
+            </template>
+          </DynamicScroller>
           <div class="keep-open">
             <Checkbox v-model="keepOpen">
               {{ $t('emoji.keep_open') }}
diff --git a/yarn.lock b/yarn.lock
index dc2050ca..7b45ee14 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6370,6 +6370,11 @@ minimist@^1.2.5:
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
   integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
 
+mitt@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
+  integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
+
 mkdirp@^0.5.1:
   version "0.5.1"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@@ -8805,6 +8810,16 @@ vue-loader@17.0.1:
     hash-sum "^2.0.0"
     loader-utils "^2.0.0"
 
+vue-observe-visibility@^2.0.0-alpha.1:
+  version "2.0.0-alpha.1"
+  resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz#1e4eda7b12562161d58984b7e0dea676d83bdb13"
+  integrity sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==
+
+vue-resize@^2.0.0-alpha.1:
+  version "2.0.0-alpha.1"
+  resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz#43eeb79e74febe932b9b20c5c57e0ebc14e2df3a"
+  integrity sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==
+
 vue-router@4.1.6:
   version "4.1.6"
   resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.6.tgz#b70303737e12b4814578d21d68d21618469375a1"
@@ -8828,6 +8843,15 @@ vue-template-compiler@2.7.14:
     de-indent "^1.0.2"
     he "^1.2.0"
 
+vue-virtual-scroller@^2.0.0-beta.7:
+  version "2.0.0-beta.7"
+  resolved "https://registry.yarnpkg.com/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.7.tgz#4ea8158638c84b2033b001a8b26c5fcb6896b271"
+  integrity sha512-OrouVj1i2939jaLjVfu8f5fsDlbzhAb4bOsYZYrAkpcVLylAmMoGtIL7eT3hJrdTiaKbwQpRdnv7DKf9Fn+tHg==
+  dependencies:
+    mitt "^2.1.0"
+    vue-observe-visibility "^2.0.0-alpha.1"
+    vue-resize "^2.0.0-alpha.1"
+
 vue@3.2.45:
   version "3.2.45"
   resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8"
-- 
cgit v1.2.3-70-g09d2


From 314a4474f6475435cfac7e5e02862015a9455660 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Mon, 2 Jan 2023 12:40:03 -0500
Subject: Fix header indicator

---
 src/components/emoji_picker/emoji_picker.js  | 28 ++++++++++++++++++++++++----
 src/components/emoji_picker/emoji_picker.vue |  2 ++
 2 files changed, 26 insertions(+), 4 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index c87dea7e..9c97e16c 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -81,6 +81,13 @@ const filterByKeyword = (list, keyword = '', languages, nameLocalizer) => {
   return orderedEmojiList.flat()
 }
 
+const getOffset = (elem) => {
+  const style = elem.style.transform
+  const res = /translateY\((\d+)px\)/.exec(style)
+  if (!res) { return 0 }
+  return res[1]
+}
+
 const EmojiPicker = {
   props: {
     enableStickerPicker: {
@@ -144,12 +151,25 @@ const EmojiPicker = {
       this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
     },
     onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) {
+      console.log('onScroll', startIndex, endIndex, visibleStartIndex, visibleEndIndex)
       const current = this.filteredEmojiGroups[visibleStartIndex].id
-      this.scrolledGroup(current)
+      const target = this.$refs['emoji-groups'].$el
+      this.scrolledGroup(target, current, visibleStartIndex, visibleEndIndex)
     },
-    scrolledGroup (groupId) {
-      this.activeGroup = groupId
-      this.scrollHeader()
+    scrolledGroup (target, groupId, start, end) {
+      const top = target.scrollTop + 5
+      this.$nextTick(() => {
+        this.filteredEmojiGroups.slice(start, end + 1).forEach(group => {
+          const ref = this.groupRefs['group-' + group.id]
+          if (!ref) { return }
+          const elem = ref.$el.parentElement
+          if (!elem) { return }
+          if (elem && getOffset(elem) <= top) {
+            this.activeGroup = group.id
+          }
+        })
+        this.scrollHeader()
+      })
     },
     scrollHeader () {
       // Scroll the active tab's header into view
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 15cdb704..78da4808 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -80,10 +80,12 @@
             :class="groupsScrolledClass"
             :min-item-size="minItemSize"
             :items="filteredEmojiGroups"
+            :emit-update="true"
             @update="onScroll"
           >
             <template #default="{ item: group, index, active }">
               <DynamicScrollerItem
+                :ref="setGroupRef('group-' + group.id)"
                 :item="group"
                 :active="active"
                 :data-index="index"
-- 
cgit v1.2.3-70-g09d2


From 6cc3b239f6f096f22139d5dbc543852a5e89ea1e Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Mon, 2 Jan 2023 13:25:59 -0500
Subject: Load emoji row by row

---
 src/components/emoji_picker/emoji_picker.js  | 45 +++++++++++++++++++++++-----
 src/components/emoji_picker/emoji_picker.vue |  3 +-
 2 files changed, 39 insertions(+), 9 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 9c97e16c..39a514a7 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -18,7 +18,7 @@ import {
   faCode,
   faFlag
 } from '@fortawesome/free-solid-svg-icons'
-import { debounce, trim } from 'lodash'
+import { debounce, trim, chunk } from 'lodash'
 
 library.add(
   faBoxOpen,
@@ -88,6 +88,10 @@ const getOffset = (elem) => {
   return res[1]
 }
 
+const toHeaderId = id => {
+  return id.replace(/^row-\d+-/, '')
+}
+
 const EmojiPicker = {
   props: {
     enableStickerPicker: {
@@ -152,20 +156,20 @@ const EmojiPicker = {
     },
     onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) {
       console.log('onScroll', startIndex, endIndex, visibleStartIndex, visibleEndIndex)
-      const current = this.filteredEmojiGroups[visibleStartIndex].id
       const target = this.$refs['emoji-groups'].$el
-      this.scrolledGroup(target, current, visibleStartIndex, visibleEndIndex)
+      this.scrolledGroup(target, visibleStartIndex, visibleEndIndex)
     },
-    scrolledGroup (target, groupId, start, end) {
+    scrolledGroup (target, start, end) {
       const top = target.scrollTop + 5
       this.$nextTick(() => {
-        this.filteredEmojiGroups.slice(start, end + 1).forEach(group => {
+        this.emojiItems.slice(start, end + 1).forEach(group => {
+          const headerId = toHeaderId(group.id)
           const ref = this.groupRefs['group-' + group.id]
           if (!ref) { return }
           const elem = ref.$el.parentElement
           if (!elem) { return }
           if (elem && getOffset(elem) <= top) {
-            this.activeGroup = group.id
+            this.activeGroup = headerId
           }
         })
         this.scrollHeader()
@@ -190,7 +194,12 @@ const EmojiPicker = {
     },
     highlight (index) {
       this.setShowStickers(false)
-      this.$refs['emoji-groups'].scrollToItem(index)
+      const item = this.filteredEmojiGroups[index]
+      if (!item) {
+        return
+      }
+      const indexInList = this.emojiItems.findIndex(k => k.id === item.id)
+      this.$refs['emoji-groups'].scrollToItem(indexInList)
     },
     updateScrolledClass (target) {
       if (target.scrollTop <= 5) {
@@ -245,7 +254,16 @@ const EmojiPicker = {
   },
   computed: {
     minItemSize () {
-      return 32
+      return this.emojiHeight
+    },
+    emojiHeight () {
+      return 32 + 4
+    },
+    emojiWidth () {
+      return 32 + 4
+    },
+    itemPerRow () {
+      return 6
     },
     activeGroupView () {
       return this.showingStickers ? '' : this.activeGroup
@@ -287,6 +305,17 @@ const EmojiPicker = {
         this.filteredEmojiGroups = this.getFilteredEmojiGroups()
       }, 500)
     },
+    emojiItems () {
+      return this.filteredEmojiGroups.map(group =>
+        chunk(group.emojis, this.itemPerRow)
+          .map((items, index) => ({
+            ...group,
+            id: index === 0 ? group.id : `row-${index}-${group.id}`,
+            emojis: items,
+            isFirstRow: index === 0
+          })))
+        .reduce((a, c) => a.concat(c), [])
+    },
     languages () {
       return ensureFinalFallback(this.$store.getters.mergedConfig.interfaceLanguage)
     },
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 78da4808..5d8b0431 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -79,7 +79,7 @@
             class="emoji-groups"
             :class="groupsScrolledClass"
             :min-item-size="minItemSize"
-            :items="filteredEmojiGroups"
+            :items="emojiItems"
             :emit-update="true"
             @update="onScroll"
           >
@@ -95,6 +95,7 @@
                   class="emoji-group"
                 >
                   <h6
+                    v-if="group.isFirstRow"
                     class="emoji-group-title"
                   >
                     {{ group.text }}
-- 
cgit v1.2.3-70-g09d2


From 081a4161034ce6d748a11e260b7a9429c65aab9d Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Mon, 2 Jan 2023 13:42:09 -0500
Subject: Calculate display count from width

---
 src/components/emoji_picker/emoji_picker.js  | 18 +++++++++++++++---
 src/components/emoji_picker/emoji_picker.vue |  1 +
 2 files changed, 16 insertions(+), 3 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 39a514a7..ca2a3683 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -112,7 +112,8 @@ const EmojiPicker = {
       contentLoaded: false,
       groupRefs: {},
       emojiRefs: {},
-      filteredEmojiGroups: []
+      filteredEmojiGroups: [],
+      width: 0
     }
   },
   components: {
@@ -155,7 +156,6 @@ const EmojiPicker = {
       this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
     },
     onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) {
-      console.log('onScroll', startIndex, endIndex, visibleStartIndex, visibleEndIndex)
       const target = this.$refs['emoji-groups'].$el
       this.scrolledGroup(target, visibleStartIndex, visibleEndIndex)
     },
@@ -221,6 +221,7 @@ const EmojiPicker = {
     },
     onShowing () {
       const oldContentLoaded = this.contentLoaded
+      this.recalculateItemPerRow()
       this.$nextTick(() => {
         this.$refs.search.focus()
       })
@@ -241,6 +242,14 @@ const EmojiPicker = {
           emojis: this.filterByKeyword(group.emojis, trim(this.keyword))
         }))
         .filter(group => group.emojis.length > 0)
+    },
+    recalculateItemPerRow () {
+      this.$nextTick(() => {
+        if (!this.$refs['emoji-groups']) {
+          return
+        }
+        this.width = this.$refs['emoji-groups'].$el.offsetWidth
+      })
     }
   },
   watch: {
@@ -252,6 +261,9 @@ const EmojiPicker = {
       this.filteredEmojiGroups = this.getFilteredEmojiGroups()
     }
   },
+  mounted () {
+    this.recalculateItemPerRow()
+  },
   computed: {
     minItemSize () {
       return this.emojiHeight
@@ -263,7 +275,7 @@ const EmojiPicker = {
       return 32 + 4
     },
     itemPerRow () {
-      return 6
+      return this.width ? Math.floor(this.width / this.emojiWidth - 1) : 6
     },
     activeGroupView () {
       return this.showingStickers ? '' : this.activeGroup
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 5d8b0431..ae4683f5 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -82,6 +82,7 @@
             :items="emojiItems"
             :emit-update="true"
             @update="onScroll"
+            @visible="recalculateItemPerRow"
           >
             <template #default="{ item: group, index, active }">
               <DynamicScrollerItem
-- 
cgit v1.2.3-70-g09d2


From 47af5419b13688893a38c34fd55f4edf58dad6b2 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Mon, 2 Jan 2023 14:01:56 -0500
Subject: Clean up code

---
 src/components/emoji_picker/emoji_picker.js  | 11 ++---------
 src/components/emoji_picker/emoji_picker.vue |  4 ++--
 2 files changed, 4 insertions(+), 11 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index ca2a3683..4a447905 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -192,13 +192,9 @@ const EmojiPicker = {
         setScroll(right + margin - headerCont.clientWidth)
       }
     },
-    highlight (index) {
+    highlight (groupId) {
       this.setShowStickers(false)
-      const item = this.filteredEmojiGroups[index]
-      if (!item) {
-        return
-      }
-      const indexInList = this.emojiItems.findIndex(k => k.id === item.id)
+      const indexInList = this.emojiItems.findIndex(k => k.id === groupId)
       this.$refs['emoji-groups'].scrollToItem(indexInList)
     },
     updateScrolledClass (target) {
@@ -261,9 +257,6 @@ const EmojiPicker = {
       this.filteredEmojiGroups = this.getFilteredEmojiGroups()
     }
   },
-  mounted () {
-    this.recalculateItemPerRow()
-  },
   computed: {
     minItemSize () {
       return this.emojiHeight
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index ae4683f5..453ecdfc 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -13,7 +13,7 @@
           class="emoji-tabs"
         >
           <span
-            v-for="(group, index) in filteredEmojiGroups"
+            v-for="group in filteredEmojiGroups"
             :ref="setGroupRef('group-header-' + group.id)"
             :key="group.id"
             class="emoji-tabs-item"
@@ -21,7 +21,7 @@
               active: activeGroupView === group.id
             }"
             :title="group.text"
-            @click.prevent="highlight(index)"
+            @click.prevent="highlight(group.id)"
           >
             <span
               v-if="group.image"
-- 
cgit v1.2.3-70-g09d2


From 76019d1e0349ecf170d660b8324145677b1e472c Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Fri, 6 Jan 2023 13:14:38 -0500
Subject: Fix emoji picker off-by-1 error

---
 src/components/emoji_picker/emoji_picker.js   | 2 +-
 src/components/emoji_picker/emoji_picker.scss | 2 +-
 src/components/emoji_picker/emoji_picker.vue  | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 4a447905..0d7ca812 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -244,7 +244,7 @@ const EmojiPicker = {
         if (!this.$refs['emoji-groups']) {
           return
         }
-        this.width = this.$refs['emoji-groups'].$el.offsetWidth
+        this.width = this.$refs['emoji-groups'].$el.clientWidth
       })
     }
   },
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index dda12197..848d435a 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -7,7 +7,7 @@ $emoji-picker-emoji-size: 32px;
 
 .emoji-picker {
   width: 25em;
-  max-width: 100vw;
+  max-width: calc(100vw - 20px); // popover gives 10px margin from window edge
   display: flex;
   flex-direction: column;
   background-color: $fallback--bg;
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 453ecdfc..ca90bf26 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -83,6 +83,7 @@
             :emit-update="true"
             @update="onScroll"
             @visible="recalculateItemPerRow"
+            @resize="recalculateItemPerRow"
           >
             <template #default="{ item: group, index, active }">
               <DynamicScrollerItem
-- 
cgit v1.2.3-70-g09d2


From d1590311211cbf1036c870eef8c7e9e80fab7a3e Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Sat, 21 Jan 2023 16:28:33 -0500
Subject: Add some aria to post status form

---
 src/components/emoji_input/emoji_input.vue           |  3 +++
 src/components/emoji_picker/emoji_picker.vue         |  1 +
 src/components/post_status_form/post_status_form.vue | 10 ++++++++++
 src/components/select/select.js                      |  3 ++-
 src/components/select/select.vue                     |  1 +
 src/i18n/en.json                                     |  2 ++
 6 files changed, 19 insertions(+), 1 deletion(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index 4a7b0fa8..7f9ecc99 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -16,6 +16,7 @@
       ref="hiddenOverlay"
       class="hidden-overlay"
       :style="overlayStyle"
+      :aria-hidden="true"
     >
       <span>{{ preText }}</span>
       <span
@@ -33,6 +34,7 @@
         v-if="!hideEmojiButton"
         class="button-unstyled emoji-picker-icon"
         type="button"
+        :title="$t('emoji.add_emoji')"
         @click.prevent="togglePicker"
       >
         <FAIcon :icon="['far', 'smile-beam']" />
@@ -53,6 +55,7 @@
       ref="suggestorPopover"
       class="autocomplete-panel"
       placement="bottom"
+      :trigger-attrs="{ 'aria-hidden': true }"
     >
       <template #content>
         <div
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index ca90bf26..6972164b 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -3,6 +3,7 @@
     ref="popover"
     trigger="click"
     popover-class="emoji-picker popover-default"
+    :trigger-attrs="{ 'aria-hidden': true }"
     @show="onPopoverShown"
     @close="onPopoverClosed"
   >
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 328e145f..64a8887c 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -30,6 +30,9 @@
           <span>{{ $t('post_status.scope_notice.public') }}</span>
           <a
             class="fa-scale-110 fa-old-padding dismiss"
+            :title="$t('post_status.scope_notice_dismiss')"
+            role="button"
+            tabindex="0"
             @click.prevent="dismissScopeNotice()"
           >
             <FAIcon icon="times" />
@@ -42,6 +45,9 @@
           <span>{{ $t('post_status.scope_notice.unlisted') }}</span>
           <a
             class="fa-scale-110 fa-old-padding dismiss"
+            :title="$t('post_status.scope_notice_dismiss')"
+            role="button"
+            tabindex="0"
             @click.prevent="dismissScopeNotice()"
           >
             <FAIcon icon="times" />
@@ -54,6 +60,9 @@
           <span>{{ $t('post_status.scope_notice.private') }}</span>
           <a
             class="fa-scale-110 fa-old-padding dismiss"
+            :title="$t('post_status.scope_notice_dismiss')"
+            role="button"
+            tabindex="0"
             @click.prevent="dismissScopeNotice()"
           >
             <FAIcon icon="times" />
@@ -199,6 +208,7 @@
               id="post-content-type"
               v-model="newStatus.contentType"
               class="form-control"
+              :attrs="{ 'aria-label': $t('post_status.content_type_selection') }"
             >
               <option
                 v-for="postFormat in postFormats"
diff --git a/src/components/select/select.js b/src/components/select/select.js
index ec571a14..34d64fd2 100644
--- a/src/components/select/select.js
+++ b/src/components/select/select.js
@@ -13,6 +13,7 @@ export default {
     'modelValue',
     'disabled',
     'unstyled',
-    'kind'
+    'kind',
+    'attrs'
   ]
 }
diff --git a/src/components/select/select.vue b/src/components/select/select.vue
index 0ce4ea82..1797afc8 100644
--- a/src/components/select/select.vue
+++ b/src/components/select/select.vue
@@ -6,6 +6,7 @@
     <select
       :disabled="disabled"
       :value="modelValue"
+      v-bind="attrs"
       @change="$emit('update:modelValue', $event.target.value)"
     >
       <slot />
diff --git a/src/i18n/en.json b/src/i18n/en.json
index ebd7d0af..d0965f84 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -266,6 +266,7 @@
       "text/markdown": "Markdown",
       "text/bbcode": "BBCode"
     },
+    "content_type_selection": "Post format",
     "content_warning": "Subject (optional)",
     "default": "Just landed in L.A.",
     "direct_warning_to_all": "This post will be visible to all the mentioned users.",
@@ -283,6 +284,7 @@
       "private": "This post will be visible to your followers only",
       "unlisted": "This post will not be visible in Public Timeline and The Whole Known Network"
     },
+    "scope_notice_dismiss": "Close this notice",
     "scope": {
       "direct": "Direct - post to mentioned users only",
       "private": "Followers-only - post to followers only",
-- 
cgit v1.2.3-70-g09d2


From 96ef76f1d76df7bd1e216524d5fe429830146aa6 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Sun, 18 Jun 2023 15:44:19 -0400
Subject: Make emoji picker buttons accessible

---
 src/components/emoji_picker/emoji_picker.vue | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 6972164b..3319dace 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -22,6 +22,7 @@
               active: activeGroupView === group.id
             }"
             :title="group.text"
+            role="button"
             @click.prevent="highlight(group.id)"
           >
             <span
@@ -108,6 +109,7 @@
                     :key="group.id + emoji.displayText"
                     :title="maybeLocalizedEmojiName(emoji)"
                     class="emoji-item"
+                    role="button"
                     @click.stop.prevent="onEmoji(emoji)"
                   >
                     <span
@@ -118,6 +120,7 @@
                       v-else
                       class="emoji-picker-emoji -custom"
                       loading="lazy"
+                      :alt="maybeLocalizedEmojiName(emoji)"
                       :src="emoji.imageUrl"
                       :data-emoji-name="group.id + emoji.displayText"
                     />
-- 
cgit v1.2.3-70-g09d2


From 09402e2537e0c43c52bd8345301885647e841ed1 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Thu, 29 Jun 2023 11:31:07 -0400
Subject: Fix scrolling emoji selector in modal in safari ios

---
 changelog.d/scroll-emoji-selector-safari.fix | 1 +
 src/components/emoji_picker/emoji_picker.js  | 4 ++++
 src/components/emoji_picker/emoji_picker.vue | 2 ++
 3 files changed, 7 insertions(+)
 create mode 100644 changelog.d/scroll-emoji-selector-safari.fix

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/changelog.d/scroll-emoji-selector-safari.fix b/changelog.d/scroll-emoji-selector-safari.fix
new file mode 100644
index 00000000..3f5dda7d
--- /dev/null
+++ b/changelog.d/scroll-emoji-selector-safari.fix
@@ -0,0 +1 @@
+Fix scrolling emoji selector in modal in safari ios
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 349b043d..30c01aa5 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -105,6 +105,7 @@ const EmojiPicker = {
       default: false
     }
   },
+  inject: ['popoversZLayer'],
   data () {
     return {
       keyword: '',
@@ -350,6 +351,9 @@ const EmojiPicker = {
 
         return emoji.displayText
       }
+    },
+    isInModal () {
+      return this.popoversZLayer === 'modals'
     }
   }
 }
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 6972164b..3e77d523 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -12,6 +12,7 @@
         <span
           ref="header"
           class="emoji-tabs"
+          v-body-scroll-lock="isInModal"
         >
           <span
             v-for="group in filteredEmojiGroups"
@@ -78,6 +79,7 @@
           <DynamicScroller
             ref="emoji-groups"
             class="emoji-groups"
+            v-body-scroll-lock="isInModal"
             :class="groupsScrolledClass"
             :min-item-size="minItemSize"
             :items="emojiItems"
-- 
cgit v1.2.3-70-g09d2


From bf5bd4235d9de636566ba804580136cfd58980a0 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Thu, 29 Jun 2023 11:40:33 -0400
Subject: Comment the v-body-scroll-lock usage in code

---
 src/components/emoji_picker/emoji_picker.vue | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 3e77d523..aacd7a22 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -12,6 +12,11 @@
         <span
           ref="header"
           class="emoji-tabs"
+          <!--
+            Body scroll lock needs to be on every scrollable element on safari iOS.
+            Here we tell it to enable scrolling for this element.
+            See https://github.com/willmcpo/body-scroll-lock#vanilla-js
+          -->
           v-body-scroll-lock="isInModal"
         >
           <span
@@ -79,6 +84,7 @@
           <DynamicScroller
             ref="emoji-groups"
             class="emoji-groups"
+            <!-- Enables scrolling for this element on safari iOS. See comments for header. -->
             v-body-scroll-lock="isInModal"
             :class="groupsScrolledClass"
             :min-item-size="minItemSize"
-- 
cgit v1.2.3-70-g09d2


From 9fa0c05b35d175a8186899ec46933bf437a2444c Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Thu, 29 Jun 2023 11:43:49 -0400
Subject: Fix lint

---
 src/components/emoji_picker/emoji_picker.vue | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'src/components/emoji_picker/emoji_picker.vue')

diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index aacd7a22..227d7718 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -9,15 +9,15 @@
   >
     <template #content>
       <div class="heading">
+        <!--
+          Body scroll lock needs to be on every scrollable element on safari iOS.
+          Here we tell it to enable scrolling for this element.
+          See https://github.com/willmcpo/body-scroll-lock#vanilla-js
+        -->
         <span
           ref="header"
-          class="emoji-tabs"
-          <!--
-            Body scroll lock needs to be on every scrollable element on safari iOS.
-            Here we tell it to enable scrolling for this element.
-            See https://github.com/willmcpo/body-scroll-lock#vanilla-js
-          -->
           v-body-scroll-lock="isInModal"
+          class="emoji-tabs"
         >
           <span
             v-for="group in filteredEmojiGroups"
@@ -81,11 +81,11 @@
               @input="$event.target.composing = false"
             >
           </div>
+          <!-- Enables scrolling for this element on safari iOS. See comments for header. -->
           <DynamicScroller
             ref="emoji-groups"
-            class="emoji-groups"
-            <!-- Enables scrolling for this element on safari iOS. See comments for header. -->
             v-body-scroll-lock="isInModal"
+            class="emoji-groups"
             :class="groupsScrolledClass"
             :min-item-size="minItemSize"
             :items="emojiItems"
-- 
cgit v1.2.3-70-g09d2

