2.0.0 Alpha prep (#2887)

* bump React & React DOM dependencies

* fix typo `TOmitableProps` → `TOmittableProps`

* bump prettier

* run prettier after prettier version bump

* bump TypeScript

* run prettier after TypeScript version bump

* enable `verbatimModuleSyntax`

This ensures all imported types are using the `type` keyword.

* add `type` to type related imports

* add common testing scenarios

Will be used in the new and existing components.

* add script to make Next.js happy

Right now Next.js does barrel file optimization and re-writing imports
to a real path in the `dist` folder. Most of those rewrites don't
actually exist because they have an assumption:

```js
import { FooBar } from '@headlessui/react'
```

is rewritten as:
```js
import { FooBar } from '@headlessui/react/dist/components/foo-bar/foo-bar'
```

This script will make sure these paths exist...

* improve `by` prop, introduce `useByComparator`

This hook has a default implementation when comparing objects. If the
object contains an `id`, then we will compare the objects by their
`id`'s without the user of the library needing to specify `by="id"`.

If the objects don't have an `id` prop, then the default is still to
compare by reference (unless specicified otherwise).

* sync yarn.lock

* rename `Features` to `HiddenFeatures` for `Hidden` component

* rename `Features` to `FocusTrapFeatures` in `FocusTrap` component

* rename `Features` to `RenderFeatures` in `render` util

* add `floating-ui` as a dependency + introduce internal floating related components

* bump Vue dependencies

* ensure scroll bar calculations can't go negative

* improve types in `@headlessui/vue`

* use snapshot tests for `Transition` tests in `@headlessui/vue`

* use snapshot tests for `portal` tests in `@headlessui/vue`

* rename `src/components/transitions/` to `src/components/transition/` (singular)

This is so that we can be consistent with the other components.

* drop custom `toMatchFormattedCss`, prefer snapshot tests instead

* use snapshot tests for `Label` tests in `@headlessui/vue`

* use snapshot tests for `Description` tests in `@headlessui/vue`

* sort exported components in tests for `@headlessui/vue`

* use snapshot tests in `@headlessui/tailwindcss`

* rename `mergeProps` to `mergePropsAdvanced`

This is a more complex version of a soon to be exported `mergeProps`
that we will be using in our components.

* do not expose `aria-labelledby` if it is only referencing itself

* expose boolean state as `kebab-case` instead of `camelCase`

These are the ones being exposed inside `data-headlessui-state="..."`

* expose boolean data attributes

A slot with `{active,focus,hover}` will be exposed as:
```html
<span data-headlessui-state="active focus hover"></span>
```

But also as boolean attributes:
```html
<span data-active data-focus data-hover></span>
```

* improve internal types for `className` in `render` util

* ensure we keep exposed data attributes into account when trying to forward them to the component inside the `Fragment`

* add small typescript type fix

This is internal code, and the public API is not influenced by this
`:any`. It does make TypeScript happy.

* introduce `mergeProps` util to be used in our components

This will help us to merge props, when event handlers are available they
will be merged by wrapping them in a function such that both (or more)
event handlers are called for the same `event`.

* add new internal `Modal` component

* fix: when using `Focus.Previous` with `activeIndex = -1` should start at the end

* prefer `window.scrollY` instead of `window.pageYOffset`

Because `window.pageYOffset` is deprecated.

* add `'use client'` directives on client only components

These components use hooks that won't work in server components and you
will receive an error otherwise.

* drop `import 'client-only'` in favor of the `'use client'` directive

* add React Aria dependencies

* pin beta dependencies

* prettier bump formatting

* improve TypeScript types in tests

* use new Jest matchers instead of deprecated ones

* improve typescript types in Vue

* prefer `useLabelledBy` and `useDescribedBy`

* add internal `DisabledProvider`

* add internal `IdProvider`

* add internal `useDidElementMove` hook

* add internal `useElementSize` hook

* add internal `useIsTouchDevice` hook

* add internal `useActivePress` hook

* use snapshot tests for `Description` tests

* use snapshot tests for `Label` tests

* use snapshot tests for `Portal` tests

* use snapshot tests for `render` tests

* add (private) `Tooltip` component

Currently this one is not ready yet, so its not publicly exposed yet.

* add internal `FormFields` component

This one adds a component to render (hidden) inputs for native form
support. It also ensures that form fields can be hoisted to the end of
the nearest `Field`. If the components are not inside a `Field` they
will be rendered in place.

* add new `Button` component

* add new `Checkbox` component

* add new `DataInteractive` component

* add new `Field` component

* add new `Fieldset` component

* add new `Legend` component

* add new `Input` component

* add new `Select` component

* add new `Textarea` component

* export new components

* WIP

* remove `within: true`

This only makes sense if anything inside the current element receives
focus, which is not the case for `input`, `select`, `textarea` or
`Radio/RadioOption`.

* group focus/hover/active hooks together

* conditionally link anchor panel

* immediately focus the container

* prevent premature disabling of `Listbox`'s floating integration

+ Track whether the button moved or not when disabling such that we can
  disable the transitions earlier.

* improve scroll locking on iOS

* skip hydration tests for now

* skip certain focus trap tests for now

* update CHANGELOG.md

* add missing requires

* drop unused `@ts-expect-error`

* ignore type issues in playgrounds

These playgrounds are mainly test playgrounds. Lower priority for now,
we will get back to them.

* add yarn resolutions to solve swc bug
This commit is contained in:
Robin Malfait
2023-12-20 19:57:57 +01:00
committed by GitHub
parent 01a34cb0c4
commit e662f12398
203 changed files with 11754 additions and 6201 deletions
@@ -0,0 +1,52 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { focus, mouseEnter } from '../../test-utils/interactions'
import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs'
import { DataInteractive } from './data-interactive'
it(
'should expose focus data attributes on the element',
suppressConsoleLogs(async () => {
render(
<DataInteractive>
<a href="alice">Alice</a>
</DataInteractive>
)
let a = screen.getByText('Alice')
// Should not have the data attribute
expect(a).not.toHaveAttribute('data-focus')
// Focus on the element
await focus(a)
// Should be focused
expect(a).toHaveFocus()
// Should have the data attribute
expect(a).toHaveAttribute('data-focus')
})
)
it(
'should expose hover data attributes on the element',
suppressConsoleLogs(async () => {
render(
<DataInteractive>
<a href="alice">Alice</a>
</DataInteractive>
)
let a = screen.getByText('Alice')
// Should not have the data attribute
expect(a).not.toHaveAttribute('data-hover')
// Hover on the element
await mouseEnter(a)
// Should have the data attribute
expect(a).toHaveAttribute('data-hover')
})
)
@@ -0,0 +1,67 @@
'use client'
import { useFocusRing } from '@react-aria/focus'
import { useHover } from '@react-aria/interactions'
import { Fragment, useMemo, type ElementType, type Ref } from 'react'
import { useActivePress } from '../../hooks/use-active-press'
import type { Props } from '../../types'
import {
forwardRefWithAs,
mergeProps,
render,
type HasDisplayName,
type RefProp,
} from '../../utils/render'
let DEFAULT_DATA_INTERACTIVE_TAG = Fragment
type DataInteractiveRenderPropArg = {
hover: boolean
focus: boolean
active: boolean
}
type DataInteractivePropsWeControl = never
export type DataInteractiveProps<TTag extends ElementType = typeof DEFAULT_DATA_INTERACTIVE_TAG> =
Props<TTag, DataInteractiveRenderPropArg, DataInteractivePropsWeControl, {}>
function DataInteractiveFn<TTag extends ElementType = typeof DEFAULT_DATA_INTERACTIVE_TAG>(
props: DataInteractiveProps<TTag>,
ref: Ref<HTMLElement>
) {
let { ...theirProps } = props
// Ideally we can use a `disabled` prop, but that would depend on the props of the child element
// and we don't have access to that in this component.
let disabled = false
let { isFocusVisible: focus, focusProps } = useFocusRing()
let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled })
let { pressed: active, pressProps } = useActivePress({ disabled })
let ourProps = mergeProps({ ref }, focusProps, hoverProps, pressProps)
let slot = useMemo(
() => ({ hover, focus, active }) satisfies DataInteractiveRenderPropArg,
[hover, focus, active]
)
return render({
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_DATA_INTERACTIVE_TAG,
name: 'DataInteractive',
})
}
export interface _internal_ComponentDataInteractive extends HasDisplayName {
<TTag extends ElementType = typeof DEFAULT_DATA_INTERACTIVE_TAG>(
props: DataInteractiveProps<TTag> & RefProp<typeof DataInteractiveFn>
): JSX.Element
}
export let DataInteractive = forwardRefWithAs(
DataInteractiveFn
) as unknown as _internal_ComponentDataInteractive