floating: add constraint size option

This commit is contained in:
Elijah Duffy
2026-04-12 17:34:02 -07:00
parent 18b0b8963a
commit ab352b217a

View File

@@ -4,7 +4,7 @@
* for more details, examples, and original source.
*/
import { computePosition, autoUpdate, flip, offset, type Placement } from '@floating-ui/dom';
import { computePosition, autoUpdate, flip, offset, type Placement, size } from '@floating-ui/dom';
import { createAttachmentKey } from 'svelte/attachments';
/**
@@ -17,6 +17,13 @@ export interface PopoverOptions {
placement?: Placement;
/** Offset distance between the reference and floating elements (default: 8) */
offset?: number;
/**
* Constraints the width and height of the popover to prevent it from
* overflowing the viewport. If true, the popover will adjust its max-width
* and max-height to fit. Scrolling is the responsibility of the parent
* element. Default is true.
*/
constrainSize?: boolean;
/** Callback when the popover is opened or closed */
ontoggle?: (open: boolean) => void;
}
@@ -29,7 +36,8 @@ export class Popover {
private options: PopoverOptions = {
interaction: 'click',
placement: 'bottom-start',
offset: 8
offset: 8,
constrainSize: true
};
private referenceElement: HTMLElement | undefined = $state();
private floatingElement: HTMLElement | undefined = $state();
@@ -165,7 +173,21 @@ export class Popover {
}
const position = await computePosition(this.referenceElement, this.floatingElement, {
placement: this.options.placement,
middleware: [flip(), offset(this.options.offset)]
middleware: [
flip(),
offset(this.options.offset),
size({
apply: ({ availableWidth, availableHeight, elements }) => {
if (this.options.constrainSize) {
elements.floating.style.maxWidth = `${availableWidth}px`;
elements.floating.style.maxHeight = `${availableHeight}px`;
} else {
elements.floating.style.maxWidth = '';
elements.floating.style.maxHeight = '';
}
}
})
]
});
const { x, y } = position;
Object.assign(this.floatingElement.style, {