Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import { useCallback, useEffect, useRef } from 'react';
/**
* React hook for managing element refs with automatic event listener cleanup.
* Use this for vscode-elements web components that emit custom events, or for
* native DOM events that need to be attached outside React's synthetic event
* system (e.g. to control propagation order).
*
* @example
* ```tsx
* function MyComponent() {
* const [selectedIndex, setSelectedIndex] = useState(0);
*
* const tabsRef = useVscodeElementRef<VscodeTabs, { selectedIndex: number }>(
* 'vsc-tabs-select',
* (element, event) => setSelectedIndex(event.detail.selectedIndex)
* );
*
* return <vscode-tabs ref={tabsRef}>...</vscode-tabs>;
* }
* ```
*
* @param eventName The event name to listen for.
* @param onEvent Callback invoked when the event fires.
* @returns A ref callback to pass to the element's ref prop.
*/
export function useVscodeElementRef<E extends HTMLElement, V = any>(
eventName: string,
onEvent: (element: E, event: CustomEvent<V>) => void
): (element: E | null) => void {
const elementRef = useRef<E | null>(null);
const handlerRef = useRef(onEvent);
// Keep handler ref up to date
useEffect(() => {
handlerRef.current = onEvent;
}, [onEvent]);
// The listener registered on the current element. Kept in a ref so detaching
// removes the exact function that was added — a listener created fresh per
// callback invocation would never match and silently leak.
const listenerRef = useRef<((event: Event) => void) | null>(null);
const refCallback = useCallback((element: E | null) => {
// Cleanup previous element
if (elementRef.current && listenerRef.current) {
elementRef.current.removeEventListener(eventName, listenerRef.current);
listenerRef.current = null;
}
elementRef.current = element;
// Setup new element
if (element) {
const listener = (event: Event) => {
if (elementRef.current) {
handlerRef.current(elementRef.current, event as CustomEvent<V>);
}
};
listenerRef.current = listener;
element.addEventListener(eventName, listener);
}
}, [eventName]);
return refCallback;
}
|