ycs77 / headlessui-float

Easily use Headless UI with Floating UI to position floating elements.
https://headlessui-float.vercel.app
MIT License
348 stars 13 forks source link

Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element' #80

Closed vincerubinetti closed 1 year ago

vincerubinetti commented 1 year ago

Use Version

"@headlessui-float/vue": "^0.11.3", "@headlessui/vue": "^1.7.16", "vue": "^3.3.4", "@floating-ui/core@^1.0.0", "@floating-ui/core@^1.4.1" "@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.2.1" Chrome

Describe the bug

Getting the error Uncaught (in promise) TypeError: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. in the console. Otherwise, everything seems to be behaving just fine.

To Reproduce

I have this custom component:

<template>
  <div class="container">
    <Listbox
      v-slot="{ open }"
      :model-value="modelValue"
      :multiple="multi"
      @update:model-value="(value) => emit('update:modelValue', value)"
    >
      <ListboxLabel>{{ label }}</ListboxLabel>
      <Float :shift="10" floating-as="template">
        <ListboxButton class="button">
          <span>{{ selectedLabel }}</span>
          <font-awesome-icon :icon="open ? faAngleUp : faAngleDown" />
        </ListboxButton>
        <ListboxOptions>
          <ListboxOption
            v-for="option in options"
            v-slot="{ active, selected }"
            :key="option"
            as="template"
            :value="option"
          >
            <li :class="{ active, selected }">
              <font-awesome-icon
                :style="{ opacity: selected ? 1 : 0 }"
                :icon="faCheck"
              />
              <span>{{ option }}</span>
            </li>
          </ListboxOption>
        </ListboxOptions>
      </Float>
    </Listbox>
  </div>
</template>

<script setup>
import { computed } from "vue";
import {
  faAngleDown,
  faAngleUp,
  faCheck,
} from "@fortawesome/free-solid-svg-icons";
import { Float } from "@headlessui-float/vue";
import {
  Listbox,
  ListboxButton,
  ListboxLabel,
  ListboxOption,
  ListboxOptions,
} from "@headlessui/vue";

const props = defineProps({
  label: {
    type: String,
    required: true,
  },
  options: {
    type: Array,
    required: true,
  },
  multi: {
    type: Boolean,
    required: false,
    default: false,
  },
  modelValue: {
    type: [String, Array],
    required: true,
  },
});

const emit = defineEmits(["update:modelValue"]);

// label to show as selected value in box
const selectedLabel = computed(() => {
  if (!props.multi) return props.modelValue;
  if (props.modelValue.length === 0) return "None selected";
  if (props.modelValue.length === 1) return props.modelValue[0];
  if (props.modelValue.length === props.options.length) return "All selected";
  return props.modelValue.length + " selected";
});
</script>

And I'm using it like this:

<template>
  <AppSelect v-model="selectedSingle" label="Single" :options="people" />
  <AppSelect
    v-model="selectedMulti"
    label="Multi"
    :options="people"
    :multi="true"
  />
</template>

<script setup>
import { ref } from "vue";
import AppSelect from "@/components/AppSelect.vue";

const people = [
  "Durward Reynolds",
  "Kenton Towne",
  "Therese Wunsch",
  "Benedict Kessler",
  "Katelyn Rohan",
];
const selectedSingle = ref(people[0]);
const selectedMulti = ref([people[0]]);
</script>

The error is only occurring when the component is in single-select-mode, and happens when selecting. I have a feeling it's related to the dropdown component unmounting and the dom element reference disappearing before floating UI is finished using it.

vincerubinetti commented 1 year ago

Making my @update:model-value emit after a 0 or more timeout (making it asynchronous) removes the error. Strange.

ycs77 commented 1 year ago

Fixed in v0.11.4