From 8c7cbb3b093f26e71fa4581defbd2ffcf3a6cf59 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 25 Apr 2024 02:13:25 +0200 Subject: [PATCH] Add string shorthand for the `anchor` prop (#3133) * allow to define `anchor` as a string. E.g.: `anchor="bottom"` * use `--anchor-gap`, `--anchor-offset` and `--anchor-padding` variables by default This way simply adding `anchor="bottom"` to one of the anchorable components will also use these variables defined on the component. * update playgrounds to use new string-based `anchor` prop + CSS variables * update changelog --- packages/@headlessui-react/CHANGELOG.md | 1 + .../src/internal/floating.tsx | 22 ++++++++++--------- .../react/pages/menu/menu-with-transition.tsx | 4 ++-- playgrounds/react/pages/popover/popover.tsx | 8 +++---- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 1646eb628f..1f325f65e6 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow passing a boolean to the `anchor` prop ([#3121](https://github.com/tailwindlabs/headlessui/pull/3121)) - Add `portal` prop to `Combobox`, `Listbox`, `Menu` and `Popover` components ([#3124](https://github.com/tailwindlabs/headlessui/pull/3124)) - Add frozen value to `ComboboxOptions` component ([#3126](https://github.com/tailwindlabs/headlessui/pull/3126)) +- Add string shorthand for the `anchor` prop ([#3133](https://github.com/tailwindlabs/headlessui/pull/3133)) ## [1.7.19] - 2024-04-15 diff --git a/packages/@headlessui-react/src/internal/floating.tsx b/packages/@headlessui-react/src/internal/floating.tsx index e7c8200b4e..802d3019f8 100644 --- a/packages/@headlessui-react/src/internal/floating.tsx +++ b/packages/@headlessui-react/src/internal/floating.tsx @@ -38,7 +38,8 @@ type BaseAnchorProps = { } export type AnchorProps = - | boolean // Enable with defaults, or disable entirely + | false // Disable entirely + | (`${Placement}` | `${Placement} ${Align}`) // String value to define the placement | Partial< BaseAnchorProps & { /** @@ -50,7 +51,8 @@ export type AnchorProps = > export type AnchorPropsWithSelection = - | boolean // Enable with defaults, or disable entirely + | false // Disable entirely + | (`${Placement | 'selection'}` | `${Placement | 'selection'} ${Align}`) | Partial< BaseAnchorProps & { /** @@ -93,11 +95,11 @@ PlacementContext.displayName = 'PlacementContext' export function useResolvedAnchor( anchor?: T -): Exclude | null { +): Exclude | null { return useMemo(() => { - if (anchor === true) return {} as Exclude // Enable with defaults if (!anchor) return null // Disable entirely - return anchor as Exclude // User-provided value + if (typeof anchor === 'string') return { to: anchor } as Exclude // Simple string based value, + return anchor as Exclude // User-provided value }, [anchor]) } @@ -124,8 +126,8 @@ export function useFloatingPanelProps() { export function useFloatingPanel( placement: (AnchorPropsWithSelection & InternalFloatingPanelProps) | null = null ) { - if (placement === true) placement = {} // Enable with defaults if (placement === false) placement = null // Disable entirely + if (typeof placement === 'string') placement = { to: placement } // Simple string based value let updatePlacementConfig = useContext(PlacementContext) let stablePlacement = useMemo( @@ -389,12 +391,12 @@ function useFixScrollingPixel(element: HTMLElement | null) { } function useResolvedConfig( - config: (Exclude & InternalFloatingPanelProps) | null, + config: (Exclude & InternalFloatingPanelProps) | null, element?: HTMLElement | null ) { - let gap = useResolvePxValue(config?.gap, element) - let offset = useResolvePxValue(config?.offset, element) - let padding = useResolvePxValue(config?.padding, element) + let gap = useResolvePxValue(config?.gap ?? 'var(--anchor-gap, 0)', element) + let offset = useResolvePxValue(config?.offset ?? 'var(--anchor-offset, 0)', element) + let padding = useResolvePxValue(config?.padding ?? 'var(--anchor-padding, 0)', element) return { ...config, gap, offset, padding } } diff --git a/playgrounds/react/pages/menu/menu-with-transition.tsx b/playgrounds/react/pages/menu/menu-with-transition.tsx index ee4b5b97c8..eadd3219ad 100644 --- a/playgrounds/react/pages/menu/menu-with-transition.tsx +++ b/playgrounds/react/pages/menu/menu-with-transition.tsx @@ -41,8 +41,8 @@ export default function Home() { afterLeave={() => console.log('After leave')} >

Signed in as

diff --git a/playgrounds/react/pages/popover/popover.tsx b/playgrounds/react/pages/popover/popover.tsx index 868751d822..60fc80deba 100644 --- a/playgrounds/react/pages/popover/popover.tsx +++ b/playgrounds/react/pages/popover/popover.tsx @@ -60,8 +60,8 @@ export default function Home() { {items.map((item) => ( @@ -72,9 +72,9 @@ export default function Home() { {items.map((item) => (