All files / molecule/accordion/src AccordionItemPanel.js

100% Statements 10/10
84% Branches 21/25
100% Functions 2/2
100% Lines 10/10

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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122                            1x                                 38x           38x 38x 38x 38x         38x                                                                             38x                     1x   1x                                                
import {forwardRef} from 'react'
import {isFragment} from 'react-is'
 
import cx from 'classnames'
import PropTypes from 'prop-types'
 
import {combineProps, inject} from '@s-ui/react-primitive-injector'
import Poly from '@s-ui/react-primitive-polymorphic-element'
 
import {useAccordionContext} from './context/index.js'
import useMeasure from './hook/useMeasure.js'
import AccordionItemPanelDefaultChildren from './AccordionItemPanelDefaultChildren.js'
import {BASE_CLASS_ELEMENT, BASE_CLASS_ITEM_PANEL, BASE_CLASS_ITEM_PANEL_CONTENT} from './settings.js'
 
const AccordionItemPanel = forwardRef(
  (
    {
      as,
      id,
      headerId,
      content,
      children = <AccordionItemPanelDefaultChildren />,
      isExpanded,
      maxHeight: maxHeightProp,
      value,
      animationDuration: animationDurationProp,
      disabled,
      ...props
    },
    forwardedRef
  ) => {
    const [contentRef, {height}] = useMeasure()
 
    const {
      values,
      animationDuration: animationDurationContext,
      maxHeight: maxHeightContext
    } = useAccordionContext({isExpanded, value})
    const maxHeight = maxHeightProp !== undefined ? maxHeightProp : maxHeightContext
    const animationDuration = animationDurationProp || animationDurationContext
    const accordionItemPanelClassName = cx(
      BASE_CLASS_ITEM_PANEL,
      BASE_CLASS_ELEMENT,
      `${BASE_CLASS_ITEM_PANEL}--${values.includes(value) ? 'expanded' : 'collapsed'}`
    )
    return (
      <div
        id={id}
        role="region"
        ref={forwardedRef}
        aria-labelledby={headerId}
        className={accordionItemPanelClassName}
        aria-disabled={disabled}
        style={{
          overflowY: height > maxHeight && maxHeight !== 0 ? 'scroll' : 'hidden',
          transition: `max-height ${animationDuration}ms ${
            values.includes(value) ? 'ease-out' : 'ease-in'
          }, opacity 0s linear ${values.includes(value) ? 0 : animationDuration}ms, border-top-width 0s linear ${
            values.includes(value) ? 0 : animationDuration
          }ms`,
          ...(values.includes(value) && {
            maxHeight: maxHeight === 0 ? height : maxHeight
          })
        }}
        {...props}
      >
        <Poly
          as={as}
          {...{
            ...(!isFragment && {
              className: `${BASE_CLASS_ITEM_PANEL_CONTENT}Wrapper`
            })
          }}
        >
          <div className={`${BASE_CLASS_ITEM_PANEL_CONTENT}WrapperRef`} ref={contentRef}>
            {inject(children, [
              {
                props: {
                  ...(content && {children: content}),
                  isExpanded,
                  values,
                  value,
                  disabled
                },
                proviso: () => true,
                combine: combineProps
              }
            ])}
          </div>
        </Poly>
      </div>
    )
  }
)
 
AccordionItemPanel.displayName = 'AccordionItemPanel'
 
AccordionItemPanel.propTypes = {
  /** The elementType of the wrapper **/
  as: PropTypes.elementType,
  /** The animation duration in ms **/
  animationDuration: PropTypes.number,
  /** child element **/
  children: PropTypes.node,
  /** panel inner content **/
  content: PropTypes.node,
  /** element enabled or not **/
  disabled: PropTypes.bool,
  /** unique identifier **/
  id: PropTypes.string,
  /** a required string indicating the button id controlling the panel **/
  headerId: PropTypes.string.isRequired,
  /** controlled expanded accordion item behavior */
  isExpanded: PropTypes.bool,
  /** the max height limit a panel can reach when its expanded **/
  maxHeight: PropTypes.number,
  /** the unique value of the element **/
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
}
 
export default AccordionItemPanel