vcc-ui
Version:
A React library for building user interfaces at Volvo Cars
58 lines (56 loc) • 1.92 kB
JavaScript
import { useEffect, useLayoutEffect, useState } from 'react';
const useUniversalLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
let serverHandoffComplete = false;
let id = 0;
function genId(prefix) {
id++;
return `${prefix}-${id}`;
}
/**
* useId
*
* Autogenerate IDs to facilitate WAI-ARIA and server rendering.
*
* Note: The returned ID will initially be `null` and will update after a
* component mounts. Users may need to supply their own ID if they need
* consistent values for SSR.
*/
export function useId(prefix, idFromProps) {
/*
* If this instance isn't part of the initial render, we don't have to do the
* double render/patch-up dance. We can just generate the ID and return it.
*/
const initialId = idFromProps || (serverHandoffComplete ? genId(prefix) : null);
const [id, setId] = useState(initialId);
useUniversalLayoutEffect(() => {
if (id === null) {
/*
* Patch the ID after render. We do this in `useLayoutEffect` to avoid any
* rendering flicker, though it'll make the first render slower (unlikely
* to matter, but you're welcome to measure your app and let us know if
* it's a problem).
*/
setId(genId(prefix));
}
}, []);
useEffect(() => {
if (serverHandoffComplete === false) {
/*
* Flag all future uses of `useId` to skip the update dance. This is in
* `useEffect` because it goes after `useLayoutEffect`, ensuring we don't
* accidentally bail out of the patch-up dance prematurely.
*/
serverHandoffComplete = true;
}
}, []);
return id != null ? String(id) : undefined;
}
export function makeId(rootId, part) {
return rootId != null ? `${rootId}--${part}` : undefined;
}
/**
* Make list of ids for aria attributes.
*/
export function makeIdList(ids) {
return ids.filter(id => typeof id === 'string').join(' ').trim();
}