@@ -4,100 +4,127 @@ import {
44 useVisibleTask$ ,
55 type QwikIntrinsicElements ,
66} from '@builder.io/qwik' ;
7+
78import {
89 ReferenceElement ,
9- arrow ,
1010 autoUpdate ,
1111 computePosition ,
12- flip ,
13- offset ,
14- shift ,
12+ offset as _offset ,
13+ flip as _flip ,
14+ shift as _shift ,
15+ arrow as _arrow ,
16+ size as _size ,
17+ autoPlacement as _autoPlacement ,
18+ hide as _hide ,
19+ inline as _inline ,
20+ type Placement ,
21+ type DetectOverflowOptions ,
22+ type ComputePositionReturn ,
1523} from '@floating-ui/dom' ;
24+
25+ import type {
26+ ShiftOptions ,
27+ OffsetOptions ,
28+ ArrowOptions ,
29+ FlipOptions ,
30+ SizeOptions ,
31+ AutoPlacementOptions ,
32+ HideOptions ,
33+ InlineOptions ,
34+ Platform ,
35+ } from '@floating-ui/core' ;
36+
1637import ComboboxContextId from './combobox-context-id' ;
1738import type { ComboboxContext , Option } from './combobox-context.type' ;
1839
19- // type ArrowData = { element: HTMLElement; padding?: number | undefined };
20-
2140export type ComboboxListboxProps = {
22- // come back to shift later
23- arrowData ?: { element : HTMLElement ; padding ?: number | undefined } ;
24- setArrow ?: boolean ;
25- setShift ?: {
26- mainAxis ?: boolean ;
27- crossAxis ?: boolean ;
28- limiter ?: {
29- fn : ( state : unknown ) => unknown ;
30- options ?: unknown ;
31- } ;
32- } ;
33- setOffset ?:
34- | number
35- | {
36- mainAxis ?: number ;
37- crossAxis ?: number ;
38- alignmentAxis ?: number | null ;
39- } ;
40- setFlip ?: boolean ;
41- placement ?:
42- | 'top'
43- | 'top-start'
44- | 'top-end'
45- | 'right'
46- | 'right-start'
47- | 'right-end'
48- | 'bottom'
49- | 'bottom-start'
50- | 'bottom-end'
51- | 'left'
52- | 'left-start'
53- | 'left-end' ;
41+ // main floating UI props
42+ placement ?: Placement ;
5443 ancestorScroll ?: boolean ;
5544 ancestorResize ?: boolean ;
5645 elementResize ?: boolean ;
5746 layoutShift ?: boolean ;
5847 animationFrame ?: boolean ;
48+
49+ // middleware
50+ offset ?: OffsetOptions ;
51+ shift ?: Partial < ShiftOptions & DetectOverflowOptions > | boolean ;
52+ flip ?: FlipOptions | boolean ;
53+ arrow ?: ArrowOptions ;
54+ size ?: SizeOptions ;
55+ autoPlacement ?: AutoPlacementOptions | boolean ;
56+ hide ?: HideOptions | boolean ;
57+ inline ?: InlineOptions | boolean ;
58+ onPositionComputed ?: ( resolvedData : ComputePositionReturn ) => void ;
59+
60+ // misc
61+ transform : string ;
62+ platform : Platform ;
5963} & QwikIntrinsicElements [ 'ul' ] ;
6064
6165export const ComboboxListbox = component$ (
6266 < O extends Option = Option > ( {
63- setOffset ,
64- setFlip = true ,
67+ offset ,
68+ flip = true ,
6569 placement = 'bottom' ,
66- setShift,
67- setArrow,
68- arrowData,
70+ shift,
71+ arrow,
72+ size,
73+ hide,
74+ inline,
75+ autoPlacement = false ,
6976 ancestorScroll = true ,
7077 ancestorResize = true ,
7178 elementResize = true ,
7279 animationFrame = false ,
80+ onPositionComputed,
81+ transform,
82+ platform,
7383 ...props
7484 } : ComboboxListboxProps ) => {
7585 const context = useContext < ComboboxContext < O > > ( ComboboxContextId ) ;
7686 const listboxId = `${ context . localId } -listbox` ;
7787
78- useVisibleTask$ ( function setListboxPosition ( { cleanup } ) {
79- // Our settings from Floating UI
88+ useVisibleTask$ ( function setFloatingUIConfig ( { cleanup } ) {
8089 function updatePosition ( ) {
81- const middleware = [ offset ( setOffset ) , setFlip && flip ( ) , setShift && shift ( ) ] ;
90+ const middleware = [ _offset ( offset ) , arrow && _arrow ( arrow ) , size && _size ( size ) ] ;
8291
83- if ( setArrow && arrowData ) {
84- middleware . push ( arrow ( arrowData ) ) ;
85- }
92+ // offers a bool to turn on or off default config, or customize it.
93+ const middlewareFunctions = [ _flip , _shift , _autoPlacement , _hide , _inline ] ;
94+ const middlewareProps = [ flip , shift , autoPlacement , hide , inline ] ;
95+
96+ middlewareFunctions . forEach ( ( func , index ) => {
97+ const isMiddlewareEnabled = middlewareProps [ index ] ;
98+
99+ if ( isMiddlewareEnabled ) {
100+ const middlewareConfig =
101+ isMiddlewareEnabled === true ? undefined : isMiddlewareEnabled ;
102+ middleware . push ( func ( middlewareConfig ) ) ;
103+ }
104+ } ) ;
86105
87106 computePosition (
88107 context . inputRef . value as ReferenceElement ,
89108 context . listboxRef . value as HTMLElement ,
90109 {
91- placement : placement ,
92- middleware : middleware ,
110+ placement,
111+ middleware,
112+ platform,
93113 } ,
94- ) . then ( ( { x, y } ) => {
114+ ) . then ( ( resolvedData ) => {
115+ const { x, y } = resolvedData ;
95116 if ( context . listboxRef . value ) {
96117 Object . assign ( context . listboxRef . value . style , {
97118 left : `${ x } px` ,
98119 top : `${ y } px` ,
120+ transform,
99121 } ) ;
100122 }
123+
124+ // user-provided resolved code
125+ if ( onPositionComputed ) {
126+ onPositionComputed ( resolvedData ) ;
127+ }
101128 } ) ;
102129 }
103130
@@ -109,10 +136,10 @@ export const ComboboxListbox = component$(
109136 context . listboxRef . value ,
110137 updatePosition ,
111138 {
112- ancestorScroll : ancestorScroll ,
113- ancestorResize : ancestorResize ,
114- elementResize : elementResize ,
115- animationFrame : animationFrame ,
139+ ancestorScroll,
140+ ancestorResize,
141+ elementResize,
142+ animationFrame,
116143 } ,
117144 ) ;
118145
@@ -128,9 +155,7 @@ export const ComboboxListbox = component$(
128155 id = { listboxId }
129156 ref = { context . listboxRef }
130157 aria-label = {
131- context . labelRef . value
132- ? context . labelRef . value ?. innerText
133- : context . inputRef . value ?. value
158+ context . labelRef . value ? context . labelRef . value ?. innerText : 'Suggestions'
134159 }
135160 role = "listbox"
136161 hidden = { ! context . isListboxOpenSig . value }
0 commit comments