Skip to content

Commit d68f5ff

Browse files
authored
TreeView: Fix scroll behavior when focus changes (#2464)
* Avoid unecessary style recalculation * Add stress test story * Only render subtree if it's expanded * Don't expand current item by default * Update controlled story * Create popular-taxis-yawn.md * Fix scroll behavior on focus * Create olive-sloths-count.md * Update src/TreeView/TreeView.tsx * Fix tests * Update snapshot
1 parent 175f3a7 commit d68f5ff

File tree

7 files changed

+23
-9
lines changed

7 files changed

+23
-9
lines changed

.changeset/olive-sloths-count.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/react": patch
3+
---
4+
5+
TreeView: Fix scroll behavior when focus changes

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"@github/combobox-nav": "^2.1.5",
8383
"@github/markdown-toolbar-element": "^2.1.0",
8484
"@github/paste-markdown": "^1.4.0",
85-
"@primer/behaviors": "^1.1.1",
85+
"@primer/behaviors": "1.3.0",
8686
"@primer/octicons-react": "^17.7.0",
8787
"@primer/primitives": "7.10.0",
8888
"@react-aria/ssr": "^3.1.0",

src/TreeView/TreeView.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ function renderWithTheme(
1515
return render(<ThemeProvider>{ui}</ThemeProvider>, options)
1616
}
1717

18+
// Mock `scrollIntoView` because it's not implemented in JSDOM
19+
Element.prototype.scrollIntoView = jest.fn()
20+
1821
describe('Markup', () => {
1922
it('uses tree role', () => {
2023
const {queryByRole} = renderWithTheme(

src/TreeView/TreeView.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,9 @@ const Item = React.forwardRef<HTMLElement, TreeViewItemProps>(
202202
trailingVisualId
203203
}}
204204
>
205+
{/* @ts-ignore Box doesn't have type support for `ref` used in combination with `as` */}
205206
<Box
206207
as="li"
207-
// @ts-ignore Box doesn't have type support for `ref` used in combination with `as`
208208
ref={ref}
209209
tabIndex={0}
210210
id={itemId}
@@ -215,6 +215,10 @@ const Item = React.forwardRef<HTMLElement, TreeViewItemProps>(
215215
aria-expanded={isSubTreeEmpty ? undefined : isExpanded}
216216
aria-current={isCurrentItem ? 'true' : undefined}
217217
onKeyDown={handleKeyDown}
218+
onFocus={event => {
219+
// Scroll the first child into view when the item receives focus
220+
event.currentTarget.firstElementChild?.scrollIntoView({block: 'nearest', inline: 'nearest'})
221+
}}
218222
sx={{
219223
outline: 'none',
220224
'&:focus-visible > div': {

src/TreeView/useRovingTabIndex.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export function useRovingTabIndex({containerRef}: {containerRef: React.RefObject
66
useFocusZone({
77
containerRef,
88
bindKeys: FocusKeys.ArrowVertical | FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
9+
preventScroll: true,
910
getNextFocusable: (direction, from, event) => {
1011
if (!(from instanceof HTMLElement)) return
1112

src/__tests__/hooks/useAnchoredPosition.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ it('should should return a position', () => {
2323
expect(cb).toHaveBeenCalledTimes(2)
2424
expect(cb.mock.calls[1][0]['position']).toMatchInlineSnapshot(`
2525
{
26+
"anchorAlign": "start",
2627
"anchorSide": "outside-bottom",
2728
"left": 0,
2829
"top": 4,

0 commit comments

Comments
 (0)