From 56e21014e0e1e0b3c92e6ca3a64f75197cb2a5cc Mon Sep 17 00:00:00 2001 From: Viktor Yakubiv Date: Fri, 18 Sep 2020 13:58:57 +0300 Subject: [PATCH 1/3] Add Section and SectionHeading --- src/content/context.js | 11 +++++++++ src/content/heading.jsx | 37 ++++++++++++++++++++++++++++++ src/content/index.js | 2 ++ src/content/section.jsx | 50 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 src/content/context.js create mode 100644 src/content/heading.jsx create mode 100644 src/content/index.js create mode 100644 src/content/section.jsx diff --git a/src/content/context.js b/src/content/context.js new file mode 100644 index 00000000..f1815684 --- /dev/null +++ b/src/content/context.js @@ -0,0 +1,11 @@ +import { createContext } from 'react' + +const defaultContext = { + level: 1, + parentId: null, +} + +const SectionContext = createContext(defaultContext) + +export default SectionContext +export { defaultContext } diff --git a/src/content/heading.jsx b/src/content/heading.jsx new file mode 100644 index 00000000..57d8bbd0 --- /dev/null +++ b/src/content/heading.jsx @@ -0,0 +1,37 @@ +import React, { forwardRef, useContext } from 'react' + +import { Heading } from '../elements' +import Context from './context' + +const SectionHeading = forwardRef( + ({ children, id: forceId, level: forceLevel, ...passProps }, ref) => { + const parentContext = useContext(Context) + const level = forceLevel ?? parentContext.level ?? 1 + const id = forceId ?? parentContext.headingId + + return ( + + {children} + + ) + } +) + +SectionHeading.propTypes = { + /** + * A local level to force the current heading heading level over the one + * passed via the context from the parent sectioning element. + * + * If `null` or no value (`undefined`) is passed, the prop is ignored. + * Otherwise, it forces the current Heading to use the passed level. + * + * In contrast to the forced `level` in the Section, this one impacts + * only the current heading and will not have effect on nested sections. + * + * The prop is created to provide the full control over the component if + * the automatic system does not work. However, we recommend avoid using it. + */ + level: PropTypes.oneOf([undefined, null, 1, 2, 3, 4, 5, 6]), +} + +export default SectionHeading diff --git a/src/content/index.js b/src/content/index.js new file mode 100644 index 00000000..a5eb7468 --- /dev/null +++ b/src/content/index.js @@ -0,0 +1,2 @@ +export Section from './section' +export Heading from './heading' diff --git a/src/content/section.jsx b/src/content/section.jsx new file mode 100644 index 00000000..5316b96f --- /dev/null +++ b/src/content/section.jsx @@ -0,0 +1,50 @@ +import React, { forwardRef, useContext } from 'react' +import PropTypes from 'prop-types' + +import Context from './context' + +const HEADING_SUFFIX = 'title' + +const Section = forwardRef( + ( + { children, id, level: forceLevel, tag: Tag = 'section', ...restProps }, + ref + ) => { + const parentContext = useContext(Context) + const level = forceLevel ?? parentContext.level + 1 + const currentContext = { + level, + parentId: id, + } + + const ariaProps = { + 'aria-labelledby': `${id}-${HEADING_SUFFIX}`, + } + + return ( + + {children} + + ) + } +) + +Section.propTypes = { + /** + * A section level to force the current section heading level over the one + * passed via the context. + * + * If `null` or no value (`undefined`) is passed, the prop is ignored. + * Otherwise, it forces descendent Heading to use the passed level. + * + * Be aware, forcing the section level impacts not only the current section + * heading but all descendent sections too. + * + * The prop is created to provide the full control over the component if + * the automatic system does not work. However, we recommend avoid using it. + */ + level: PropTypes.oneOf([undefined, null, 1, 2, 3, 4, 5, 6]), +} + +export default Section +export { HEADING_SUFFIX } From c02f0a243868ade222b75dbfb9fb80ac9930db32 Mon Sep 17 00:00:00 2001 From: Viktor Yakubiv Date: Fri, 18 Sep 2020 14:08:37 +0300 Subject: [PATCH 2/3] Fix headingId passing --- src/content/section.jsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/content/section.jsx b/src/content/section.jsx index 5316b96f..0d28ea37 100644 --- a/src/content/section.jsx +++ b/src/content/section.jsx @@ -3,22 +3,24 @@ import PropTypes from 'prop-types' import Context from './context' -const HEADING_SUFFIX = 'title' - const Section = forwardRef( ( { children, id, level: forceLevel, tag: Tag = 'section', ...restProps }, ref ) => { const parentContext = useContext(Context) + const level = forceLevel ?? parentContext.level + 1 - const currentContext = { - level, - parentId: id, - } + const headingId = `${id}-title` const ariaProps = { - 'aria-labelledby': `${id}-${HEADING_SUFFIX}`, + 'aria-labelledby': headingId, + } + + const currentContext = { + level, + id, + headingId, } return ( @@ -47,4 +49,3 @@ Section.propTypes = { } export default Section -export { HEADING_SUFFIX } From b97895b70f6b65fd9d81267390d14fc28de2147f Mon Sep 17 00:00:00 2001 From: Viktor Yakubiv Date: Thu, 3 Feb 2022 14:45:37 +0200 Subject: [PATCH 3/3] Fix prop-types usage --- src/content/heading.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/content/heading.jsx b/src/content/heading.jsx index 57d8bbd0..d6807c75 100644 --- a/src/content/heading.jsx +++ b/src/content/heading.jsx @@ -1,4 +1,5 @@ import React, { forwardRef, useContext } from 'react' +import PropTypes from 'prop-types' import { Heading } from '../elements' import Context from './context'