Skip to content

Commit 3811f44

Browse files
authored
Use focusableElementFilter with overflowItems as a dependency
1 parent 73c6db3 commit 3811f44

1 file changed

Lines changed: 25 additions & 44 deletions

File tree

packages/react/src/ActionBar/ActionBar.tsx

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -195,57 +195,38 @@ const renderMenuItem = (item: ActionBarMenuItemProps, index: number): React.Reac
195195
)
196196
}
197197

198-
export const ActionBar: React.FC<React.PropsWithChildren<ActionBarProps>> = props => {
199-
const {
200-
size = 'medium',
201-
children,
202-
'aria-label': ariaLabel,
203-
'aria-labelledby': ariaLabelledBy,
204-
flush = false,
205-
className,
206-
gap = 'condensed',
207-
} = props
208-
209-
// We derive the numeric gap from computed style so layout math stays in sync with CSS
210-
const listRef = useRef<HTMLDivElement>(null)
211-
198+
export const ActionBar: React.FC<React.PropsWithChildren<ActionBarProps>> = ({
199+
size = 'medium',
200+
children,
201+
'aria-label': ariaLabel,
202+
'aria-labelledby': ariaLabelledBy,
203+
flush = false,
204+
className,
205+
gap = 'condensed',
206+
}) => {
212207
const [childRegistry, setChildRegistry] = ActionBarItemsRegistry.useRegistryState()
213208

214-
const navRef = useRef<HTMLDivElement>(null)
215-
216-
useFocusZone({
217-
containerRef: listRef,
218-
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
219-
focusOutBehavior: 'wrap',
220-
// Ensure that hidden (overflowing) items are excluded from the elements list
221-
strict: true,
222-
// Even with strict: true, the focus zone still gets confused when there's hidden items, so we have to define our own `getNextFocusable`
223-
getNextFocusable: (direction, from) => {
224-
const items = Array.from(listRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE_ITEM_SELECTOR) ?? [])
225-
const fromIndex = from ? items.indexOf(from as HTMLElement) : -1
226-
227-
switch (direction) {
228-
case 'start':
229-
return items[0]
230-
case 'end':
231-
return items.at(-1)
232-
case 'next':
233-
return items[fromIndex + 1] ?? items[0]
234-
case 'previous':
235-
return items[fromIndex - 1] ?? items.at(-1)
236-
}
237-
},
238-
})
209+
const overflowItems = useMemo(
210+
() =>
211+
childRegistry &&
212+
Array.from(childRegistry.entries()).filter((entry): entry is [string, ChildProps] => entry[1] !== null),
213+
[childRegistry],
214+
)
239215

240-
const overflowItems =
241-
childRegistry &&
242-
Array.from(childRegistry.entries()).filter((entry): entry is [string, ChildProps] => entry[1] !== null)
216+
const {containerRef} = useFocusZone(
217+
{
218+
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
219+
focusOutBehavior: 'wrap',
220+
focusableElementFilter: element => element.matches(FOCUSABLE_ITEM_SELECTOR),
221+
},
222+
[overflowItems],
223+
)
243224

244225
return (
245226
<ActionBarContext.Provider value={{size}}>
246-
<div ref={navRef} className={clsx(className, styles.Nav)} data-flush={flush}>
227+
<div className={clsx(className, styles.Nav)} data-flush={flush}>
247228
<div
248-
ref={listRef}
229+
ref={containerRef as RefObject<HTMLDivElement>}
249230
role="toolbar"
250231
className={styles.List}
251232
aria-label={ariaLabel}

0 commit comments

Comments
 (0)