UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

134 lines (133 loc) 7.2 kB
import "../../CommonImports"; import "../../Core/core.css"; import "./Pill.css"; import * as React from "react"; import { format } from '../../Core/Util/String'; import { Button } from '../../Button'; import { FocusZoneContext } from '../../FocusZone'; import { Icon, IconSize } from '../../Icon'; import * as Resources from '../../Resources.Widgets'; import { css, getSafeId, KeyCode } from '../../Util'; import { darken, getColorString, isDark } from '../../Utilities/Color'; import { getTabIndex } from '../../Utilities/Focus'; import { PillSize, PillVariant } from "./Pill.Props"; export class Pill extends React.Component { constructor(props) { super(props); this.getChildText = () => { let text = ""; React.Children.map(this.props.children, child => { if (typeof child === "string") { text += child; } }); return text; }; this.onKeyDown = (event) => { const keyCode = event.which; if (keyCode === KeyCode.enter) { this.props.onClick && this.props.onClick(); } }; this.onMouseEnter = (event) => { this.props.onMouseEnter && this.props.onMouseEnter(event); this.setState({ isHoveringPrimaryElement: true }); }; /** * onMouseLeaveButton fires first; if it leaves the container too * onMouseLeave will setState again, which will prevent weird behavior */ this.onMouseLeave = (event) => { this.props.onMouseLeave && this.props.onMouseLeave(event); this.setState({ isHoveringPrimaryElement: false }); }; this.onMouseLeaveButton = () => { this.setState({ isHoveringPrimaryElement: true }); }; this.onMouseOverButton = () => { this.setState({ isHoveringPrimaryElement: false }); }; this.state = { isHoveringPrimaryElement: false }; } static getColorStyle(color, isHoveringPrimaryElement, onClick) { if (!color) { return undefined; } const renderColor = onClick && isHoveringPrimaryElement ? darken(color, 0.06) : color; return { backgroundColor: getColorString(renderColor) }; } static getSizeClass(size) { switch (size) { case PillSize.compact: return "compact"; case PillSize.large: return "large"; case PillSize.regular: default: return "regular"; } } static getVariantClass(variant, color) { switch (variant) { case PillVariant.outlined: return "outlined"; case PillVariant.colored: if (color) { return css("colored", isDark(color) ? "dark" : "light"); } else { return "standard"; } case PillVariant.themedStandard: return "themed-standard"; case PillVariant.standard: default: return "standard"; } } static getDerivedStateFromProps(props, state) { if (false) { const { color, iconProps, onRenderFilledVisual, size = PillSize.regular, variant } = props; // Checking for unsupported compact fields and warning if there are any if (size === PillSize.compact) { const unsupportedFields = []; onRenderFilledVisual && unsupportedFields.push("onRenderFilledVisual"); if (unsupportedFields.length > 0) { console.warn(`Pill Size is Compact, but the following fields were provided: ${unsupportedFields.join(", ")} - these will be ignored. Consider changing Pill Size to Regular or Large if you need to support these items`); } } else { if (onRenderFilledVisual && iconProps) { console.warn("onRenderFilledVisual and iconProps have both been supplied; using onRenderFilledVisual"); } } if (variant === PillVariant.colored && !color) { console.warn("Pill Variant is set to Colored, but not color was provided - Pill will render as Standard"); } else if (color && variant !== PillVariant.colored) { console.warn("Color was provided, but Pill Variant is not set to Colored - Pill will render as whatever variant was provided"); } } return state; } render() { const { ariaHidden, contentClassName, className, color, containsCount = false, iconProps, id, isListItem, onClick, onBlur, onFocus, onRemoveClick, onRenderFilledVisual, size = PillSize.regular, variant = PillVariant.standard } = this.props; const { isHoveringPrimaryElement } = this.state; const ariaLabel = this.props.ariaLabel || this.getChildText(); return (React.createElement(FocusZoneContext.Consumer, null, (zoneContext) => (React.createElement("div", { className: css(className, "bolt-pill flex-row flex-center", Pill.getVariantClass(variant, color), Pill.getSizeClass(size), containsCount && "count", isHoveringPrimaryElement && "hover", onClick && "clickable", onRenderFilledVisual && "has-filled-visual", iconProps && !onRenderFilledVisual && "has-icon", onRemoveClick && "has-remove-button"), id: getSafeId(id), onClick: onClick, onBlur: onBlur, onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave, style: Pill.getColorStyle(color, isHoveringPrimaryElement, onClick), role: isListItem ? "listitem" : undefined }, onRenderFilledVisual && React.createElement("div", { className: "bolt-pill-filled-visual flex-noshrink" }, onRenderFilledVisual()), iconProps && !onRenderFilledVisual && React.createElement(Icon, Object.assign({}, iconProps, { className: css(iconProps.className, "bolt-pill-icon") })), React.createElement("div", { "aria-label": ariaLabel, "aria-hidden": ariaHidden, className: css(contentClassName, "bolt-pill-content text-ellipsis"), "data-focuszone": !this.props.excludeFocusZone ? zoneContext.focuszoneId : undefined, onFocus: onFocus, onKeyDown: this.onKeyDown, role: this.props.role || (onClick ? "button" : "presentation"), tabIndex: onClick || onFocus ? getTabIndex(this.props) : undefined }, this.props.children), onRemoveClick && (React.createElement(Button, { ariaLabel: format(Resources.RemovePillLabel, ariaLabel), className: "bolt-pill-button", iconProps: { iconName: "Cancel", size: IconSize.inherit }, onClick: onRemoveClick, onMouseLeave: this.onMouseLeaveButton, onMouseOver: this.onMouseOverButton, subtle: true, tooltipProps: { text: format(Resources.RemovePillLabel, ariaLabel) }, tabIndex: this.props.removeButtonTabIndex })))))); } }