( props: AriaDisclosureProps, state: DisclosureState, ref: RefObject<HTMLElement | null> )
| 46 | * @param ref - A ref for the disclosure panel. |
| 47 | */ |
| 48 | export function useDisclosure( |
| 49 | props: AriaDisclosureProps, |
| 50 | state: DisclosureState, |
| 51 | ref: RefObject<HTMLElement | null> |
| 52 | ): DisclosureAria { |
| 53 | let {isDisabled} = props; |
| 54 | let triggerId = useId(); |
| 55 | let panelId = useId(); |
| 56 | let isSSR = useIsSSR(); |
| 57 | |
| 58 | let raf = useRef<number | null>(null); |
| 59 | |
| 60 | let handleBeforeMatch = useCallback(() => { |
| 61 | // Wait a frame to revert browser's removal of hidden attribute |
| 62 | raf.current = requestAnimationFrame(() => { |
| 63 | if (ref.current) { |
| 64 | ref.current.setAttribute('hidden', 'until-found'); |
| 65 | } |
| 66 | }); |
| 67 | // Force sync state update |
| 68 | flushSync(() => { |
| 69 | state.toggle(); |
| 70 | }); |
| 71 | }, [ref, state]); |
| 72 | |
| 73 | // @ts-ignore https://github.com/facebook/react/pull/24741 |
| 74 | useEvent(ref, 'beforematch', handleBeforeMatch); |
| 75 | |
| 76 | let isExpandedRef = useRef<boolean | null>(null); |
| 77 | useLayoutEffect(() => { |
| 78 | // Cancel any pending RAF to prevent stale updates |
| 79 | if (raf.current) { |
| 80 | cancelAnimationFrame(raf.current); |
| 81 | } |
| 82 | if (ref.current && !isSSR) { |
| 83 | let panel = ref.current; |
| 84 | |
| 85 | if (isExpandedRef.current == null || typeof panel.getAnimations !== 'function') { |
| 86 | // On initial render (and in tests), set attributes without animation. |
| 87 | if (state.isExpanded) { |
| 88 | panel.removeAttribute('hidden'); |
| 89 | panel.style.setProperty('--disclosure-panel-width', 'auto'); |
| 90 | panel.style.setProperty('--disclosure-panel-height', 'auto'); |
| 91 | } else { |
| 92 | panel.setAttribute('hidden', 'until-found'); |
| 93 | panel.style.setProperty('--disclosure-panel-width', '0px'); |
| 94 | panel.style.setProperty('--disclosure-panel-height', '0px'); |
| 95 | } |
| 96 | } else if (state.isExpanded !== isExpandedRef.current) { |
| 97 | if (state.isExpanded) { |
| 98 | panel.removeAttribute('hidden'); |
| 99 | |
| 100 | // Set the width and height as pixels so they can be animated. |
| 101 | panel.style.setProperty('--disclosure-panel-width', panel.scrollWidth + 'px'); |
| 102 | panel.style.setProperty('--disclosure-panel-height', panel.scrollHeight + 'px'); |
| 103 | |
| 104 | Promise.all(panel.getAnimations().map(a => a.finished)) |
| 105 | .then(() => { |
no test coverage detected