vue-final / vue-final-modal

🍕Vue Final Modal is a tiny, renderless, mobile-friendly, feature-rich modal component for Vue.js.
https://vue-final-modal.org
MIT License
864 stars 95 forks source link

Error on focus trap for modal inside RouterView #361

Closed DefJunx closed 1 year ago

DefJunx commented 1 year ago

Version

vue-final-modal: 4.3.1 vue: 3.2.45 vue-router: 4.1.6

OS

Windows

Steps to reproduce

I have the following modal defined (which is managed by vue-router):

<script setup lang="ts">
...
const props = withDefaults(
  defineProps<{
    itemId?: number;
    discounts?: Discount[];
  }>(),
  {
    discounts: (props) => reactive(Array.from({ length: MAX_DISCOUNTS_NUMBER }, () => discountFactory(props.itemId))),
  }
);

const emit = defineEmits<{
  (e: "update:modelValue", modelValue: boolean): void;
  (e: "onSaveButtonPressed", itemId: number, discountsToSave: Discount[]): void;
}>();
...
</script>

<template>
  <VueFinalModal
    class="modal-container discounts-modal"
    content-class="modal-quotes modal-content"
    @update:model-value="(val) => emit('update:modelValue', val)"
  >
    <button class="modal__close" @click.prevent="emit('update:modelValue', false)">X</button>
    <span class="modal__title">{{ $t("Discounts Management") }}</span>
    <div class="modal__content">
      <ErrorsContainer v-if="errors.length" :error-strings="errors" />
      <div class="discount-container">
        <div class="discount-header">
          <div></div>
          <div>
            <strong>{{ $t("Discount type") }}</strong>
          </div>
          <div>
            <strong>{{ $t("Discount amount") }}</strong>
          </div>
        </div>
        <div class="discount" v-for="(discount, idx) in props.discounts" :key="idx">
          <div>{{ idx + 1 }}.</div>
          <select v-model="discount.type" :disabled="shouldDisableDiscountCombo(idx)">
            <option :value="undefined">{{ $t("Select discount type") }}</option>
            <option
              v-if="idx === 0 || props.discounts[idx - 1].type === DISCOUNT_TYPE_AMOUNT"
              :value="DISCOUNT_TYPE_AMOUNT"
            >
              €
            </option>
            <option :value="DISCOUNT_TYPE_PERCENTAGE">%</option>
          </select>
          <input type="text" :disabled="discount.type === undefined" v-model="discount.amount" />
          <button @click.prevent="cleanDiscount(discount)" class="button button--icon" style="width: 120px">
            <img :src="trashIconSrc" alt="trash icon" />
          </button>
        </div>
      </div>
    </div>
    <div class="modal__action action-container">
      <button class="button button--cyan button--small" @click.prevent="onSaveButtonPressed">
        {{ $t("Save") }}
      </button>
      <button class="button button--cyan button--small" @click.prevent="emit('update:modelValue', false)">
        {{ $t("Cancel") }}
      </button>
    </div>
  </VueFinalModal>
</template>

which is called inside a component managed by vue-router:

<DiscountModal
    v-model="showDiscountsModal"
    :discounts="currentEditingDiscounts"
    :item-id="currentItemId!"
    @on-save-button-pressed="(itemId, discounts) => saveLineDiscounts(itemId, discounts)"
  />

But the modal won't open.

What is Expected?

The modal to open

What is actually happening?

The following console error which I can't figure out how to solve:

Uncaught Error: Your focus-trap must have at least one container with at least one tabbable node in it at all times
    at y (DiscountModal-87ebc22c.js:7:3990)
    at Object.activate (DiscountModal-87ebc22c.js:7:6823)
    at u (DiscountModal-87ebc22c.js:7:8821)
    at DiscountModal-87ebc22c.js:7:12136
DefJunx commented 1 year ago

Also, adding :focusTrap to false does not help as the panel doesn't open either

DefJunx commented 1 year ago

It was a class conflicting with my modal, keeping it at display:none and therefore breaking the focus trap.

I feel really silly, I'm sorry for opening this.