diff --git a/src/lib/actions/floating-ui/index.ts b/src/lib/actions/floating-ui/index.ts new file mode 100644 index 00000000..424c6e4e --- /dev/null +++ b/src/lib/actions/floating-ui/index.ts @@ -0,0 +1,85 @@ +import { + autoUpdate, + computePosition, + flip, + offset, + type DetectOverflowOptions, + type Placement, + type MiddlewareState, + type Coords, + type Strategy, + type ReferenceElement +} from '@floating-ui/dom'; + +interface IAutoUpdateOptions { + ancestorScroll?: boolean; + ancestorResize?: boolean; + elementResize?: boolean; + animationFrame?: boolean; +} + +interface IFlipOptions extends DetectOverflowOptions { + mainAxis?: boolean; + crossAxis?: boolean; + fallbackAxisSideDirection?: 'none' | 'start' | 'end'; + flipAlignment?: boolean; + fallbackPlacements?: Array; + fallbackStrategy?: 'bestFit' | 'initialPlacement'; +} + +interface IAxesOffsets { + mainAxis?: number; + crossAxis?: number; + alignmentAxis?: number | null; +} + +type TOffsetOptions = number | IAxesOffsets | ((state: MiddlewareState) => number | IAxesOffsets); + +interface IShiftOptions extends DetectOverflowOptions { + mainAxis?: boolean; + crossAxis?: boolean; + limiter?: { + fn: (state: MiddlewareState) => Coords; + options?: unknown; + }; +} + +interface IConfig { + autoUpdate?: IAutoUpdateOptions; + placement?: Placement; + strategy?: Strategy; + offset?: TOffsetOptions; + shift?: IShiftOptions; + flip?: IFlipOptions; +} + +export default function floatingUI( + node: HTMLElement, + config: IConfig = { + placement: 'bottom-start', + strategy: 'absolute' + } +): { destroy: () => void } { + const referenceEl = node.previousElementSibling as ReferenceElement; + + function updatePosition() { + computePosition(referenceEl, node, { + placement: config?.placement, + strategy: config?.strategy, + middleware: [offset(config.offset), flip()] + }).then(({ x, y }) => { + Object.assign(node.style, { + left: `${x}px`, + top: `${y}px` + }); + }); + } + + const cleanup = autoUpdate(referenceEl, node, updatePosition, config?.autoUpdate); + + return { + destroy() { + cleanup(); + } + }; +} diff --git a/src/lib/actions/index.ts b/src/lib/actions/index.ts index 572d3760..d82f53dc 100644 --- a/src/lib/actions/index.ts +++ b/src/lib/actions/index.ts @@ -12,6 +12,7 @@ import useActions, { type ActionArray } from './use-actions'; import clipboard from './clipboard'; +import floatingUI from './floating-ui'; export { tooltip, @@ -27,5 +28,6 @@ export { SVGActionEntry, SVGActionArray, ActionArray, - clipboard + clipboard, + floatingUI };