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

Add string shorthand for the anchor prop #3133

Merged
merged 4 commits into from Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/@headlessui-react/CHANGELOG.md
Expand Up @@ -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

Expand Down
22 changes: 12 additions & 10 deletions packages/@headlessui-react/src/internal/floating.tsx
Expand Up @@ -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 & {
/**
Expand All @@ -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 & {
/**
Expand Down Expand Up @@ -93,11 +95,11 @@ PlacementContext.displayName = 'PlacementContext'

export function useResolvedAnchor<T extends AnchorProps | AnchorPropsWithSelection>(
anchor?: T
): Exclude<T, boolean> | null {
): Exclude<T, boolean | string> | null {
return useMemo(() => {
if (anchor === true) return {} as Exclude<T, boolean> // Enable with defaults
if (!anchor) return null // Disable entirely
return anchor as Exclude<T, boolean> // User-provided value
if (typeof anchor === 'string') return { to: anchor } as Exclude<T, boolean | string> // Simple string based value,
return anchor as Exclude<T, boolean | string> // User-provided value
}, [anchor])
}

Expand All @@ -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(
Expand Down Expand Up @@ -389,12 +391,12 @@ function useFixScrollingPixel(element: HTMLElement | null) {
}

function useResolvedConfig(
config: (Exclude<AnchorPropsWithSelection, boolean> & InternalFloatingPanelProps) | null,
config: (Exclude<AnchorPropsWithSelection, boolean | string> & 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 }
}
Expand Down
4 changes: 2 additions & 2 deletions playgrounds/react/pages/menu/menu-with-transition.tsx
Expand Up @@ -41,8 +41,8 @@ export default function Home() {
afterLeave={() => console.log('After leave')}
>
<Menu.Items
anchor={{ to: 'bottom start', gap: 'var(--gap)' }}
className="w-[calc(var(--button-width)*2)] divide-y divide-gray-100 rounded-md border border-gray-200 bg-white shadow-lg outline-none [--gap:theme(spacing.2)]"
anchor="bottom start"
className="w-[calc(var(--button-width)*2)] divide-y divide-gray-100 rounded-md border border-gray-200 bg-white shadow-lg outline-none [--anchor-gap:theme(spacing.2)]"
>
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
Expand Down
8 changes: 4 additions & 4 deletions playgrounds/react/pages/popover/popover.tsx
Expand Up @@ -60,8 +60,8 @@ export default function Home() {
<Popover as="div" className="relative">
<Button>Portal</Button>
<Popover.Panel
anchor={{ to: 'bottom start', gap: 4 }}
className="flex w-64 flex-col border-2 border-blue-900 bg-gray-100"
anchor="bottom start"
className="flex w-64 flex-col border-2 border-blue-900 bg-gray-100 [--anchor-gap:theme(spacing.1)]"
>
{items.map((item) => (
<Button key={item}>Portal - {item}</Button>
Expand All @@ -72,9 +72,9 @@ export default function Home() {
<Popover as="div" className="relative">
<Button>Focus in Portal</Button>
<Popover.Panel
anchor={{ to: 'bottom start', gap: 4 }}
focus
className="flex w-64 flex-col border-2 border-blue-900 bg-gray-100"
anchor="bottom start"
className="flex w-64 flex-col border-2 border-blue-900 bg-gray-100 [--anchor-gap:theme(spacing.1)]"
>
{items.map((item) => (
<Button key={item}>Focus in Portal - {item}</Button>
Expand Down