diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 72c1d6dba..bf548403a 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add ability to render multiple `Dialog` components at once (without nesting them) ([#3242](https://github.com/tailwindlabs/headlessui/pull/3242)) -- Add new data-attribute-based transition API ([#3273](https://github.com/tailwindlabs/headlessui/pull/3273), [#3285](https://github.com/tailwindlabs/headlessui/pull/3285), [#3307](https://github.com/tailwindlabs/headlessui/pull/3307), [#3309](https://github.com/tailwindlabs/headlessui/pull/3309)) +- Add new data-attribute-based transition API ([#3273](https://github.com/tailwindlabs/headlessui/pull/3273), [#3285](https://github.com/tailwindlabs/headlessui/pull/3285), [#3307](https://github.com/tailwindlabs/headlessui/pull/3307), [#3309](https://github.com/tailwindlabs/headlessui/pull/3309), [#3312](https://github.com/tailwindlabs/headlessui/pull/3312)) - Add `DialogBackdrop` component ([#3307](https://github.com/tailwindlabs/headlessui/pull/3307), [#3310](https://github.com/tailwindlabs/headlessui/pull/3310)) - Add `PopoverBackdrop` component to replace `PopoverOverlay` ([#3308](https://github.com/tailwindlabs/headlessui/pull/3308)) diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index f89e5140a..ba62f11d3 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -41,7 +41,7 @@ import { useResolveButtonType } from '../../hooks/use-resolve-button-type' import { useScrollLock } from '../../hooks/use-scroll-lock' import { useSyncRefs } from '../../hooks/use-sync-refs' import { useTrackedPointer } from '../../hooks/use-tracked-pointer' -import { useTransition, type TransitionData } from '../../hooks/use-transition' +import { transitionDataAttributes, useTransition } from '../../hooks/use-transition' import { useTreeWalker } from '../../hooks/use-tree-walker' import { useWatch } from '../../hooks/use-watch' import { useDisabled } from '../../internal/disabled' @@ -1564,7 +1564,7 @@ let DEFAULT_OPTIONS_TAG = 'div' as const type OptionsRenderPropArg = { open: boolean option: unknown -} & TransitionData +} type OptionsPropsWeControl = 'aria-labelledby' | 'aria-multiselectable' | 'role' | 'tabIndex' let OptionsRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static @@ -1665,9 +1665,8 @@ function OptionsFn( return { open: data.comboboxState === ComboboxState.Open, option: undefined, - ...transitionData, } satisfies OptionsRenderPropArg - }, [data.comboboxState, transitionData]) + }, [data.comboboxState]) // When the user scrolls **using the mouse** (so scroll event isn't appropriate) // we want to make sure that the current activation trigger is set to pointer. @@ -1706,6 +1705,7 @@ function OptionsFn( } as CSSProperties, onWheel: data.activationTrigger === ActivationTrigger.Pointer ? undefined : handleWheel, onMouseDown: handleMouseDown, + ...transitionDataAttributes(transitionData), }) // We should freeze when the combobox is visible but "closed". This means that diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx index a173ff6e6..66f593803 100644 --- a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx +++ b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx @@ -24,7 +24,7 @@ import { useEvent } from '../../hooks/use-event' import { useId } from '../../hooks/use-id' import { useResolveButtonType } from '../../hooks/use-resolve-button-type' import { optionalRef, useSyncRefs } from '../../hooks/use-sync-refs' -import { useTransition, type TransitionData } from '../../hooks/use-transition' +import { transitionDataAttributes, useTransition } from '../../hooks/use-transition' import { CloseProvider } from '../../internal/close-provider' import { OpenClosedProvider, @@ -425,7 +425,7 @@ let DEFAULT_PANEL_TAG = 'div' as const type PanelRenderPropArg = { open: boolean close: (focusableElement?: HTMLElement | MutableRefObject) => void -} & TransitionData +} type DisclosurePanelPropsWeControl = never let PanelRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static @@ -475,13 +475,13 @@ function PanelFn( return { open: state.disclosureState === DisclosureStates.Open, close, - ...transitionData, } satisfies PanelRenderPropArg - }, [state.disclosureState, close, transitionData]) + }, [state.disclosureState, close]) let ourProps = { ref: panelRef, id, + ...transitionDataAttributes(transitionData), } return ( diff --git a/packages/@headlessui-react/src/components/listbox/listbox.tsx b/packages/@headlessui-react/src/components/listbox/listbox.tsx index 6f84675b5..2d551b8a2 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.tsx @@ -41,7 +41,7 @@ import { useScrollLock } from '../../hooks/use-scroll-lock' import { useSyncRefs } from '../../hooks/use-sync-refs' import { useTextValue } from '../../hooks/use-text-value' import { useTrackedPointer } from '../../hooks/use-tracked-pointer' -import { useTransition, type TransitionData } from '../../hooks/use-transition' +import { transitionDataAttributes, useTransition } from '../../hooks/use-transition' import { useDisabled } from '../../internal/disabled' import { FloatingProvider, @@ -870,7 +870,7 @@ let SelectedOptionContext = createContext(false) let DEFAULT_OPTIONS_TAG = 'div' as const type OptionsRenderPropArg = { open: boolean -} & TransitionData +} type OptionsPropsWeControl = | 'aria-activedescendant' | 'aria-labelledby' @@ -1090,9 +1090,8 @@ function OptionsFn( let slot = useMemo(() => { return { open: data.listboxState === ListboxStates.Open, - ...transitionData, } satisfies OptionsRenderPropArg - }, [data.listboxState, transitionData]) + }, [data.listboxState]) let ourProps = mergeProps(anchor ? getFloatingPanelProps() : {}, { id, @@ -1113,6 +1112,7 @@ function OptionsFn( ...style, '--button-width': useElementSize(data.buttonRef, true).width, } as CSSProperties, + ...transitionDataAttributes(transitionData), }) // We should freeze when the listbox is visible but "closed". This means that diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx index 7fb21a2c1..804e4e117 100644 --- a/packages/@headlessui-react/src/components/menu/menu.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.tsx @@ -37,7 +37,7 @@ import { useScrollLock } from '../../hooks/use-scroll-lock' import { useSyncRefs } from '../../hooks/use-sync-refs' import { useTextValue } from '../../hooks/use-text-value' import { useTrackedPointer } from '../../hooks/use-tracked-pointer' -import { useTransition, type TransitionData } from '../../hooks/use-transition' +import { transitionDataAttributes, useTransition } from '../../hooks/use-transition' import { useTreeWalker } from '../../hooks/use-tree-walker' import { FloatingProvider, @@ -565,7 +565,7 @@ function ButtonFn( let DEFAULT_ITEMS_TAG = 'div' as const type ItemsRenderPropArg = { open: boolean -} & TransitionData +} type ItemsPropsWeControl = 'aria-activedescendant' | 'aria-labelledby' | 'role' | 'tabIndex' let ItemsRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static @@ -760,9 +760,8 @@ function ItemsFn( let slot = useMemo(() => { return { open: state.menuState === MenuStates.Open, - ...transitionData, } satisfies ItemsRenderPropArg - }, [state.menuState, transitionData]) + }, [state.menuState]) let ourProps = mergeProps(anchor ? getFloatingPanelProps() : {}, { 'aria-activedescendant': @@ -782,6 +781,7 @@ function ItemsFn( ...style, '--button-width': useElementSize(state.buttonRef, true).width, } as CSSProperties, + ...transitionDataAttributes(transitionData), }) return ( diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx index 3c991823f..c86ea41c1 100644 --- a/packages/@headlessui-react/src/components/popover/popover.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.tsx @@ -36,7 +36,7 @@ import { useMainTreeNode, useRootContainers } from '../../hooks/use-root-contain import { useScrollLock } from '../../hooks/use-scroll-lock' import { optionalRef, useSyncRefs } from '../../hooks/use-sync-refs' import { Direction as TabDirection, useTabDirection } from '../../hooks/use-tab-direction' -import { useTransition, type TransitionData } from '../../hooks/use-transition' +import { transitionDataAttributes, useTransition } from '../../hooks/use-transition' import { CloseProvider } from '../../internal/close-provider' import { FloatingProvider, @@ -732,7 +732,7 @@ function ButtonFn( let DEFAULT_BACKDROP_TAG = 'div' as const type BackdropRenderPropArg = { open: boolean -} & TransitionData +} type BackdropPropsWeControl = 'aria-hidden' let BackdropRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static @@ -778,15 +778,15 @@ function BackdropFn( let slot = useMemo(() => { return { open: popoverState === PopoverStates.Open, - ...transitionData, } satisfies BackdropRenderPropArg - }, [popoverState, transitionData]) + }, [popoverState]) let ourProps = { ref: backdropRef, id, 'aria-hidden': true, onClick: handleClick, + ...transitionDataAttributes(transitionData), } return render({ @@ -806,7 +806,7 @@ let DEFAULT_PANEL_TAG = 'div' as const type PanelRenderPropArg = { open: boolean close: (focusableElement?: HTMLElement | MutableRefObject) => void -} & TransitionData +} let PanelRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static @@ -936,9 +936,8 @@ function PanelFn( return { open: state.popoverState === PopoverStates.Open, close, - ...transitionData, } satisfies PanelRenderPropArg - }, [state.popoverState, close, transitionData]) + }, [state.popoverState, close]) let ourProps: Record = mergeProps(anchor ? getFloatingPanelProps() : {}, { ref: panelRef, @@ -968,6 +967,7 @@ function PanelFn( ...style, '--button-width': useElementSize(state.button, true).width, } as React.CSSProperties, + ...transitionDataAttributes(transitionData), }) let direction = useTabDirection() diff --git a/packages/@headlessui-react/src/components/transition/__snapshots__/transition.test.tsx.snap b/packages/@headlessui-react/src/components/transition/__snapshots__/transition.test.tsx.snap index 1bc291473..7d2fa9fb7 100644 --- a/packages/@headlessui-react/src/components/transition/__snapshots__/transition.test.tsx.snap +++ b/packages/@headlessui-react/src/components/transition/__snapshots__/transition.test.tsx.snap @@ -132,7 +132,6 @@ exports[`Setup API transition classes should be possible to passthrough the tran class="enter enter-from" data-closed="" data-enter="" - data-headlessui-state="closed enter transition" data-transition="" style="" > diff --git a/packages/@headlessui-react/src/components/transition/transition.test.tsx b/packages/@headlessui-react/src/components/transition/transition.test.tsx index 045f47430..5911fbc7d 100644 --- a/packages/@headlessui-react/src/components/transition/transition.test.tsx +++ b/packages/@headlessui-react/src/components/transition/transition.test.tsx @@ -374,7 +374,6 @@ describe('Setup API', () => {
` is done, but there is still a // child `` busy, then `visible` would be `false`, while // `state` would still be `TreeStates.Visible`. - let [, slot] = useTransition(enabled, container, show, { start, end }) + let [, transitionData] = useTransition(enabled, container, show, { start, end }) let ourProps = compact({ ref: transitionRef, @@ -451,25 +451,26 @@ function TransitionChildFn @@ -477,7 +478,6 @@ function TransitionChildFn = {} + for (let key in data) { + if (data[key as keyof TransitionData] === true) { + attributes[`data-${key}`] = '' + } + } + return attributes +} + export function useTransition( enabled: boolean, elementRef: MutableRefObject,