MCPcopy Create free account
hub / github.com/primer/react / SubTree

Function SubTree

packages/react/src/TreeView/TreeView.tsx:547–653  ·  view source on GitHub ↗
({count, state, children})

Source from the content-addressed store, hash-verified

545}
546
547const SubTree: React.FC<TreeViewSubTreeProps> = ({count, state, children}) => {
548 const {announceUpdate} = React.useContext(RootContext)
549 const {itemId, isExpanded, isSubTreeEmpty, setIsSubTreeEmpty} = React.useContext(ItemContext)
550 const loadingItemRef = React.useRef<HTMLElement>(null)
551 const ref = React.useRef<HTMLElement>(null)
552 const [loadingFocused, setLoadingFocused] = React.useState(false)
553 const previousState = usePreviousValue(state)
554 const {safeSetTimeout} = useSafeTimeout()
555
556 React.useEffect(() => {
557 // If `state` is undefined, we're working in a synchronous context and need
558 // to detect if the sub-tree has content. If `state === 'done` then we're
559 // working in an asynchronous context and need to see if there is content
560 // that has been loaded in.
561 if (state === undefined || state === 'done') {
562 if (!isSubTreeEmpty && !children) {
563 setIsSubTreeEmpty(true)
564 } else if (isSubTreeEmpty && children) {
565 setIsSubTreeEmpty(false)
566 }
567 }
568 }, [state, isSubTreeEmpty, setIsSubTreeEmpty, children])
569
570 // Handle transition from loading to done state
571 React.useEffect(() => {
572 if (previousState === 'loading' && state === 'done') {
573 const parentElement = document.getElementById(itemId)
574 if (!parentElement) return
575
576 // Announce update to screen readers
577 const parentName = getAccessibleName(parentElement)
578
579 if (ref.current?.childElementCount) {
580 announceUpdate(`${parentName} content loaded`)
581 } else {
582 announceUpdate(`${parentName} is empty`)
583 }
584
585 // Move focus to the first child if the loading indicator
586 // was focused when the async items finished loading
587 if (loadingFocused) {
588 const firstChild = getFirstChildElement(parentElement)
589
590 if (firstChild) {
591 safeSetTimeout(() => {
592 firstChild.focus()
593 })
594 } else {
595 safeSetTimeout(() => {
596 parentElement.focus()
597 })
598 }
599
600 setLoadingFocused(false)
601 }
602 }
603 }, [loadingFocused, previousState, state, itemId, announceUpdate, ref, safeSetTimeout])
604

Callers

nothing calls this directly

Calls 4

getAccessibleNameFunction · 0.90
getFirstChildElementFunction · 0.90
usePreviousValueFunction · 0.85
useSafeTimeoutFunction · 0.85

Tested by

no test coverage detected