@@ -35,13 +35,16 @@ interface ClosePathAction {
3535
3636type Action = ToggleAction | OpenPathAction | ClosePathAction
3737
38+ type Placement = 'top' | 'bottom' | 'start' | 'end'
39+
3840/**
3941 * @ignore
4042 */
4143interface NestedMenuState {
4244 items : Items
4345 isOpen : boolean
4446 currentPath : string [ ]
47+ placement : Placement
4548}
4649
4750/**
@@ -75,6 +78,7 @@ interface NestedMenuProps {
7578 items ?: Items
7679 isOpen ?: boolean
7780 defaultOpenPath ?: string [ ]
81+ placement ?: Placement
7882}
7983
8084// interface HitAreaProps {
@@ -90,11 +94,13 @@ export const useNestedMenu = ({
9094 items = [ ] ,
9195 isOpen = false ,
9296 defaultOpenPath = [ ] ,
97+ placement = 'end' ,
9398} : NestedMenuProps ) => {
9499 const [ state , dispatch ] = React . useReducer ( reducer , {
95100 items,
96101 isOpen,
97102 currentPath : defaultOpenPath ,
103+ placement,
98104 } )
99105
100106 const globalClickHandler = React . useCallback (
@@ -183,25 +189,61 @@ export const useNestedMenu = ({
183189
184190 const getMenuOffsetStyles = ( currentItem ?: MenuItem ) => {
185191 const item = currentItem ? itemRefs . current [ currentItem . id ] : null
186- const level =
187- state . currentPath . length === 0
188- ? 0 // root menu
189- : currentItem && state . currentPath . includes ( currentItem . id )
190- ? 1 // submenu, indent
191- : 0
192192 const button = toggleButtonRef . current as HTMLElement
193193
194194 const dir = getDirection ( )
195- const direction = dir === 'ltr' ? 'left' : 'right'
196- const rootX =
195+ const rootXEnd =
197196 dir === 'ltr'
198197 ? button . getBoundingClientRect ( ) . right
199198 : window . innerWidth - button . getBoundingClientRect ( ) . left
200199
200+ let vertical : string = 'top'
201+ let horizontal : string = dir === 'ltr' ? 'left' : 'right'
202+ let verticalValue = item ? 0 : button . getBoundingClientRect ( ) . top
203+ let horizontalValue = item ? item . getBoundingClientRect ( ) . width : rootXEnd
204+
205+ if ( dir === 'ltr' ) {
206+ if ( placement === 'top' ) {
207+ vertical = item ? 'top' : 'bottom'
208+ verticalValue = item ? 0 : window . innerHeight - button . getBoundingClientRect ( ) . top
209+ horizontalValue = item
210+ ? item . getBoundingClientRect ( ) . width
211+ : button . getBoundingClientRect ( ) . left
212+ } else if ( placement === 'bottom' ) {
213+ verticalValue = item ? 0 : button . getBoundingClientRect ( ) . bottom
214+ horizontalValue = item
215+ ? item . getBoundingClientRect ( ) . width
216+ : button . getBoundingClientRect ( ) . left
217+ } else if ( placement === 'start' ) {
218+ horizontal = item ? 'left' : 'right'
219+ horizontalValue = item
220+ ? item . getBoundingClientRect ( ) . width
221+ : window . innerWidth - button . getBoundingClientRect ( ) . left
222+ }
223+ } else {
224+ if ( placement === 'top' ) {
225+ vertical = item ? 'top' : 'bottom'
226+ horizontal = 'right'
227+ verticalValue = item ? 0 : window . innerHeight - button . getBoundingClientRect ( ) . top
228+ horizontalValue = item
229+ ? item . getBoundingClientRect ( ) . width
230+ : window . innerWidth - button . getBoundingClientRect ( ) . right
231+ } else if ( placement === 'bottom' ) {
232+ verticalValue = item ? 0 : button . getBoundingClientRect ( ) . bottom
233+ horizontalValue = item
234+ ? item . getBoundingClientRect ( ) . width
235+ : window . innerWidth - button . getBoundingClientRect ( ) . right
236+ } else if ( placement === 'start' ) {
237+ horizontal = item ? 'right' : 'left'
238+ horizontalValue = item
239+ ? item . getBoundingClientRect ( ) . width
240+ : button . getBoundingClientRect ( ) . right
241+ }
242+ }
243+
201244 return {
202- top : item ? 0 : button . getBoundingClientRect ( ) . top ,
203- [ direction ] : item ? button . getBoundingClientRect ( ) . width * level : rootX ,
204- width : button . getBoundingClientRect ( ) . width ,
245+ [ vertical ] : verticalValue ,
246+ [ horizontal ] : horizontalValue ,
205247 }
206248 }
207249
0 commit comments