Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple new components #220

Merged
merged 47 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
8494bd5
add Disclosure component
RobinMalfait Jan 26, 2021
07f9167
expose the Disclosure component
RobinMalfait Jan 26, 2021
8648052
add Disclosure example component page
RobinMalfait Jan 26, 2021
1d98d7d
temporary fix selector because of JSDOM bug
RobinMalfait Jan 29, 2021
97011bb
add useFocusTrap hook
RobinMalfait Feb 1, 2021
4943d02
add FocusTrap component
RobinMalfait Jan 29, 2021
5c293b8
expose FocusTrap
RobinMalfait Jan 29, 2021
a52f2e3
add Dialog component
RobinMalfait Feb 3, 2021
a1ed110
add Dialog example component page
RobinMalfait Feb 3, 2021
dec4049
expose Dialog
RobinMalfait Jan 29, 2021
370d3bc
random cleanup
RobinMalfait Feb 1, 2021
40f1bc6
make TypeScript a bit more happy
RobinMalfait Feb 1, 2021
222f7d5
add Switch.Description component for React
RobinMalfait Feb 1, 2021
c4e953b
add Switch.Description component for Vue
RobinMalfait Feb 1, 2021
d1d332f
ensure focus event is triggered on click when element is focusable
RobinMalfait Feb 4, 2021
4a0becc
remove Dialog.Button and Dialog.Panel from accessibility assertions
RobinMalfait Feb 4, 2021
108c2f0
add Portal component
RobinMalfait Feb 4, 2021
2bc6a6d
expose Portal
RobinMalfait Feb 4, 2021
bb2148c
always render Dialog in a Portal
RobinMalfait Feb 5, 2021
b912bf6
add useInertOthers hook
RobinMalfait Feb 5, 2021
301be38
use the useInertOthers hook
RobinMalfait Feb 5, 2021
61193d8
add scroll lock to the dialog
RobinMalfait Feb 7, 2021
c2f723b
ensure we respect autoFocus on form elements within the Dialog
RobinMalfait Feb 7, 2021
6f665d9
only mark aria-modal when Dialog is open
RobinMalfait Feb 7, 2021
6b2b8d1
add initialFocus option to Dialog, FocusTrap & useFocusTrap
RobinMalfait Feb 7, 2021
66e0dfd
add tests and a few fixes for the initialFocusRef functionality
RobinMalfait Feb 8, 2021
575de8f
forward ref to underlying Dialog component
RobinMalfait Feb 8, 2021
1459bac
close Dialog when it becomes hidden
RobinMalfait Feb 8, 2021
7ff4dc3
prevent infinite loop
RobinMalfait Feb 8, 2021
8628328
isIntersecting doesn't work in every scenario
RobinMalfait Feb 8, 2021
64fed3f
render Portal contents in a div
RobinMalfait Feb 8, 2021
75d05e5
ensure the props bag is typed
RobinMalfait Feb 9, 2021
ccd2e4a
add getByText and assertContainsActiveElement helpers
RobinMalfait Feb 12, 2021
42dd9f7
add Popover component
RobinMalfait Feb 12, 2021
8046055
expose Popover
RobinMalfait Feb 12, 2021
8ab53e4
add Popover example component page
RobinMalfait Feb 11, 2021
983061d
add quick checks to prevent useless renders
RobinMalfait Feb 11, 2021
247ab32
drop incorrect close function
RobinMalfait Feb 11, 2021
a5e197e
update Changelog
RobinMalfait Feb 8, 2021
8fce1f6
make test error more readable when comparing DOM nodes
RobinMalfait Feb 17, 2021
bc4f7e9
actually call .focus() on the element
RobinMalfait Feb 17, 2021
b9db527
improve useSyncRefs, because ...refs is *always* different
RobinMalfait Feb 17, 2021
5873f12
add dedicated focus management utilities
RobinMalfait Feb 17, 2021
05475f3
refactor useFocusTrap, use focus management utilities
RobinMalfait Feb 17, 2021
2785733
fix regression while using outside click
RobinMalfait Feb 17, 2021
8296ead
add outside-click to Dialog itself
RobinMalfait Feb 18, 2021
2aeaf1a
update docs
RobinMalfait Feb 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased - React]

- Nothing yet!
### Added

- Add `Disclosure`, `Disclosure.Button` and `Disclosure.Panel` components ([#220](https://github.com/tailwindlabs/headlessui/pull/220))
- Add `Dialog`, `Dialog.Overlay`, `Dialog.Tile` and `Dialog.Description` components ([#220](https://github.com/tailwindlabs/headlessui/pull/220))
- Add `Portal` component ([#220](https://github.com/tailwindlabs/headlessui/pull/220))
- Add `Switch.Description` component, which adds the `aria-describedby` to the actual Switch ([#220](https://github.com/tailwindlabs/headlessui/pull/220))
- Add `FocusTrap` component ([#220](https://github.com/tailwindlabs/headlessui/pull/220))
- Add `Flyout` component ([#220](https://github.com/tailwindlabs/headlessui/pull/220))

## [Unreleased - Vue]

Expand Down
603 changes: 538 additions & 65 deletions packages/@headlessui-react/README.md

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions packages/@headlessui-react/pages/dialog/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useState, Fragment } from 'react'
import { Dialog, Transition } from '@headlessui/react'

export default function Home() {
let [isOpen, setIsOpen] = useState(false)

return (
<>
<button
type="button"
onClick={() => setIsOpen(v => !v)}
className="m-12 px-4 py-2 text-base font-medium leading-6 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue sm:text-sm sm:leading-5"
>
Toggle!
</button>

<Transition show={isOpen} as={Fragment}>
<Dialog open={isOpen} onClose={setIsOpen} static>
<div className="fixed z-10 inset-0 overflow-y-auto">
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 transition-opacity">
<div className="absolute inset-0 bg-gray-500 opacity-75"></div>
</Dialog.Overlay>
</Transition.Child>

<Transition.Child
enter="ease-out transform duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in transform duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
{/* Heroicon name: exclamation */}
<svg
className="h-6 w-6 text-red-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
>
Deactivate account
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500">
Are you sure you want to deactivate your account? All of your data will
be permanently removed. This action cannot be undone.
</p>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
onClick={() => setIsOpen(false)}
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:shadow-outline-red sm:ml-3 sm:w-auto sm:text-sm"
>
Deactivate
</button>
<button
type="button"
onClick={() => setIsOpen(false)}
className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:shadow-outline-indigo sm:mt-0 sm:w-auto sm:text-sm"
>
Cancel
</button>
</div>
</div>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</>
)
}
32 changes: 32 additions & 0 deletions packages/@headlessui-react/pages/disclosure/disclosure.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import { Disclosure, Transition } from '@headlessui/react'

export default function Home() {
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="w-full max-w-xs mx-auto">
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button>Trigger</Disclosure.Button>

<Transition
show={open}
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Disclosure.Panel static className="p-4 bg-white mt-4">
Content
</Disclosure.Panel>
</Transition>
</>
)}
</Disclosure>
</div>
</div>
)
}
101 changes: 101 additions & 0 deletions packages/@headlessui-react/pages/popover/popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React, { forwardRef } from 'react'
import { Popover, Portal } from '@headlessui/react'
import { usePopper } from '../../playground-utils/hooks/use-popper'
import { PropsOf as Props } from '../../src/types'

let Button = forwardRef((props: Props<'button'>, ref) => {
return (
<Popover.Button
ref={ref}
className="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900"
{...props}
/>
)
})

function Link(props: Props<'a'>) {
return (
<a
href="/"
className="px-3 py-2 border-2 border-transparent hover:bg-gray-200 focus:bg-gray-200 focus:outline-none focus:border-blue-900"
{...props}
>
{props.children}
</a>
)
}

export default function Home() {
let options = {
placement: 'bottom-start',
strategy: 'fixed',
modifiers: [],
}

let [reference1, popper1] = usePopper(options)
let [reference2, popper2] = usePopper(options)

let links = ['First', 'Second', 'Third', 'Fourth']

return (
<div className="flex justify-center items-center space-x-12 p-12">
<button>Previous</button>

<Popover.Group as="nav" ar-label="Mythical University" className="flex space-x-3">
<Popover as="div" className="relative">
<Button>Normal</Button>
<Popover.Panel className="absolute flex flex-col w-64 bg-gray-100 border-2 border-blue-900">
{links.map((link, i) => (
<Link key={link} hidden={i === 2}>
Normal - {link}
</Link>
))}
</Popover.Panel>
</Popover>

<Popover as="div" className="relative">
<Button>Focus</Button>
<Popover.Panel
focus
className="absolute flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
{links.map((link, i) => (
<Link key={link}>Focus - {link}</Link>
))}
</Popover.Panel>
</Popover>

<Popover as="div" className="relative">
<Button ref={reference1}>Portal</Button>
<Portal>
<Popover.Panel
ref={popper1}
className="flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
{links.map(link => (
<Link key={link}>Portal - {link}</Link>
))}
</Popover.Panel>
</Portal>
</Popover>

<Popover as="div" className="relative">
<Button ref={reference2}>Focus in Portal</Button>
<Portal>
<Popover.Panel
ref={popper2}
focus
className="flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
{links.map(link => (
<Link key={link}>Focus in Portal - {link}</Link>
))}
</Popover.Panel>
</Portal>
</Popover>
</Popover.Group>

<button>Next</button>
</div>
)
}
Loading