ensure we forward attributes when using providers

This commit is contained in:
Robin Malfait
2021-04-08 18:13:28 +02:00
parent a02c818f94
commit 2aa95f28c6
5 changed files with 135 additions and 4 deletions
@@ -75,15 +75,15 @@ export let Dialog = defineComponent({
},
render() {
let propsWeControl = {
// Manually passthrough the attributes, because Vue can't automatically pass
// it to the underlying div because of all the wrapper components below.
...this.$attrs,
ref: 'el',
id: this.id,
role: 'dialog',
'aria-modal': this.dialogState === DialogStates.Open ? true : undefined,
'aria-labelledby': this.titleId,
'aria-describedby': this.describedby,
// Manually passthrough the attributes, because Vue can't automatically pass
// it to the underlying div because of all the wrapper components below.
...this.$attrs,
}
let { open, onClose, initialFocus, ...passThroughProps } = this.$props
let containers = this.containers
@@ -244,6 +244,55 @@ describe('Rendering', () => {
`Dine in - ${JSON.stringify({ checked: false, active: false })}`
)
})
it('should be possible to put classes on a RadioGroup', async () => {
renderTemplate({
template: html`
<RadioGroup v-model="deliveryMethod" as="div" class="abc">
<RadioGroupLabel>Pizza Delivery</RadioGroupLabel>
<RadioGroupOption v-for="option in options" key="option.id" :value="option" v-slot="data"
>{{option.label}}</RadioGroupOption
>
</RadioGroup>
`,
setup() {
let deliveryMethod = ref(undefined)
let options = ref([{ id: 1, label: 'Pickup' }])
return { deliveryMethod, options }
},
})
await new Promise<void>(nextTick)
expect(document.querySelector('[id^="headlessui-radiogroup-"]')).toHaveClass('abc')
})
it('should be possible to put classes on a RadioGroupOption', async () => {
renderTemplate({
template: html`
<RadioGroup v-model="deliveryMethod">
<RadioGroupLabel>Pizza Delivery</RadioGroupLabel>
<RadioGroupOption
v-for="option in options"
key="option.id"
:value="option"
v-slot="data"
class="abc"
>{{option.label}}</RadioGroupOption
>
</RadioGroup>
`,
setup() {
let deliveryMethod = ref(undefined)
let options = ref([{ id: 1, label: 'Pickup' }])
return { deliveryMethod, options }
},
})
await new Promise<void>(nextTick)
expect(getByText('Pickup')).toHaveClass('abc')
})
})
describe('Keyboard interactions', () => {
@@ -60,6 +60,7 @@ function useRadioGroupContext(component: string) {
export let RadioGroup = defineComponent({
name: 'RadioGroup',
emits: ['update:modelValue'],
inheritAttrs: false, // Manually handling this
props: {
as: { type: [Object, String], default: 'div' },
disabled: { type: [Boolean], default: false },
@@ -69,6 +70,9 @@ export let RadioGroup = defineComponent({
let { modelValue, disabled, ...passThroughProps } = this.$props
let propsWeControl = {
// Manually passthrough the attributes, because Vue can't automatically pass
// it to the underlying div because of all the wrapper components below.
...this.$attrs,
ref: 'el',
id: this.id,
role: 'radiogroup',
@@ -225,6 +229,7 @@ enum OptionState {
export let RadioGroupOption = defineComponent({
name: 'RadioGroupOption',
inheritAttrs: false, // Manually handling this
props: {
as: { type: [Object, String], default: 'div' },
value: { type: [Object, String] },
@@ -246,6 +251,9 @@ export let RadioGroupOption = defineComponent({
let slot = { checked: this.checked, active: Boolean(this.state & OptionState.Active) }
let propsWeControl = {
// Manually passthrough the attributes, because Vue can't automatically pass
// it to the underlying div because of all the wrapper components below.
...this.$attrs,
id: this.id,
ref: 'el',
role: 'radio',
@@ -8,6 +8,7 @@ import {
getSwitch,
assertActiveElement,
getSwitchLabel,
getByText,
} from '../../test-utils/accessibility-assertions'
import { press, click, Keys } from '../../test-utils/interactions'
import { html } from '../../test-utils/html'
@@ -215,6 +216,65 @@ describe('Render composition', () => {
description: 'This is an important feature',
})
})
it('should be possible to put classes on a SwitchLabel', async () => {
renderTemplate({
template: html`
<SwitchGroup>
<SwitchLabel class="abc">Label A</SwitchLabel>
<Switch v-model="checked" />
</SwitchGroup>
`,
setup: () => ({ checked: ref(false) }),
})
await new Promise(requestAnimationFrame)
assertSwitch({
state: SwitchState.Off,
label: 'Label A',
})
expect(getByText('Label A')).toHaveClass('abc')
})
it('should be possible to put classes on a SwitchDescription', async () => {
renderTemplate({
template: html`
<SwitchGroup>
<SwitchDescription class="abc">Description A</SwitchDescription>
<Switch v-model="checked" />
</SwitchGroup>
`,
setup: () => ({ checked: ref(false) }),
})
await new Promise(requestAnimationFrame)
assertSwitch({
state: SwitchState.Off,
description: 'Description A',
})
expect(getByText('Description A')).toHaveClass('abc')
})
it('should be possible to put classes on a SwitchGroup', async () => {
renderTemplate({
template: html`
<SwitchGroup as="div" class="abc" id="group">
<Switch v-model="checked" />
</SwitchGroup>
`,
setup: () => ({ checked: ref(false) }),
})
await new Promise(requestAnimationFrame)
assertSwitch({ state: SwitchState.Off })
expect(document.getElementById('group')).toHaveClass('abc')
})
})
describe('Keyboard interactions', () => {
@@ -30,6 +30,7 @@ let GroupContext = Symbol('GroupContext') as InjectionKey<StateDefinition>
export let SwitchGroup = defineComponent({
name: 'SwitchGroup',
inheritAttrs: false, // Manually handling this
props: {
as: { type: [Object, String], default: 'template' },
},
@@ -56,7 +57,20 @@ export let SwitchGroup = defineComponent({
},
},
},
() => [render({ props, slot: {}, slots, attrs, name: 'SwitchGroup' })]
() => [
render({
props: {
// Manually passthrough the attributes, because Vue can't automatically pass
// it to the underlying div because of all the wrapper components below.
...attrs,
...props,
},
slot: {},
slots,
attrs,
name: 'SwitchGroup',
}),
]
),
])
},