UNPKG

react-accessible-headings

Version:

Accessible dynamic H1, H2, that will adjust for accessibility reasons! WCAG ARIA

79 lines 3.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkHeadingLevels = exports.useHClassName = exports.useLevel = exports.H = exports.Level = exports.HeadingsContext = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); exports.HeadingsContext = (0, react_1.createContext)({ level: 1 }); function Level({ children, value, hClassName }) { const context = (0, react_1.useContext)(exports.HeadingsContext); const level = levelRange(value !== undefined ? value : context.level + 1); return ((0, jsx_runtime_1.jsx)(exports.HeadingsContext.Provider, { value: { level, hClassName: hClassName || context.hClassName, }, children: children })); } exports.Level = Level; function H({ children, offset, className, ...otherProps }) { const context = (0, react_1.useContext)(exports.HeadingsContext); const proposedLevel = context.level + (offset !== undefined ? offset : 0); const level = levelRange(proposedLevel); // merge and trim unneeded spaces between classNames const mergedClassName = [context.hClassName, className] .filter(Boolean) .join(' '); setTimeout(checkHeadingLevelsDom, CHECK_AFTER_MS); // couldn't have JSX syntax, because ts throws // "Property 'children' does not exist on type 'IntrinsicAttributes'" return (0, react_1.createElement)(`h${level}`, { className: mergedClassName, ...otherProps }, children); } exports.H = H; function levelRange(level) { if (level > 0 && level <= MAXIMUM_LEVEL) { return level; } const errorMessage = `Heading level "${level}" is not valid HTML5 which only allows levels 1-${MAXIMUM_LEVEL}`; console.error(errorMessage); return Math.min(Math.max(1, level), MAXIMUM_LEVEL); } function useLevel() { const context = (0, react_1.useContext)(exports.HeadingsContext); setTimeout(checkHeadingLevelsDom, CHECK_AFTER_MS); return levelRange(context.level); } exports.useLevel = useLevel; function useHClassName() { const context = (0, react_1.useContext)(exports.HeadingsContext); return context.hClassName || ''; } exports.useHClassName = useHClassName; function checkHeadingLevelsDom() { if (typeof window === 'undefined') return; // No need to run during SSR checkHeadingLevels(Array.from(document.querySelectorAll('h1,h2,h3,h4,h5,h6')).map((elm) => parseFloat(elm.tagName.substring(1)))); } function checkHeadingLevels(headings) { const badHeadings = getBadHeadings(headings); if (badHeadings.length > 0) { const errorMessage = `WCAG accessibility issue detected: skipped heading levels ${badHeadings.map((num) => `h${num}`)}. See https://www.npmjs.com/package/react-accessible-headings#why`; console.error(errorMessage); } return badHeadings; } exports.checkHeadingLevels = checkHeadingLevels; function getBadHeadings(headings) { return headings.filter( // multiple H1s are not recommended. See docs. (heading) => heading === 1).length >= 2 || headings.some((heading, index, arr) => { // detect skipped levels const precedingHeading = arr[index - 1]; if (!precedingHeading) return false; return heading > precedingHeading + 1; }) ? headings : []; } const MAXIMUM_LEVEL = 6; const CHECK_AFTER_MS = 1; // used in setTimeout and browsers will typically clamp this to ~5ms //# sourceMappingURL=index.js.map