Skip to content

Commit a1a81bc

Browse files
committed
Add placement prop and change positioning behavior
1 parent 61f2a3f commit a1a81bc

File tree

1 file changed

+53
-11
lines changed

1 file changed

+53
-11
lines changed

src/react-headless-nested-menu.tsx

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ interface ClosePathAction {
3535

3636
type Action = ToggleAction | OpenPathAction | ClosePathAction
3737

38+
type Placement = 'top' | 'bottom' | 'start' | 'end'
39+
3840
/**
3941
* @ignore
4042
*/
4143
interface 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

Comments
 (0)