optimizely-oui
Version:
Optimizely's Component Library.
194 lines (171 loc) • 6.73 kB
JavaScript
import React from "react";
import PropTypes from "prop-types";
import Icon from "react-oui-icons";
import DismissButton from "./DismissButton";
import classNames from "classnames";
import { FILL_COLOR_MAP_LIGHT } from "../../utils/accessibility";
const LIGHT_BACKGROUND_STYLES = ["tertiary"];
// Light backgrounds require a dark font and dismiss Icon color.
const getStylingInfo = (style, backgroundColor) =>
LIGHT_BACKGROUND_STYLES.includes(style) || backgroundColor
? { fontClass: "oui-token--font-dark", dismissFillColor: "black" }
: { fontClass: "oui-token--font-light", dismissFillColor: "white" };
/**
* Token to be used to make token lists.
* @param {Object} props - Properties passed to component
* @returns {ReactElement}
*/
const Token = ({
className,
description,
dragHandleProps,
backgroundColor,
hasSnugWrap,
hasWrap,
isDismissible,
isDraggable,
isFullWidth,
name,
onDismiss,
order,
style,
showWell,
testSection,
usesDragHandle,
...props
}) => {
const tokenContainerClasses = classNames({
"oui-token-wrap": hasWrap && !hasSnugWrap,
"oui-token-wrap--snug": hasSnugWrap,
"oui-token-wrap--well": showWell,
"oui-token--full-width": isFullWidth,
}, className);
const tokenClasses = classNames({
"oui-token": true,
[`oui-token--${style}`]: style,
"flex-align--center": !description,
});
const tokenToolsClasses = classNames({
"oui-token-tool": isDraggable || order,
"cursor--grab": isDraggable,
});
const { fontClass, dismissFillColor } = getStylingInfo(style, backgroundColor);
// ensure valid backgroundColor name
// (in the case that propType errors are ignored)
const tokenFillColor =
backgroundColor && Object.keys(FILL_COLOR_MAP_LIGHT).includes(backgroundColor)
? FILL_COLOR_MAP_LIGHT[backgroundColor]
: null;
if (usesDragHandle) {
return (
/* eslint-disable react/jsx-boolean-value */
<div data-oui-component={true} className={tokenContainerClasses} data-test-section={testSection} {...props}>
<div className={tokenClasses} style={{ backgroundColor: tokenFillColor }}>
<div className="flex flex-align--center">
<div className={tokenToolsClasses} data-token-handle>
{order && <span className="oui-token__number push--right">{order}</span>}
{isDraggable && (
<div
className="oui-icon oui-token__move push--right oui-token__move--drag-handle"
{...dragHandleProps}
>
<Icon name="hamburger" fill="#ffffff" />
</div>
)}
</div>
<div className={fontClass}>
{name}
{description && <div className="oui-token__description">{description}</div>}
</div>
</div>
{isDismissible && onDismiss && (
<DismissButton
onClick={onDismiss}
fill={dismissFillColor}
testSection={testSection}
backgroundColor={backgroundColor}
/>
)}
</div>
</div>
/* eslint-enable */
);
}
return (
/* eslint-disable react/jsx-boolean-value */
<div data-oui-component={true} className={tokenContainerClasses} data-test-section={testSection} {...props}>
<div className={tokenToolsClasses} data-token-handle>
{order && <span className="oui-token__number push--right">{order}</span>}
{isDraggable && (
<div className="oui-icon oui-token__move">
<Icon name="ellipsis" fill="#c7c7c7" />
</div>
)}
</div>
<div className={tokenClasses} style={{ backgroundColor: tokenFillColor }}>
<div className={fontClass}>
{name}
{description && <div className="oui-token__description">{description}</div>}
</div>
{isDismissible && onDismiss && (
<DismissButton onClick={onDismiss} fill={dismissFillColor} testSection={testSection} />
)}
</div>
</div>
/* eslint-enable */
);
};
Token.propTypes = {
/**
* Color to use for the background of the token
*/
backgroundColor: PropTypes.oneOf(["aqua", "yellow", "blue", "green", "orange", "pink", "red", "magenta", "purple"]),
/** CSS class names. */
className: PropTypes.string,
/** Description explaining the token */
description: PropTypes.string,
/**
* Set of props provided by react-beautiful-dnd to configure
* this token's drag handle
*/
dragHandleProps: PropTypes.object,
/** Whether or not the token should have a tighter wrap */
hasSnugWrap: PropTypes.bool,
/** Whether or not the token should have a wrap */
hasWrap: PropTypes.bool,
/**
* Determines if token has dismissible feature or not. If true, `onDismiss`
* is required.
*/
isDismissible: PropTypes.bool,
/** Shows an icon indicating that the token is draggable */
isDraggable: PropTypes.bool,
/** Makes the component full width of container */
isFullWidth: PropTypes.bool,
/** Name label on token */
name: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
/**
* Function to call that dismisses the token. Required if the token is
* dismissible.
*/
onDismiss: PropTypes.func,
/** Show a number indicating the token's order */
order: PropTypes.number,
/** Whether or not a well is presented around the token. */
showWell: PropTypes.bool,
/** Determines style of token depending on priority level or error */
style: PropTypes.oneOf(["primary", "secondary", "tertiary", "error"]),
/** Hook for automated JavaScript tests */
testSection: PropTypes.string,
/** Used to switch drag handle */
usesDragHandle: PropTypes.bool,
};
Token.defaultProps = {
dragHandleProps: {},
hasWrap: true,
isDismissible: false,
style: "secondary",
showWell: true,
usesDragHandle: true,
};
export default Token;