remove classname feature (#607)
* change className to class Co-authored-by: Ryan Johnston <ryan@magic.nz> * drop className as a function in Vue * update changelog Co-authored-by: Ryan Johnston <ryan@magic.nz>
This commit is contained in:
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Improve React peer dependency version range ([#544](https://github.com/tailwindlabs/headlessui/pull/544))
|
||||
- Improve types for the `open` prop in the `Dialog` component ([#550](https://github.com/tailwindlabs/headlessui/pull/550))
|
||||
- Improve `aria-expanded` logic ([#592](https://github.com/tailwindlabs/headlessui/pull/592))
|
||||
- Remove undocumented `:className` prop ([#607](https://github.com/tailwindlabs/headlessui/pull/607))
|
||||
|
||||
## [Unreleased - Vue]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div className="container my-24">
|
||||
<div className="prose">
|
||||
<div class="container my-24">
|
||||
<div class="prose">
|
||||
<h2>Examples</h2>
|
||||
<Examples :examples="examples" />
|
||||
</div>
|
||||
|
||||
@@ -479,84 +479,6 @@ describe('Rendering', () => {
|
||||
})
|
||||
|
||||
describe('Rendering composition', () => {
|
||||
it(
|
||||
'should be possible to conditionally render classNames (aka className can be a function?!)',
|
||||
suppressConsoleLogs(async () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Listbox v-model="value">
|
||||
<ListboxButton>Trigger</ListboxButton>
|
||||
<ListboxOptions>
|
||||
<ListboxOption value="a" :className="JSON.stringify">
|
||||
Option A
|
||||
</ListboxOption>
|
||||
<ListboxOption value="b" disabled :className="JSON.stringify">
|
||||
Option B
|
||||
</ListboxOption>
|
||||
<ListboxOption value="c" className="no-special-treatment">
|
||||
Option C
|
||||
</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</Listbox>
|
||||
`,
|
||||
setup: () => ({ value: ref(null) }),
|
||||
})
|
||||
|
||||
assertListboxButton({
|
||||
state: ListboxState.InvisibleUnmounted,
|
||||
attributes: { id: 'headlessui-listbox-button-1' },
|
||||
})
|
||||
assertListbox({ state: ListboxState.InvisibleUnmounted })
|
||||
|
||||
// Open Listbox
|
||||
await click(getListboxButton())
|
||||
|
||||
let options = getListboxOptions()
|
||||
|
||||
// Verify correct classNames
|
||||
expect('' + options[0].classList).toEqual(
|
||||
JSON.stringify({ active: false, selected: false, disabled: false })
|
||||
)
|
||||
expect('' + options[1].classList).toEqual(
|
||||
JSON.stringify({ active: false, selected: false, disabled: true })
|
||||
)
|
||||
expect('' + options[2].classList).toEqual('no-special-treatment')
|
||||
|
||||
// Double check that nothing is active
|
||||
assertNoActiveListboxOption(getListbox())
|
||||
|
||||
// Make the first option active
|
||||
await press(Keys.ArrowDown)
|
||||
|
||||
// Verify the classNames
|
||||
expect('' + options[0].classList).toEqual(
|
||||
JSON.stringify({ active: true, selected: false, disabled: false })
|
||||
)
|
||||
expect('' + options[1].classList).toEqual(
|
||||
JSON.stringify({ active: false, selected: false, disabled: true })
|
||||
)
|
||||
expect('' + options[2].classList).toEqual('no-special-treatment')
|
||||
|
||||
// Double check that the first option is the active one
|
||||
assertActiveListboxOption(options[0])
|
||||
|
||||
// Let's go down, this should go to the third option since the second option is disabled!
|
||||
await press(Keys.ArrowDown)
|
||||
|
||||
// Verify the classNames
|
||||
expect('' + options[0].classList).toEqual(
|
||||
JSON.stringify({ active: false, selected: false, disabled: false })
|
||||
)
|
||||
expect('' + options[1].classList).toEqual(
|
||||
JSON.stringify({ active: false, selected: false, disabled: true })
|
||||
)
|
||||
expect('' + options[2].classList).toEqual('no-special-treatment')
|
||||
|
||||
// Double check that the last option is the active one
|
||||
assertActiveListboxOption(options[2])
|
||||
})
|
||||
)
|
||||
|
||||
it(
|
||||
'should be possible to swap the Listbox option with a button for example',
|
||||
suppressConsoleLogs(async () => {
|
||||
|
||||
@@ -19,7 +19,6 @@ import { Features, render, omit } from '../../utils/render'
|
||||
import { useId } from '../../hooks/use-id'
|
||||
import { Keys } from '../../keyboard'
|
||||
import { calculateActiveIndex, Focus } from '../../utils/calculate-active-index'
|
||||
import { resolvePropValue } from '../../utils/resolve-prop-value'
|
||||
import { dom } from '../../utils/dom'
|
||||
import { useWindowEvent } from '../../hooks/use-window-event'
|
||||
import { useOpenClosed, State, useOpenClosedProvider } from '../../internal/open-closed'
|
||||
@@ -474,7 +473,6 @@ export let ListboxOption = defineComponent({
|
||||
value: { type: [Object, String] },
|
||||
disabled: { type: Boolean, default: false },
|
||||
class: { type: [String, Function], required: false },
|
||||
className: { type: [String, Function], required: false },
|
||||
},
|
||||
setup(props, { slots, attrs }) {
|
||||
let api = useListboxContext('ListboxOption')
|
||||
@@ -548,13 +546,13 @@ export let ListboxOption = defineComponent({
|
||||
}
|
||||
|
||||
return () => {
|
||||
let { disabled, class: defaultClass, className = defaultClass } = props
|
||||
let { disabled, class: defaultClass } = props
|
||||
let slot = { active: active.value, selected: selected.value, disabled }
|
||||
let propsWeControl = {
|
||||
id,
|
||||
role: 'option',
|
||||
tabIndex: disabled === true ? undefined : -1,
|
||||
class: resolvePropValue(className, slot),
|
||||
class: defaultClass,
|
||||
'aria-disabled': disabled === true ? true : undefined,
|
||||
'aria-selected': selected.value === true ? selected.value : undefined,
|
||||
disabled: undefined, // Never forward the `disabled` prop
|
||||
|
||||
@@ -633,60 +633,6 @@ describe('Rendering', () => {
|
||||
})
|
||||
|
||||
describe('Rendering composition', () => {
|
||||
it('should be possible to conditionally render classNames (aka className can be a function?!)', async () => {
|
||||
renderTemplate(jsx`
|
||||
<Menu>
|
||||
<MenuButton>Trigger</MenuButton>
|
||||
<MenuItems>
|
||||
<MenuItem as="a" :className="JSON.stringify">Item A</MenuItem>
|
||||
<MenuItem as="a" disabled :className="JSON.stringify">Item B</MenuItem>
|
||||
<MenuItem as="a" class="no-special-treatment">Item C</MenuItem>
|
||||
</MenuItems>
|
||||
</Menu>
|
||||
`)
|
||||
|
||||
assertMenuButton({
|
||||
state: MenuState.InvisibleUnmounted,
|
||||
attributes: { id: 'headlessui-menu-button-1' },
|
||||
})
|
||||
assertMenu({ state: MenuState.InvisibleUnmounted })
|
||||
|
||||
// Open menu
|
||||
await click(getMenuButton())
|
||||
|
||||
let items = getMenuItems()
|
||||
|
||||
// Verify correct classNames
|
||||
expect('' + items[0].classList).toEqual(JSON.stringify({ active: false, disabled: false }))
|
||||
expect('' + items[1].classList).toEqual(JSON.stringify({ active: false, disabled: true }))
|
||||
expect('' + items[2].classList).toEqual('no-special-treatment')
|
||||
|
||||
// Double check that nothing is active
|
||||
assertNoActiveMenuItem()
|
||||
|
||||
// Make the first item active
|
||||
await press(Keys.ArrowDown)
|
||||
|
||||
// Verify the classNames
|
||||
expect('' + items[0].classList).toEqual(JSON.stringify({ active: true, disabled: false }))
|
||||
expect('' + items[1].classList).toEqual(JSON.stringify({ active: false, disabled: true }))
|
||||
expect('' + items[2].classList).toEqual('no-special-treatment')
|
||||
|
||||
// Double check that the first item is the active one
|
||||
assertMenuLinkedWithMenuItem(items[0])
|
||||
|
||||
// Let's go down, this should go to the third item since the second item is disabled!
|
||||
await press(Keys.ArrowDown)
|
||||
|
||||
// Verify the classNames
|
||||
expect('' + items[0].classList).toEqual(JSON.stringify({ active: false, disabled: false }))
|
||||
expect('' + items[1].classList).toEqual(JSON.stringify({ active: false, disabled: true }))
|
||||
expect('' + items[2].classList).toEqual('no-special-treatment')
|
||||
|
||||
// Double check that the last item is the active one
|
||||
assertMenuLinkedWithMenuItem(items[2])
|
||||
})
|
||||
|
||||
it(
|
||||
'should be possible to swap the menu item with a button for example',
|
||||
suppressConsoleLogs(async () => {
|
||||
@@ -734,22 +680,22 @@ describe('Rendering composition', () => {
|
||||
template: jsx`
|
||||
<Menu>
|
||||
<MenuButton>Trigger</MenuButton>
|
||||
<div className="outer">
|
||||
<div class="outer">
|
||||
<MenuItems>
|
||||
<div className="py-1 inner">
|
||||
<div class="py-1 inner">
|
||||
<MenuItem as="button">Item A</MenuItem>
|
||||
<MenuItem as="button">Item B</MenuItem>
|
||||
</div>
|
||||
<div className="py-1 inner">
|
||||
<div class="py-1 inner">
|
||||
<MenuItem as="button">Item C</MenuItem>
|
||||
<MenuItem>
|
||||
<div>
|
||||
<div className="outer">Item D</div>
|
||||
<div class="outer">Item D</div>
|
||||
</div>
|
||||
</MenuItem>
|
||||
</div>
|
||||
<div className="py-1 inner">
|
||||
<form className="inner">
|
||||
<div class="py-1 inner">
|
||||
<form class="inner">
|
||||
<MenuItem as="button">Item E</MenuItem>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Features, render } from '../../utils/render'
|
||||
import { useId } from '../../hooks/use-id'
|
||||
import { Keys } from '../../keyboard'
|
||||
import { Focus, calculateActiveIndex } from '../../utils/calculate-active-index'
|
||||
import { resolvePropValue } from '../../utils/resolve-prop-value'
|
||||
import { dom } from '../../utils/dom'
|
||||
import { useWindowEvent } from '../../hooks/use-window-event'
|
||||
import { useTreeWalker } from '../../hooks/use-tree-walker'
|
||||
@@ -413,7 +412,6 @@ export let MenuItem = defineComponent({
|
||||
as: { type: [Object, String], default: 'template' },
|
||||
disabled: { type: Boolean, default: false },
|
||||
class: { type: [String, Function], required: false },
|
||||
className: { type: [String, Function], required: false },
|
||||
},
|
||||
setup(props, { slots, attrs }) {
|
||||
let api = useMenuContext('MenuItem')
|
||||
@@ -467,13 +465,13 @@ export let MenuItem = defineComponent({
|
||||
}
|
||||
|
||||
return () => {
|
||||
let { disabled, class: defaultClass, className = defaultClass } = props
|
||||
let { disabled, class: defaultClass } = props
|
||||
let slot = { active: active.value, disabled }
|
||||
let propsWeControl = {
|
||||
id,
|
||||
role: 'menuitem',
|
||||
tabIndex: disabled === true ? undefined : -1,
|
||||
class: resolvePropValue(className, slot),
|
||||
class: defaultClass,
|
||||
'aria-disabled': disabled === true ? true : undefined,
|
||||
onClick: handleClick,
|
||||
onFocus: handleFocus,
|
||||
|
||||
@@ -20,7 +20,6 @@ import { useId } from '../../hooks/use-id'
|
||||
import { render } from '../../utils/render'
|
||||
import { Label, useLabels } from '../label/label'
|
||||
import { Description, useDescriptions } from '../description/description'
|
||||
import { resolvePropValue } from '../../utils/resolve-prop-value'
|
||||
import { useTreeWalker } from '../../hooks/use-tree-walker'
|
||||
|
||||
interface Option {
|
||||
@@ -234,16 +233,9 @@ export let RadioGroupOption = defineComponent({
|
||||
value: { type: [Object, String, Number, Boolean] },
|
||||
disabled: { type: Boolean, default: false },
|
||||
class: { type: [String, Function], required: false },
|
||||
className: { type: [String, Function], required: false },
|
||||
},
|
||||
render() {
|
||||
let {
|
||||
value,
|
||||
disabled,
|
||||
class: defaultClass,
|
||||
className = defaultClass,
|
||||
...passThroughProps
|
||||
} = this.$props
|
||||
let { value, disabled, class: defaultClass, ...passThroughProps } = this.$props
|
||||
|
||||
let slot = {
|
||||
checked: this.checked,
|
||||
@@ -255,7 +247,7 @@ export let RadioGroupOption = defineComponent({
|
||||
id: this.id,
|
||||
ref: 'el',
|
||||
role: 'radio',
|
||||
class: resolvePropValue(className, slot),
|
||||
class: defaultClass,
|
||||
'aria-checked': this.checked ? 'true' : 'false',
|
||||
'aria-labelledby': this.labelledby,
|
||||
'aria-describedby': this.describedby,
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
import { render } from '../../utils/render'
|
||||
import { useId } from '../../hooks/use-id'
|
||||
import { Keys } from '../../keyboard'
|
||||
import { resolvePropValue } from '../../utils/resolve-prop-value'
|
||||
import { Label, useLabels } from '../label/label'
|
||||
import { Description, useDescriptions } from '../description/description'
|
||||
|
||||
@@ -63,11 +62,10 @@ export let Switch = defineComponent({
|
||||
as: { type: [Object, String], default: 'button' },
|
||||
modelValue: { type: Boolean, default: false },
|
||||
class: { type: [String, Function], required: false },
|
||||
className: { type: [String, Function], required: false },
|
||||
},
|
||||
render() {
|
||||
let api = inject(GroupContext, null)
|
||||
let { class: defaultClass, className = defaultClass } = this.$props
|
||||
let { class: defaultClass } = this.$props
|
||||
|
||||
let slot = { checked: this.$props.modelValue }
|
||||
let propsWeControl = {
|
||||
@@ -75,7 +73,7 @@ export let Switch = defineComponent({
|
||||
ref: api === null ? undefined : api.switchRef,
|
||||
role: 'switch',
|
||||
tabIndex: 0,
|
||||
class: resolvePropValue(className, slot),
|
||||
class: defaultClass,
|
||||
'aria-checked': this.$props.modelValue,
|
||||
'aria-labelledby': this.labelledby,
|
||||
'aria-describedby': this.describedby,
|
||||
|
||||
Reference in New Issue
Block a user