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

2.0.0 Alpha prep #2887

Merged
merged 83 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
e64fcb2
bump React & React DOM dependencies
RobinMalfait Dec 19, 2023
f74cbc3
fix typo `TOmitableProps` → `TOmittableProps`
RobinMalfait Dec 19, 2023
34da82d
bump prettier
RobinMalfait Dec 19, 2023
543be6b
run prettier after prettier version bump
RobinMalfait Dec 19, 2023
2c86682
bump TypeScript
RobinMalfait Dec 19, 2023
cdc3839
run prettier after TypeScript version bump
RobinMalfait Dec 19, 2023
9124f23
enable `verbatimModuleSyntax`
RobinMalfait Dec 19, 2023
8c57cea
add `type` to type related imports
RobinMalfait Dec 19, 2023
d66f4cb
add common testing scenarios
RobinMalfait Dec 19, 2023
0c08eb6
add script to make Next.js happy
RobinMalfait Dec 19, 2023
4c3fffa
improve `by` prop, introduce `useByComparator`
RobinMalfait Dec 19, 2023
a9b9054
sync yarn.lock
RobinMalfait Dec 19, 2023
ce7c8aa
rename `Features` to `HiddenFeatures` for `Hidden` component
RobinMalfait Dec 19, 2023
b80ced4
rename `Features` to `FocusTrapFeatures` in `FocusTrap` component
RobinMalfait Dec 19, 2023
236c32a
rename `Features` to `RenderFeatures` in `render` util
RobinMalfait Dec 19, 2023
ed9cefd
add `floating-ui` as a dependency + introduce internal floating relat…
RobinMalfait Dec 19, 2023
10df5a0
bump Vue dependencies
RobinMalfait Dec 19, 2023
a119bd0
ensure scroll bar calculations can't go negative
RobinMalfait Dec 19, 2023
7cfbc54
improve types in `@headlessui/vue`
RobinMalfait Dec 19, 2023
80bfdff
use snapshot tests for `Transition` tests in `@headlessui/vue`
RobinMalfait Dec 19, 2023
ac04bdc
use snapshot tests for `portal` tests in `@headlessui/vue`
RobinMalfait Dec 19, 2023
27dc45b
rename `src/components/transitions/` to `src/components/transition/` …
RobinMalfait Dec 19, 2023
1df9740
drop custom `toMatchFormattedCss`, prefer snapshot tests instead
RobinMalfait Dec 19, 2023
f8ccae6
use snapshot tests for `Label` tests in `@headlessui/vue`
RobinMalfait Dec 19, 2023
3f06286
use snapshot tests for `Description` tests in `@headlessui/vue`
RobinMalfait Dec 19, 2023
7cebfed
sort exported components in tests for `@headlessui/vue`
RobinMalfait Dec 19, 2023
5214fee
use snapshot tests in `@headlessui/tailwindcss`
RobinMalfait Dec 19, 2023
e0e5b68
rename `mergeProps` to `mergePropsAdvanced`
RobinMalfait Dec 19, 2023
e45d307
do not expose `aria-labelledby` if it is only referencing itself
RobinMalfait Dec 19, 2023
94148bb
expose boolean state as `kebab-case` instead of `camelCase`
RobinMalfait Dec 19, 2023
fb3f648
expose boolean data attributes
RobinMalfait Dec 19, 2023
00a79e5
improve internal types for `className` in `render` util
RobinMalfait Dec 19, 2023
87ca4e1
ensure we keep exposed data attributes into account when trying to fo…
RobinMalfait Dec 19, 2023
303598a
add small typescript type fix
RobinMalfait Dec 19, 2023
d7259d8
introduce `mergeProps` util to be used in our components
RobinMalfait Dec 19, 2023
c963d1a
add new internal `Modal` component
RobinMalfait Dec 19, 2023
85302d5
fix: when using `Focus.Previous` with `activeIndex = -1` should start…
RobinMalfait Dec 19, 2023
eda1c5d
prefer `window.scrollY` instead of `window.pageYOffset`
RobinMalfait Dec 19, 2023
5844d0c
add `'use client'` directives on client only components
RobinMalfait Dec 19, 2023
dcb7439
drop `import 'client-only'` in favor of the `'use client'` directive
RobinMalfait Dec 19, 2023
2a39c02
add React Aria dependencies
RobinMalfait Dec 19, 2023
ac20930
pin beta dependencies
RobinMalfait Dec 19, 2023
dfd1c1c
prettier bump formatting
RobinMalfait Dec 19, 2023
ea7f2e5
improve TypeScript types in tests
RobinMalfait Dec 19, 2023
d4c7e45
use new Jest matchers instead of deprecated ones
RobinMalfait Dec 19, 2023
4a2d9a1
improve typescript types in Vue
RobinMalfait Dec 19, 2023
f69ce40
prefer `useLabelledBy` and `useDescribedBy`
RobinMalfait Dec 19, 2023
28633dd
add internal `DisabledProvider`
RobinMalfait Dec 19, 2023
444565a
add internal `IdProvider`
RobinMalfait Dec 19, 2023
7200d9d
add internal `useDidElementMove` hook
RobinMalfait Dec 19, 2023
cb8058d
add internal `useElementSize` hook
RobinMalfait Dec 19, 2023
443116f
add internal `useIsTouchDevice` hook
RobinMalfait Dec 19, 2023
a16ca71
add internal `useActivePress` hook
RobinMalfait Dec 19, 2023
b42630b
use snapshot tests for `Description` tests
RobinMalfait Dec 19, 2023
fbb267d
use snapshot tests for `Label` tests
RobinMalfait Dec 19, 2023
5d297ad
use snapshot tests for `Portal` tests
RobinMalfait Dec 19, 2023
1660b74
use snapshot tests for `render` tests
RobinMalfait Dec 19, 2023
60177b4
add (private) `Tooltip` component
RobinMalfait Dec 19, 2023
57f2788
add internal `FormFields` component
RobinMalfait Dec 19, 2023
317fc21
add new `Button` component
RobinMalfait Dec 19, 2023
f07b113
add new `Checkbox` component
RobinMalfait Dec 19, 2023
44ae0b4
add new `DataInteractive` component
RobinMalfait Dec 19, 2023
9bbe00c
add new `Field` component
RobinMalfait Dec 19, 2023
745d2f4
add new `Fieldset` component
RobinMalfait Dec 19, 2023
0d99ae8
add new `Legend` component
RobinMalfait Dec 19, 2023
dd9b9d5
add new `Input` component
RobinMalfait Dec 19, 2023
fec9254
add new `Select` component
RobinMalfait Dec 19, 2023
08b3198
add new `Textarea` component
RobinMalfait Dec 19, 2023
94f7fe9
export new components
RobinMalfait Dec 19, 2023
3122165
WIP
RobinMalfait Dec 19, 2023
5045eba
remove `within: true`
RobinMalfait Dec 20, 2023
df3654c
group focus/hover/active hooks together
RobinMalfait Dec 20, 2023
08865e6
conditionally link anchor panel
RobinMalfait Dec 20, 2023
6af85cd
immediately focus the container
RobinMalfait Dec 20, 2023
297d214
prevent premature disabling of `Listbox`'s floating integration
RobinMalfait Dec 20, 2023
7d22cf3
improve scroll locking on iOS
RobinMalfait Dec 20, 2023
a117138
skip hydration tests for now
RobinMalfait Dec 20, 2023
252083e
skip certain focus trap tests for now
RobinMalfait Dec 20, 2023
1fafc52
update CHANGELOG.md
RobinMalfait Dec 20, 2023
f03dfc6
add missing requires
RobinMalfait Dec 20, 2023
32a7229
drop unused `@ts-expect-error`
RobinMalfait Dec 20, 2023
83c75a7
ignore type issues in playgrounds
RobinMalfait Dec 20, 2023
20165b4
add yarn resolutions to solve swc bug
RobinMalfait Dec 20, 2023
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
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"workspaces": [
"packages/*"
],
"resolutions": {
"next/@swc/helpers": "0.4.36"
},
"scripts": {
"react": "yarn workspace @headlessui/react",
"react-playground": "yarn workspace playground-react dev",
Expand Down Expand Up @@ -46,6 +49,7 @@
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.13.3",
"@swc-node/register": "^1.6.8",
"@swc/core": "^1.2.131",
"@swc/jest": "^0.2.17",
"@testing-library/jest-dom": "^5.16.4",
Expand All @@ -56,11 +60,11 @@
"jest": "26",
"lint-staged": "^12.2.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.6.2",
"prettier-plugin-organize-imports": "^3.2.3",
"prettier-plugin-tailwindcss": "0.4",
"prettier": "^3.1.0",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.5.7",
"rimraf": "^3.0.2",
"tslib": "^2.3.1",
"typescript": "^4.9.5"
"typescript": "^5.3.2"
}
}
29 changes: 24 additions & 5 deletions packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `immediate` prop to `<Combobox />` for immediately opening the Combobox when the `input` receives focus ([#2686](https://github.com/tailwindlabs/headlessui/pull/2686))
- Add `virtual` prop to `Combobox` component ([#2779](https://github.com/tailwindlabs/headlessui/pull/2779))
- Add new `Checkbox` component
- Add new `Radio` component as an alternative to the existing `RadioGroup.Option` component
- Add new `Button` component
- Add new `Input` component
- Add new `Textarea` component
- Add new `Select` component
- Add new `Field`, `Label`, `Description`, `Fieldset` and `Legend` components
- Add new `DataInteractive` component
- Add new `anchor` and `modal` prop to `ComboboxOptions`, `ListboxOptions`, `MenuItems` and `PopoverPanel` components
- Add new `ListboxSelectedOption` component
- Add new `MenuSection`, `MenuHeading`, and `MenuSeparator` components
- Add new simplified `data-*` attributes as an alternative to the existing `data-headlessui-state="..."` attribute
- Add `autoFocus` prop on focusable components (which maps to `data-autofocus`)

### Changed

- Bumped to React and React DOM 18
- Dialog is focused by default instead of the first focusable element (unless an element exists with a `data-autofocus` in the dialog)

### Fixed

- Don't call `<Dialog>`'s `onClose` twice on mobile devices ([#2690](https://github.com/tailwindlabs/headlessui/pull/2690))
Expand All @@ -21,11 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix outside click detection when component is mounted in the Shadow DOM ([#2866](https://github.com/tailwindlabs/headlessui/pull/2866))
- Fix CJS types ([#2880](https://github.com/tailwindlabs/headlessui/pull/2880))
- Fix error when transition classes contain new lines ([#2871](https://github.com/tailwindlabs/headlessui/pull/2871))

### Added

- Add `immediate` prop to `<Combobox />` for immediately opening the Combobox when the `input` receives focus ([#2686](https://github.com/tailwindlabs/headlessui/pull/2686))
- Add `virtual` prop to `Combobox` component ([#2779](https://github.com/tailwindlabs/headlessui/pull/2779))
- Fix iOS scroll lock glitches

## [1.7.17] - 2023-08-17

Expand Down
14 changes: 8 additions & 6 deletions packages/@headlessui-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,17 @@
},
"devDependencies": {
"@testing-library/react": "^13.0.0",
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"esbuild": "^0.11.18",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"snapshot-diff": "^0.8.1"
},
"dependencies": {
"@tanstack/react-virtual": "^3.0.0-beta.60",
"client-only": "^0.0.1"
"@floating-ui/react": "^0.26.2",
"@tanstack/react-virtual": "3.0.0-beta.60",
"@react-aria/focus": "^3.14.3",
"@react-aria/interactions": "3.0.0-nightly.2584"
}
}
39 changes: 39 additions & 0 deletions packages/@headlessui-react/src/components/button/button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { Button } from './button'

describe('Rendering', () => {
describe('Button', () => {
it('should render a button', async () => {
render(<Button>My Button</Button>)

expect(screen.getByRole('button')).toBeInTheDocument()
})

it('should default to `type="button"`', async () => {
render(<Button>My Button</Button>)

expect(screen.getByRole('button')).toHaveAttribute('type', 'button')
})

it('should render a button using a render prop', () => {
render(<Button>{(slot) => <>{JSON.stringify(slot)}</>}</Button>)

expect(screen.getByRole('button').textContent).toEqual(
JSON.stringify({
disabled: false,
hover: false,
focus: false,
active: false,
autofocus: false,
})
)
})

it('should map the `autoFocus` prop to a `data-autofocus` attribute', () => {
render(<Button autoFocus>My Button</Button>)

expect(screen.getByRole('button')).toHaveAttribute('data-autofocus')
})
})
})
88 changes: 88 additions & 0 deletions packages/@headlessui-react/src/components/button/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use client'

import { useFocusRing } from '@react-aria/focus'
import { useHover } from '@react-aria/interactions'
import { useMemo, type ElementType, type Ref } from 'react'
import { useActivePress } from '../../hooks/use-active-press'
import { useDisabled } from '../../internal/disabled'
import type { Props } from '../../types'
import {
forwardRefWithAs,
mergeProps,
render,
type HasDisplayName,
type RefProp,
} from '../../utils/render'

let DEFAULT_BUTTON_TAG = 'button' as const

type ButtonRenderPropArg = {
disabled: boolean
hover: boolean
focus: boolean
active: boolean
autofocus: boolean
}
type ButtonPropsWeControl = never

export type ButtonProps<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG> = Props<
TTag,
ButtonRenderPropArg,
ButtonPropsWeControl,
{
disabled?: boolean
autoFocus?: boolean
type?: 'button' | 'submit' | 'reset'
}
>

function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
props: ButtonProps<TTag>,
ref: Ref<HTMLElement>
) {
let providedDisabled = useDisabled()
let { disabled = providedDisabled || false, ...theirProps } = props

let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let { pressed: active, pressProps } = useActivePress({ disabled })

let ourProps = mergeProps(
{
ref,
disabled: disabled || undefined,
type: theirProps.type ?? 'button',
},
focusProps,
hoverProps,
pressProps
)

let slot = useMemo(
() =>
({
disabled,
hover,
focus,
active,
autofocus: props.autoFocus ?? false,
}) satisfies ButtonRenderPropArg,
[disabled, hover, focus, active, props.autoFocus]
)

return render({
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_BUTTON_TAG,
name: 'Button',
})
}

export interface _internal_ComponentButton extends HasDisplayName {
<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
props: ButtonProps<TTag> & RefProp<typeof ButtonFn>
): JSX.Element
}

export let Button = forwardRefWithAs(ButtonFn) as unknown as _internal_ComponentButton
121 changes: 121 additions & 0 deletions packages/@headlessui-react/src/components/checkbox/checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { render } from '@testing-library/react'
import React, { useState } from 'react'
import {
CheckboxState,
assertCheckbox,
getCheckbox,
} from '../../test-utils/accessibility-assertions'
import { Keys, click, focus, press } from '../../test-utils/interactions'
import {
commonControlScenarios,
commonFormScenarios,
commonRenderingScenarios,
} from '../../test-utils/scenarios'
import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs'
import { Checkbox, type CheckboxProps } from './checkbox'

commonRenderingScenarios(Checkbox, { getElement: getCheckbox })
commonControlScenarios(Checkbox)
commonFormScenarios((props) => <Checkbox defaultChecked {...props} />, {
async performUserInteraction(control) {
await click(control)
},
})

describe('Rendering', () => {
it(
'should be possible to put the checkbox in an indeterminate state',
suppressConsoleLogs(async () => {
render(<Checkbox indeterminate />)

assertCheckbox({ state: CheckboxState.Indeterminate })
})
)

it(
'should be possible to put the checkbox in an default checked state',
suppressConsoleLogs(async () => {
render(<Checkbox defaultChecked />)

assertCheckbox({ state: CheckboxState.Checked })
})
)

it(
'should render a checkbox in an unchecked state',
suppressConsoleLogs(async () => {
render(<Checkbox />)

assertCheckbox({ state: CheckboxState.Unchecked })
})
)
})

describe.each([
[
'Uncontrolled',
function Example(props: CheckboxProps) {
return <Checkbox {...props} />
},
],
[
'Controlled',
function Example(props: CheckboxProps) {
let [checked, setChecked] = useState(false)
return <Checkbox checked={checked} onChange={setChecked} {...props} />
},
],
])('Keyboard interactions (%s)', (_, Example) => {
describe('`Space` key', () => {
it(
'should be possible to toggle a checkbox',
suppressConsoleLogs(async () => {
render(<Example />)

assertCheckbox({ state: CheckboxState.Unchecked })

await focus(getCheckbox())
await press(Keys.Space)

assertCheckbox({ state: CheckboxState.Checked })

await press(Keys.Space)

assertCheckbox({ state: CheckboxState.Unchecked })
})
)
})
})

describe.each([
[
'Uncontrolled',
function Example(props: CheckboxProps) {
return <Checkbox {...props} />
},
],
[
'Controlled',
function Example(props: CheckboxProps) {
let [checked, setChecked] = useState(false)
return <Checkbox checked={checked} onChange={setChecked} {...props} />
},
],
])('Mouse interactions (%s)', (_, Example) => {
it(
'should be possible to toggle a checkbox by clicking it',
suppressConsoleLogs(async () => {
render(<Example />)

assertCheckbox({ state: CheckboxState.Unchecked })

await click(getCheckbox())

assertCheckbox({ state: CheckboxState.Checked })

await click(getCheckbox())

assertCheckbox({ state: CheckboxState.Unchecked })
})
)
})
Loading