Skip to content

Commit

Permalink
Next release (#431)
Browse files Browse the repository at this point in the history
* Fixed typos (#350)

* chore: Fix typo in render.ts (#347)

* Better vue link (#353)

* Better vue link

* add better React link

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>

* Enable NoScroll feature for the initial useFocusTrap hook (#356)

* enable NoScroll feature for the initial useFocusTrap hook

Once you are using Tab and Shift+Tab it does the scrolling.

Fixes: #345

* update changelog

* Revert "Enable NoScroll feature for the initial useFocusTrap hook (#356)"

This reverts commit 19590b0.

Solution is not 100% correct, so will revert for now!

* Improve search (#385)

* make search case insensitive for the listbox

* make search case insensitive for the menu

* update changelog

* add `disabled` prop to RadioGroup and RadioGroup Option (#401)

* add `disabled` prop to RadioGroup and RadioGroup Option

Also did some general cleanup which in turn fixed an issue where the
RadioGroup is unreachable when a value is used that doesn't exist in the
list of options.

Fixes: #378

* update changelog

* Fix type of `RadioGroupOption` (#400)

Match RadioGroupOption value types to match modelValue allowed types for RadioGroup

* update changelog

* fix typo's

* chore(CI): update main workflow (#395)

* chore(CI): update main workflow

* Update main.yml

* fix dialog event propagation (#422)

* re-export the `screen` utility for quick debugging purposes

* stop event propagation when clicking inside a Dialog

Fixes: #414

* improve dialog escape (#430)

* Make sure that `Escape` only closes the top most Dialog

* update changelog

* add defaultOpen prop to Disclosure component (#447)

* add defaultOpen prop to Disclosure component

* update changelog

Co-authored-by: Shuvro Roy <shuvro.roy@northsouth.edu>
Co-authored-by: Alex Nault <nault.alex@gmail.com>
Co-authored-by: Eugene Kopich <github@web2033.com>
Co-authored-by: Nathan Shoemark <n.shoemark@gmail.com>
Co-authored-by: Michaël De Boey <info@michaeldeboey.be>
  • Loading branch information
6 people committed Apr 26, 2021
1 parent 6a01c54 commit ce23ede
Show file tree
Hide file tree
Showing 42 changed files with 1,067 additions and 139 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ jobs:
uses: actions/checkout@v2

- name: Use Node 12
uses: actions/setup-node@v1
uses: actions/setup-node@v2
with:
node-version: 12.x
node-version: 12

# - name: Use cached node_modules
# id: cache
# uses: actions/cache@v1
# uses: actions/cache@v2
# with:
# path: node_modules
# key: nodeModules-${{ hashFiles('**/yarn.lock') }}
Expand Down
23 changes: 21 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased - React]

- Nothing yet!
### Fixes

- Improve search, make searching case insensitive ([#385](https://github.com/tailwindlabs/headlessui/pull/385))
- Fix unreachable `RadioGroup` ([#401](https://github.com/tailwindlabs/headlessui/pull/401))
- Fix closing nested `Dialog` components when pressing `Escape` ([#430](https://github.com/tailwindlabs/headlessui/pull/430))

### Added

- Add `disabled` prop to `RadioGroup` and `RadioGroup.Option` ([#401](https://github.com/tailwindlabs/headlessui/pull/401))
- Add `defaultOpen` prop to the `Disclosure` component ([#447](https://github.com/tailwindlabs/headlessui/pull/447))

## [Unreleased - Vue]

- Nothing yet!
### Fixes

- Improve search, make searching case insensitive ([#385](https://github.com/tailwindlabs/headlessui/pull/385))
- Fix unreachable `RadioGroup` ([#401](https://github.com/tailwindlabs/headlessui/pull/401))
- Fix `RadioGroupOption` value type ([#400](https://github.com/tailwindlabs/headlessui/pull/400))
- Fix closing nested `Dialog` components when pressing `Escape` ([#430](https://github.com/tailwindlabs/headlessui/pull/430))

### Added

- Add `disabled` prop to `RadioGroup` and `RadioGroupOption` ([#401](https://github.com/tailwindlabs/headlessui/pull/401))
- Add `defaultOpen` prop to the `Disclosure` component ([#447](https://github.com/tailwindlabs/headlessui/pull/447))

## [@headlessui/react@v1.0.0] - 2021-04-14

Expand Down
2 changes: 1 addition & 1 deletion packages/@headlessui-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ yarn add @headlessui/react

## Documentation

For full documentation, visit [headlessui.dev](https://headlessui.dev/react).
For full documentation, visit [headlessui.dev](https://headlessui.dev/react/menu).

## Community

Expand Down
4 changes: 2 additions & 2 deletions packages/@headlessui-react/pages/dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ function Nested({ onClose, level = 0 }) {

return (
<>
<Dialog open={true} onClose={onClose} className="fixed z-10 inset-0 pointer-events-none">
<Dialog open={true} onClose={onClose} className="fixed z-10 inset-0">
{true && <Dialog.Overlay className="fixed inset-0 bg-gray-500 opacity-25" />}
<div
className="z-10 fixed left-12 top-24 bg-white w-96 p-4 pointer-events-auto"
className="z-10 fixed left-12 top-24 bg-white w-96 p-4"
style={{
transform: `translate(calc(50px * ${level}), calc(50px * ${level}))`,
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ it('should be possible to use a DescriptionProvider and a single Description, an
`)
})

it('should be possible to use a DescriptionProvider and multiple Description ocmponents, and have them linked', async () => {
it('should be possible to use a DescriptionProvider and multiple Description components, and have them linked', async () => {
function Component(props: { children: ReactNode }) {
let [describedby, DescriptionProvider] = useDescriptions()

Expand Down
149 changes: 149 additions & 0 deletions packages/@headlessui-react/src/components/dialog/dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getDialogOverlay,
getByText,
assertActiveElement,
getDialogs,
} from '../../test-utils/accessibility-assertions'
import { click, press, Keys } from '../../test-utils/interactions'
import { PropsOf } from '../../types'
Expand Down Expand Up @@ -496,4 +497,152 @@ describe('Mouse interactions', () => {
assertActiveElement(getByText('Hello'))
})
)

it(
'should stop propagating click events when clicking on the Dialog.Overlay',
suppressConsoleLogs(async () => {
let wrapperFn = jest.fn()
function Example() {
let [isOpen, setIsOpen] = useState(true)
return (
<div onClick={wrapperFn}>
<Dialog open={isOpen} onClose={setIsOpen}>
Contents
<Dialog.Overlay />
<TabSentinel />
</Dialog>
</div>
)
}
render(<Example />)

// Verify it is open
assertDialog({ state: DialogState.Visible })

// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)

// Click the Dialog.Overlay to close the Dialog
await click(getDialogOverlay())

// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })

// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
})
)

it(
'should stop propagating click events when clicking on an element inside the Dialog',
suppressConsoleLogs(async () => {
let wrapperFn = jest.fn()
function Example() {
let [isOpen, setIsOpen] = useState(true)
return (
<div onClick={wrapperFn}>
<Dialog open={isOpen} onClose={setIsOpen}>
Contents
<button onClick={() => setIsOpen(false)}>Inside</button>
<TabSentinel />
</Dialog>
</div>
)
}
render(<Example />)

// Verify it is open
assertDialog({ state: DialogState.Visible })

// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)

// Click the button inside the the Dialog
await click(getByText('Inside'))

// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })

// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
})
)
})

describe('Nesting', () => {
it('should be possible to open nested Dialog components and close them with `Escape`', async () => {
function Nested({ onClose, level = 1 }: { onClose: (value: boolean) => void; level?: number }) {
let [showChild, setShowChild] = useState(false)

return (
<>
<Dialog open={true} onClose={onClose}>
<div>
<p>Level: {level}</p>
<button onClick={() => setShowChild(true)}>Open {level + 1}</button>
</div>
{showChild && <Nested onClose={setShowChild} level={level + 1} />}
</Dialog>
</>
)
}

function Example() {
let [open, setOpen] = useState(false)

return (
<>
<button onClick={() => setOpen(true)}>Open 1</button>
{open && <Nested onClose={setOpen} />}
</>
)
}

render(<Example />)

// Verify we have no open dialogs
expect(getDialogs()).toHaveLength(0)

// Open Dialog 1
await click(getByText('Open 1'))

// Verify that we have 1 open dialog
expect(getDialogs()).toHaveLength(1)

// Open Dialog 2
await click(getByText('Open 2'))

// Verify that we have 2 open dialogs
expect(getDialogs()).toHaveLength(2)

// Press escape to close the top most Dialog
await press(Keys.Escape)

// Verify that we have 1 open dialog
expect(getDialogs()).toHaveLength(1)

// Open Dialog 2
await click(getByText('Open 2'))

// Verify that we have 2 open dialogs
expect(getDialogs()).toHaveLength(2)

// Open Dialog 3
await click(getByText('Open 3'))

// Verify that we have 3 open dialogs
expect(getDialogs()).toHaveLength(3)

// Press escape to close the top most Dialog
await press(Keys.Escape)

// Verify that we have 2 open dialogs
expect(getDialogs()).toHaveLength(2)

// Press escape to close the top most Dialog
await press(Keys.Escape)

// Verify that we have 1 open dialog
expect(getDialogs()).toHaveLength(1)
})
})
34 changes: 25 additions & 9 deletions packages/@headlessui-react/src/components/dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import React, {
ContextType,
ElementType,
MouseEvent as ReactMouseEvent,
KeyboardEvent as ReactKeyboardEvent,
MutableRefObject,
Ref,
} from 'react'
Expand Down Expand Up @@ -92,7 +93,13 @@ let DEFAULT_DIALOG_TAG = 'div' as const
interface DialogRenderPropArg {
open: boolean
}
type DialogPropsWeControl = 'id' | 'role' | 'aria-modal' | 'aria-describedby' | 'aria-labelledby'
type DialogPropsWeControl =
| 'id'
| 'role'
| 'aria-modal'
| 'aria-describedby'
| 'aria-labelledby'
| 'onClick'

let DialogRenderFeatures = Features.RenderStrategy | Features.Static

Expand Down Expand Up @@ -171,14 +178,6 @@ let DialogRoot = forwardRefWithAs(function Dialog<
close()
})

// Handle `Escape` to close
useWindowEvent('keydown', event => {
if (event.key !== Keys.Escape) return
if (dialogState !== DialogStates.Open) return
if (containers.current.size > 1) return // 1 is myself, otherwise other elements in the Stack
close()
})

// Scroll lock
useEffect(() => {
if (dialogState !== DialogStates.Open) return
Expand All @@ -190,6 +189,7 @@ let DialogRoot = forwardRefWithAs(function Dialog<

document.documentElement.style.overflow = 'hidden'
document.documentElement.style.paddingRight = `${scrollbarWidth}px`

return () => {
document.documentElement.style.overflow = overflow
document.documentElement.style.paddingRight = paddingRight
Expand Down Expand Up @@ -243,6 +243,20 @@ let DialogRoot = forwardRefWithAs(function Dialog<
'aria-modal': dialogState === DialogStates.Open ? true : undefined,
'aria-labelledby': state.titleId,
'aria-describedby': describedby,
onClick(event: ReactMouseEvent) {
event.preventDefault()
event.stopPropagation()
},

// Handle `Escape` to close
onKeyDown(event: ReactKeyboardEvent) {
if (event.key !== Keys.Escape) return
if (dialogState !== DialogStates.Open) return
if (containers.current.size > 1) return // 1 is myself, otherwise other elements in the Stack
event.preventDefault()
event.stopPropagation()
close()
},
}
let passthroughProps = rest

Expand Down Expand Up @@ -302,6 +316,8 @@ let Overlay = forwardRefWithAs(function Overlay<
let handleClick = useCallback(
(event: ReactMouseEvent) => {
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()
event.preventDefault()
event.stopPropagation()
close()
},
[close]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,29 @@ describe('Rendering', () => {
assertDisclosurePanel({ state: DisclosureState.Visible, textContent: 'Panel is: open' })
})
)

it('should be possible to render a Disclosure in an open state by default', async () => {
render(
<Disclosure defaultOpen>
{({ open }) => (
<>
<Disclosure.Button>Trigger</Disclosure.Button>
<Disclosure.Panel>Panel is: {open ? 'open' : 'closed'}</Disclosure.Panel>
</>
)}
</Disclosure>
)

assertDisclosureButton({
state: DisclosureState.Visible,
attributes: { id: 'headlessui-disclosure-button-1' },
})
assertDisclosurePanel({ state: DisclosureState.Visible, textContent: 'Panel is: open' })

await click(getDisclosureButton())

assertDisclosureButton({ state: DisclosureState.InvisibleUnmounted })
})
})

describe('Disclosure.Button', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,16 @@ interface DisclosureRenderPropArg {
}

export function Disclosure<TTag extends ElementType = typeof DEFAULT_DISCLOSURE_TAG>(
props: Props<TTag, DisclosureRenderPropArg>
props: Props<TTag, DisclosureRenderPropArg> & {
defaultOpen?: boolean
}
) {
let { defaultOpen = false, ...passthroughProps } = props
let buttonId = `headlessui-disclosure-button-${useId()}`
let panelId = `headlessui-disclosure-panel-${useId()}`

let reducerBag = useReducer(stateReducer, {
disclosureState: DisclosureStates.Closed,
disclosureState: defaultOpen ? DisclosureStates.Open : DisclosureStates.Closed,
linkedPanel: false,
buttonId,
panelId,
Expand All @@ -135,7 +138,7 @@ export function Disclosure<TTag extends ElementType = typeof DEFAULT_DISCLOSURE_
return (
<DisclosureContext.Provider value={reducerBag}>
{render({
props,
props: passthroughProps,
slot,
defaultTag: DEFAULT_DISCLOSURE_TAG,
name: 'Disclosure',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ it(

let [a, b, c, d] = Array.from(document.querySelectorAll('input'))

// Ensure that input-b is the active elememt
// Ensure that input-b is the active element
assertActiveElement(b)

// Tab to the next item
await press(Keys.Tab)

// Ensure that input-c is the active elememt
// Ensure that input-c is the active element
assertActiveElement(c)

// Try to move focus
Expand Down
Loading

0 comments on commit ce23ede

Please sign in to comment.