lucid-ui
Version:
A UI component library from AppNexus.
133 lines (132 loc) • 6 kB
JavaScript
import _ from 'lodash';
import React from 'react';
import PropTypes from 'react-peek/prop-types';
import MinusCircleIcon from '../Icon/MinusCircleIcon/MinusCircleIcon';
import SuccessIcon from '../Icon/SuccessIcon/SuccessIcon';
import CloseIcon from '../Icon/CloseIcon/CloseIcon';
import InfoIcon from '../Icon/InfoIcon/InfoIcon';
import WarningIcon from '../Icon/WarningIcon/WarningIcon';
import { lucidClassNames } from '../../util/style-helpers';
import { omitProps, getFirst, } from '../../util/component-types';
const { createElement } = React;
const { bool, func, string, node, oneOf } = PropTypes;
const cx = lucidClassNames.bind('&-Selection');
function defaultIcon(kind, responsiveMode) {
return kind === 'default' ? null : kind === 'container' ? null : kind ===
'success' ? (React.createElement(SuccessIcon, { className: cx('&-Icon', `&-Icon-is-${responsiveMode}`) })) : kind === 'danger' ? (React.createElement(MinusCircleIcon, { className: cx('&-Icon', `&-Icon-is-${responsiveMode}`) })) : kind === 'info' ? (React.createElement(InfoIcon, { className: cx('&-Icon', `&-Icon-is-${responsiveMode}`) })) : kind === 'warning' ? (React.createElement(WarningIcon, { className: cx('&-Icon', `&-Icon-is-${responsiveMode}`) })) : null;
}
const SelectionIcon = () => null;
SelectionIcon.peek = {
description: `
Icon that is displayed within the Selection. Any of the lucid \`*Icon\` components should work.
`,
};
SelectionIcon.displayName = 'Selection.Icon';
SelectionIcon.propName = 'Icon';
const SelectionLabel = () => null;
SelectionLabel.peek = {
description: `
Label for the Selection.
`,
};
SelectionLabel.displayName = 'Selection.Label';
SelectionLabel.propName = 'Label';
const defaultProps = {
isRemovable: true,
onRemove: _.noop,
hasBackground: false,
isBold: false,
kind: 'default',
responsiveMode: 'large',
};
const Selection = (props) => {
const { className, isRemovable, children, hasBackground, isBold, isFilled, isTop, kind, onRemove, responsiveMode, ...passThroughs } = props;
const isSmall = responsiveMode === 'small';
const labelProps = _.get(getFirst(props, Selection.Label), 'props', {});
const iconElement = getFirst(props, Selection.Icon);
const iconChildren = _.get(iconElement, 'props.children');
const icon = iconChildren
? createElement(iconChildren.type, {
...iconChildren.props,
className: cx('&-Icon', iconChildren.props.className),
})
: defaultIcon(kind, responsiveMode);
return (React.createElement("div", Object.assign({}, omitProps(passThroughs, undefined, _.keys(Selection.propTypes)), { className: cx('&', `&-is-${responsiveMode}`, kind && `&-${kind}`, {
'&-has-background': hasBackground,
'&-is-bold': isBold,
'&-is-filled': isFilled,
'&-is-top': isTop,
'&-no-title': _.isEmpty(labelProps),
}, className) }),
icon,
React.createElement("div", { className: cx('&-content') },
React.createElement("div", { className: cx('&-label-container') },
React.createElement("span", Object.assign({}, labelProps, { className: cx('&-label', isSmall && '&-label-is-small') })),
isRemovable ? (React.createElement(CloseIcon, { isClickable: true, size: !isSmall ? 8 : 16, className: cx('&-close-button', isSmall && '&-close-button-is-small'), onClick: ({ event }) => {
onRemove({ event, props });
} })) : null),
!_.isEmpty(children) && (React.createElement("div", { className: cx('&-children-container') }, _.map(React.Children.toArray(children), (child, i) => {
if (React.isValidElement(child) && child.type === Selection) {
return (React.createElement(Selection, Object.assign({ key: _.get(getFirst(child.props, Selection.Label), ['props', 'children'], {}) + i }, child.props)));
}
return child;
}))))));
};
Selection.displayName = 'Selection';
Selection.Icon = SelectionIcon;
Selection.Label = SelectionLabel;
Selection.peek = {
description: `
Used to indicate selections. Selection is very similar to \`Tag\` but is meant
to be used in areas of the UI that have more space available to them.
`,
categories: ['communication'],
};
Selection.defaultProps = defaultProps;
Selection.propTypes = {
className: string `
Appended to the component-specific class names set on the root element.
`,
kind: oneOf(['default', 'container', 'success', 'danger', 'info', 'warning']) `
Applies an icon and styles for the kind of selection.
`,
isTop: bool `
Apply to the top of a nested sequence of Selection components.
Adds some spacing for a list of top level Selections with nested Selctions inside each.
`,
isFilled: bool `
Only applies to \`container\` Selection components.
Fills with a darker gray background.
Defaults to false.
`,
isRemovable: bool `
Shows or hides the little "x" for a given item.
`,
hasBackground: bool `
Gives the selection a background. This is desirable when you only have
one level of nested selections.
`,
isBold: bool `
Make the content text bold. This is desirable when you only have one
level of nested selections.
`,
onRemove: func `
Called when the close button is clicked.
`,
Label: node `
Label of the component.
`,
Icon: node `
Display a custom icon for the selection. Generally you shouldn't need
this prop since the \`kind\` prop will pick the correct icon for you.
`,
children: node `
Arbitrary children.
`,
responsiveMode: oneOf(['small', 'medium', 'large']) `
Adjusts the display of this component. This should typically be driven by
screen size. Currently \`small\` and \`large\` are explicitly handled by
this component.
`,
};
export default Selection;