ea26870480
* start of combobox
* start with a copy of the Listbox
* WIP
* Add Vue Combobox
* Update Vue version of combobox
* Update tests
* Fix typescript errors in combobox test
* Fix input label
The spec says that the combobox itself is labelled directly by the associated label. The button can however be labelled by the label or itself.
* Add active descendant to combobox/input
* Add listbox role to comobox options
Right now the option list *is* just a listbox. If we were to allow other types in the future this will need to be changable
* Update tests
* move React playground to dedicated package
* add react playground script to root
* ensure we only open/close the combobox when necessary
* ensure export order is correct
* remove leftover pages directory from React package
* Only add aria controls when combobox is open
* add missing next commands
* make typescript happy
* build @headlessui/react before building playground-react
* add empty public folder
This makes vercel happy
* wip
* Add todo
* Update tests
Still more updates to do but some are blocked on implementation
* change default combobox example slightly
* ensure that we sync the input with new state
When the <Combobox value={...} /> changes, then the input should change
as well.
* only sync the value with the input in a single spot
* WIP: object value to string
* WIP
* WIP
* WIP groups
* Add static search filtering to combobox
* Move mouse leave event to combobox
* Fix use in fragments
* Update
* WIP
* make all tests pass for the combobox in React
* remove unnecessary playground item
* remove listbox wip
* only fire change event on inputs
Potentially we also have to do this for all kinds of form inputs. But
this will do for now.
* disable combobox vue tests
* Fix vue typescript errors
* Vue tests WIP
* improve combobox playgrounds a tiny bit
* ensure to lookup the correct value
* make sure that we are using a div instead of a Fragment
* expose `activeItem`
This will be similar to `yourData[activeIndex]`, but in this case the
active option's data. Can probably rename this if necessary!
* Update comments
* Port react tests to Vue
* Vue tests WIP
* WIP
* Rename activeItem to activeOption
* Move display value to input
* Update playgrounds
* Remove static filtering
* Add tests for display value
* WIP Vue Tests
* WIP
* unfocus suite
* Cleanup react accessibility assertions code
* Vue WIP
* Cleanup errors in react interactions test utils
* Update vue implementation
closer :D
* Fix searching
* Update
* Add display value stubs
* Update tests
* move `<Combobox onSearch={} />` to `<Combobox.Input onChange={} />`
* use `useLatestValue` hook
* make `onChange` explicitly required
* remove unused variables
* move `<Combobox @search="" />` to `<ComboboxInput @change="" />`
* use correct event
* use `let` for consistency
* remove unnecessary hidden check
* implement displayValue for Vue
* update playground to reflect changes
* make sure that the activeOptionIndex stays correct
* update changelog
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
84 lines
2.9 KiB
TypeScript
84 lines
2.9 KiB
TypeScript
import React from 'react'
|
|
import { Menu } from '@headlessui/react'
|
|
import { classNames } from '../../utils/class-names'
|
|
|
|
export default function Home() {
|
|
return (
|
|
<div className="flex justify-center w-screen h-full p-12 space-x-4 bg-gray-50">
|
|
<Dropdown />
|
|
|
|
<div>
|
|
<div className="relative rounded-md shadow-sm">
|
|
<input
|
|
className="block w-full form-input sm:text-sm sm:leading-5"
|
|
placeholder="you@example.com"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<Dropdown />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function Dropdown() {
|
|
function resolveClass({ active, disabled }) {
|
|
return classNames(
|
|
'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700',
|
|
active && 'bg-gray-100 text-gray-900',
|
|
disabled && 'cursor-not-allowed opacity-50'
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="relative inline-block text-left">
|
|
<Menu>
|
|
<span className="inline-flex rounded-md shadow-sm">
|
|
<Menu.Button className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
|
|
<span>Options</span>
|
|
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
</Menu.Button>
|
|
</span>
|
|
|
|
<Menu.Items className="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none">
|
|
<div className="px-4 py-3">
|
|
<p className="text-sm leading-5">Signed in as</p>
|
|
<p className="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
|
|
</div>
|
|
|
|
<div className="py-1">
|
|
<Menu.Item as="a" href="#account-settings" className={resolveClass}>
|
|
Account settings
|
|
</Menu.Item>
|
|
<Menu.Item>
|
|
{data => (
|
|
<a href="#support" className={resolveClass(data)}>
|
|
Support
|
|
</a>
|
|
)}
|
|
</Menu.Item>
|
|
<Menu.Item as="a" disabled href="#new-feature" className={resolveClass}>
|
|
New feature (soon)
|
|
</Menu.Item>
|
|
<Menu.Item as="a" href="#license" className={resolveClass}>
|
|
License
|
|
</Menu.Item>
|
|
</div>
|
|
|
|
<div className="py-1">
|
|
<Menu.Item as="a" href="#sign-out" className={resolveClass}>
|
|
Sign out
|
|
</Menu.Item>
|
|
</div>
|
|
</Menu.Items>
|
|
</Menu>
|
|
</div>
|
|
)
|
|
}
|