diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md index 4dd6dfa727..0873634280 100644 --- a/packages/@headlessui-vue/CHANGELOG.md +++ b/packages/@headlessui-vue/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Disable `ComboboxInput` when its `Combobox` is disabled ([#2375](https://github.com/tailwindlabs/headlessui/pull/2375)) - Add `FocusTrap` event listeners once document has loaded ([#2389](https://github.com/tailwindlabs/headlessui/pull/2389)) - Don't scroll-lock `` when wrapping transition isn't showing ([#2422](https://github.com/tailwindlabs/headlessui/pull/2422)) +- Ensure DOM `ref` is properly handled in the `RadioGroup` component ([#2424](https://github.com/tailwindlabs/headlessui/pull/2424)) ### Added diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts index 4d39fbd297..3c066fb37e 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts @@ -1523,6 +1523,33 @@ describe('Rendering', () => { expect(handleChange).toHaveBeenNthCalledWith(2, 'bob') }) }) + + it( + 'should be possible to use a custom component using the `as` prop without crashing', + suppressConsoleLogs(async () => { + let CustomComponent = defineComponent({ + template: html``, + }) + + renderTemplate({ + template: html` + + + + + Alice + Bob + Charlie + + + `, + setup: () => ({ CustomComponent }), + }) + + // Open combobox + await click(getComboboxButton()) + }) + ) }) describe('Rendering composition', () => { diff --git a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx index a40bbd1341..56a8ab8b0a 100644 --- a/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx +++ b/packages/@headlessui-vue/src/components/listbox/listbox.test.tsx @@ -1270,6 +1270,32 @@ describe('Rendering', () => { expect(handleChange).toHaveBeenNthCalledWith(2, 'bob') }) }) + + it( + 'should be possible to use a custom component using the `as` prop without crashing', + suppressConsoleLogs(async () => { + let CustomComponent = defineComponent({ + template: html``, + }) + + renderTemplate({ + template: html` + + + + Alice + Bob + Charlie + + + `, + setup: () => ({ CustomComponent }), + }) + + // Open listbox + await click(getListboxButton()) + }) + ) }) describe('Rendering composition', () => { diff --git a/packages/@headlessui-vue/src/components/menu/menu.test.tsx b/packages/@headlessui-vue/src/components/menu/menu.test.tsx index 8f87562c15..9b1e9bcc1e 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.test.tsx +++ b/packages/@headlessui-vue/src/components/menu/menu.test.tsx @@ -818,6 +818,32 @@ describe('Rendering', () => { // Verify that the third menu item is active assertMenuLinkedWithMenuItem(items[2]) }) + + it( + 'should be possible to use a custom component using the `as` prop without crashing', + suppressConsoleLogs(async () => { + let CustomComponent = defineComponent({ + template: ``, + }) + + renderTemplate({ + template: ` + + + + Alice + Bob + Charlie + + + `, + setup: () => ({ CustomComponent }), + }) + + // Open menu + await click(getMenuButton()) + }) + ) }) describe('Rendering composition', () => { diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts index 6cb0e4ce59..1a4cc83b11 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.test.ts @@ -1,4 +1,4 @@ -import { nextTick, ref, watch, reactive } from 'vue' +import { nextTick, ref, watch, reactive, defineComponent, defineExpose } from 'vue' import { createRenderTemplate, render } from '../../test-utils/vue-testing-library' import { RadioGroup, RadioGroupOption, RadioGroupLabel, RadioGroupDescription } from './radio-group' @@ -496,6 +496,26 @@ describe('Rendering', () => { assertActiveElement(getByText('Option 3')) }) + it( + 'should be possible to use a custom component using the `as` prop without crashing', + suppressConsoleLogs(async () => { + let CustomComponent = defineComponent({ + template: html``, + }) + + renderTemplate({ + template: html` + + Alice + Bob + Charlie + + `, + setup: () => ({ CustomComponent }), + }) + }) + ) + describe('Equality', () => { let options = [ { id: 1, name: 'Alice' }, diff --git a/packages/@headlessui-vue/src/components/radio-group/radio-group.ts b/packages/@headlessui-vue/src/components/radio-group/radio-group.ts index a198d19975..e320a54610 100644 --- a/packages/@headlessui-vue/src/components/radio-group/radio-group.ts +++ b/packages/@headlessui-vue/src/components/radio-group/radio-group.ts @@ -272,7 +272,7 @@ export let RadioGroup = defineComponent({ : []), render({ ourProps, - theirProps: { ...attrs, ...omit(theirProps, ['modelValue', 'defaultValue']) }, + theirProps: { ...attrs, ...omit(theirProps, ['modelValue', 'defaultValue', 'by']) }, slot: {}, attrs, slots, @@ -309,7 +309,8 @@ export let RadioGroupOption = defineComponent({ expose({ el: optionRef, $el: optionRef }) - onMounted(() => api.registerOption({ id: props.id, element: optionRef, propsRef })) + let element = computed(() => dom(optionRef)) + onMounted(() => api.registerOption({ id: props.id, element, propsRef })) onUnmounted(() => api.unregisterOption(props.id)) let isFirstOption = computed(() => api.firstOption.value?.id === props.id) @@ -326,7 +327,7 @@ export let RadioGroupOption = defineComponent({ if (!api.change(props.value)) return state.value |= OptionState.Active - optionRef.value?.focus() + dom(optionRef)?.focus() } function handleFocus() {