All files / molecule/accordion/src AccordionItemPanel.js

100% Statements 9/9
82.6% Branches 19/23
100% Functions 2/2
100% Lines 9/9

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                            1x                               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
    },
    forwardedRef
  ) => {
    const [contentRef, {height}] = useMeasure()
 
    const {
      values,
      animationDuration: animationDurationContext,
      maxHeight: maxHeightContext
    } = useAccordionContext({isExpanded, value})
    const maxHeight = maxHeightProp !== undefined ? maxHeightProp : maxHeightContext
    const animationDuration = animationDurationProp || animationDurationContext
    return (
      <div
        id={id}
        ref={forwardedRef}
        role="region"
        className={cx(BASE_CLASS_ITEM_PANEL, BASE_CLASS_ELEMENT)}
        aria-expanded={values.includes(value)}
        aria-labelledby={headerId}
        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
          })
        }}
      >
        <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