terra-list
Version:
The Terra List is a structural component to arrange content within list/listitems.
128 lines (118 loc) • 3.94 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import classNamesBind from 'classnames/bind';
import ThemeContext from 'terra-theme-context';
import ListUtils from './ListUtils';
import styles from './ListSubsectionHeader.module.scss';
const cx = classNamesBind.bind(styles);
const propTypes = {
/**
* @private Whether or not the subsection is collapsed.
*/
isCollapsed: PropTypes.bool,
/**
* @private Whether or not the subsection can be collapsed.
*/
isCollapsible: PropTypes.bool,
/**
* Optionally sets the heading level. One of `2`, `3`, `4`, `5`, `6`.
*/
level: PropTypes.oneOf([2, 3, 4, 5, 6]),
/**
* @private The associated metaData to be provided in the onSelect callback.
*/
// eslint-disable-next-line react/forbid-prop-types
metaData: PropTypes.object,
/**
* @private Function callback for when the appropriate click or key action is performed.
* Callback contains the javascript evnt and prop metadata, e.g. onSelect(event, metaData)
*/
onSelect: PropTypes.func,
/**
* Function callback passthrough for the ref of the section li.
*/
refCallback: PropTypes.func,
/**
* Title text to be placed within the subsection header.
*/
title: PropTypes.string.isRequired,
/**
* @private Callback function not intended for use with this API, but if set pass it through to the element regardless.
*/
onBlur: PropTypes.func,
/**
* @private Callback function not intended for use with this API, but if set pass it through to the element regardless.
*/
onClick: PropTypes.func,
/**
* @private Callback function not intended for use with this API, but if set pass it through to the element regardless.
*/
onKeyDown: PropTypes.func,
/**
* @private Callback function not intended for use with this API, but if set pass it through to the element regardless.
*/
onMouseDown: PropTypes.func,
};
const defaultProps = {
isCollapsed: false,
isCollapsible: false,
level: 2,
};
const ListSubsectionHeader = ({
isCollapsed,
isCollapsible,
level,
metaData,
onBlur,
onClick,
onKeyDown,
onMouseDown,
onSelect,
refCallback,
title,
...customProps
}) => {
const theme = React.useContext(ThemeContext);
const sectionHeaderClassNames = classNames(
cx(
'subsection-header',
{ 'is-collapsible': isCollapsible },
),
customProps.className,
);
const attrSpread = {};
const Element = `h${level}`;
const titleElement = <div className={cx('fill')}>{title}</div>;
let accordionIcon;
if (isCollapsible) {
accordionIcon = (
<div className={cx('start')}>
<span className={cx(['accordion-icon', { 'is-open': !isCollapsed }])} />
</div>
);
attrSpread.onClick = ListUtils.wrappedOnClickForItem(onClick, onSelect, metaData);
attrSpread.onKeyDown = ListUtils.wrappedOnKeyDownForItem(onKeyDown, onSelect, metaData);
attrSpread.tabIndex = '0';
attrSpread.role = 'button';
attrSpread['aria-expanded'] = !isCollapsed;
attrSpread['data-item-show-focus'] = 'true';
attrSpread.onBlur = ListUtils.wrappedEventCallback(onBlur, event => event.currentTarget.setAttribute('data-item-show-focus', 'true'));
attrSpread.onMouseDown = ListUtils.wrappedEventCallback(onMouseDown, event => event.currentTarget.setAttribute('data-item-show-focus', 'false'));
}
/* eslint-disable-next-line no-param-reassign */
delete customProps?.isTabFocusDisabled;
return (
<li {...customProps} className={cx('list-item', theme.className)} ref={refCallback}>
<Element className={cx('title')}>
<div {...attrSpread} className={sectionHeaderClassNames}>
{accordionIcon}
{titleElement}
</div>
</Element>
</li>
);
};
ListSubsectionHeader.propTypes = propTypes;
ListSubsectionHeader.defaultProps = defaultProps;
export default ListSubsectionHeader;