serebrov / emoji-mart-vue

One component to pick them all (performance improvements) 👊🏼
https://serebrov.github.io/emoji-mart-vue/
BSD 3-Clause "New" or "Revised" License
274 stars 48 forks source link

Categories displaying wrong because of vue-virtual-scroller #57

Closed apasov closed 5 years ago

apasov commented 5 years ago

I use this package in Quasar Framework dialog:

<q-dialog v-model="emojiPickerDialog">
    <emoji-picker :data="emojiIndex" :emojiSize="24" :native="true" @select="selectEmoji"></emoji-picker>
</q-dialog>

Here is what I get, emoji categories are not displayed properly:

image

BUT, when I enter any string in the search field:

image

And then press backspace until the search field is empty again, all goes as it should be:

image

I believe it's because of vue-virtual-scroller. Or maybe I am wrong?

Possible solution: remove or make vue-virtual-scroller optional as suggested in #52

serebrov commented 5 years ago

@apasov I am not 100% sure this is because of virtual scroller, but it might be, I'll need to check it. Do you have by chance some minimal working example that I can run locally and debug?

Also, when the picker is rendered initially, do you see any errors in the console (there might be some if this is a javascript problem, otherwise might be related to css).

serebrov commented 5 years ago

@apasov I've added a QDialog example to the demo app - https://serebrov.github.io/emoji-mart-vue/

It works fine for me, although I am not sure if I am using it the same way as you, when I just tried to insert the <picker>.. inside the <q-dialog>, it was empty, so I used body slot to show the content:

    <div class="row"></div>
    <h2>QDialog Example</h2>
    <div class="row">
      <q-btn label="Open QDialog" @click="emojiPickerDialog = true" />
    </div>

    <q-dialog v-model="emojiPickerDialog">
      <template v-slot:body>
        <picker :data="index" :emojiSize="24" :native="true"></picker>
      </template>
    </q-dialog>

So I am still not sure if this issue is related to #52.

apasov commented 5 years ago

@serebrov No, I don't see any js errors in console. I created a working example: https://github.com/apasov/emoji-mart-vue-error-reproduction

Please test on your local machine. For me it almost always works wrong, especially with dev console open and mobile screen simulation in Chrome. Sometimes as if by accident it displays properly, but after you close the popup and re-open it it gets broken again.

serebrov commented 5 years ago

@apasov thanks a lot for the example app, I see the issue now. I had a feeling I saw something very similar some time ago and after googling I found a link, to my surprise, to this repository :)

This is the same issue as in #50 and it is related to the virtual scroller: due to the animation of the dialog on open, virtual scroller doesn't get correct sizes for its elements (emoji categories), so the result is the overlap.

One workarond is to disable dialog animation, as mentioned in #50. Another one is to wait a bit for animation to complete and then render the emoji picker:

<template>
    <q-btn color="primary" label="Select emoji" @click="showDialog"/>

    <q-dialog v-model="emojiPickerDialog">
        <q-card-section>
          <emoji-picker v-if="dialogRendered" :data="emojiIndex" :emojiSize="24" :native="true" @select="selectEmoji"></emoji-picker>
        </q-card-section>
    </q-dialog>
</template>

<script>
import emojiData from 'emoji-mart-vue-fast/data/all'
import 'emoji-mart-vue-fast/css/emoji-mart.css'
import { Picker as EmojiPicker, EmojiIndex } from 'emoji-mart-vue-fast'

export default {
  name: 'PageIndex',
  data () {
    return {
      selectedEmoji: '',
      emojiPickerDialog: false,
      dialogRendered: false
    }
  },
  components: {
    EmojiPicker
  },
  created () {
    this.emojiIndex = new EmojiIndex(emojiData)
  },
  methods: {
    selectEmoji (emoji) {
      this.selectedEmoji = emoji.native
    },
    showDialog () {
      this.emojiPickerDialog = true
      setTimeout(() => {
        this.dialogRendered = true
      }, 50)
    }
  }
}
</script>
serebrov commented 5 years ago

And one more solution, without v-if and looks nicer for the user, but relies on vue-virtual-scroller internals to trigger the scoller update:

<template>
          <!-- here we add `ref="picker"` -->
          <emoji-picker ref="picker" :data="emojiIndex" :emojiSize="24" :native="true" @select="selectEmoji"></emoji-picker>
</template>

<script>
   // ...
    showDialog () {
      this.emojiPickerDialog = true
      setTimeout(() => {
        const dynScroller = this.$refs.picker.$refs.dynScroller
        dynScroller.forceUpdate()
      }, 500)
    }
</script>
apasov commented 5 years ago

@serebrov thank you for the quick fix! Aha, I see #50 is also related to Quasar Dialog. I used StaticPicker and it just worked perfectly. Maybe later I will try some of the workarounds, but currently StaticPicker is good enough for my project. Thanks again!