optimizely-oui
Version:
Optimizely's Component Library.
145 lines (130 loc) • 4.49 kB
JavaScript
import React from "react";
import PropTypes from "prop-types";
import classNames from "classnames";
class Item extends React.Component {
constructor(props) {
super(props);
this._handleOnKeyDown = this._handleOnKeyDown.bind(this);
}
ref = React.createRef();
componentDidUpdate() {
if (this.props.hasFauxFocus) {
this.ref.current.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
}
_handleOnKeyDown(event) {
if (event && event.keyCode === 32 && event.target === this._itemWithOnClick) {
// Space key was pressed on the item, not a child of the item.
// Run the `onClick` and prevent the page from scrolling.
event.preventDefault();
this.props.onClick();
}
}
render() {
let item;
const {
children,
className,
gutters,
hasFauxFocus,
href,
hrefTarget,
hrefTitle,
isDisabled,
onClick,
onMouseDown,
testSection,
...props
} = this.props;
const commonClasses = classNames({
"oui-block-list__item": true,
"oui-block-list__item--has-focus": hasFauxFocus,
"hard--sides": gutters === "tight",
});
if (isDisabled) {
item = (
<div className={`${commonClasses} pointer-events--none background--faint muted`}>
{children}
</div>
);
} else if (onClick) {
// The element is rendered as a `div` instead of a `button` because the
// user may want to pass in a `button` within `children`.
// `tabIndex`, `role`, and `onKeyDown` are provided to make the `div`
// behave like a button: https://mzl.la/1mRMvQj
item = (
<div
className={`${commonClasses} link oui-block-list__link`}
onClick={onClick}
onKeyDown={this._handleOnKeyDown}
tabIndex="0"
role="button"
ref={el => {
this._itemWithOnClick = el;
}}
>
{children}
</div>
);
} else if (href) {
item = (
<a
href={href}
className={`${commonClasses} oui-block-list__link display--block`}
target={hrefTarget}
title={hrefTitle}
rel={hrefTarget === "_blank" && "noopener noreferrer"}
>
{children}
</a>
);
} else {
item = (
<div
className={commonClasses}
onMouseDown={onMouseDown}
{...(testSection && { "data-test-section": testSection + "-item" })}
>
{children}
</div>
);
}
return (
<li ref={this.ref} style={{ wordBreak: "break-word" }} className={className} data-test-section={testSection} {...props}>
{item}
</li>
);
}
}
Item.propTypes = {
/** String or JSX that appears within the component */
children: PropTypes.node.isRequired,
/** CSS class names. */
className: PropTypes.string,
/** Determines level of padding of item */
gutters: PropTypes.oneOf(["loose", "tight"]),
/** Boolean to set faux focus of a list item */
hasFauxFocus: PropTypes.bool,
/** URL to navigate to when clicking on the item */
href: PropTypes.string,
/** Target that the link, if provided, should open in */
hrefTarget: PropTypes.oneOf(["_self", "_blank"]),
/** Sets the `title` attribute on an `href` */
hrefTitle: PropTypes.string,
/** Disable the item */
isDisabled: PropTypes.bool,
/** Function that is run when clicking on the item */
onClick: PropTypes.func,
/** Function that is run when mouse-down event is fired on the item */
onMouseDown: PropTypes.func,
/** Hook for automated JavaScript tests */
testSection: PropTypes.string,
};
Item.defaultProps = {
gutters: "loose",
};
Item.displayName = "BlockList.Item";
export default Item;