UNPKG

@carbon/react

Version:

React components for the Carbon Design System

222 lines (214 loc) 8.91 kB
/** * Copyright IBM Corp. 2016, 2023 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js'); var PropTypes = require('prop-types'); var React = require('react'); var cx = require('classnames'); var iconsReact = require('@carbon/icons-react'); var useId = require('../../internal/useId.js'); var usePrefix = require('../../internal/usePrefix.js'); var Text = require('../Text/Text.js'); require('../Text/TextDirection.js'); var deprecate = require('../../prop-types/deprecate.js'); var DefinitionTooltip = require('../Tooltip/DefinitionTooltip.js'); require('../Tooltip/Tooltip.js'); var isEllipsisActive = require('./isEllipsisActive.js'); var useMergedRefs = require('../../internal/useMergedRefs.js'); var index = require('../AILabel/index.js'); var utils = require('../../internal/utils.js'); var useIsomorphicEffect = require('../../internal/useIsomorphicEffect.js'); var _Close; const TYPES = { red: 'Red', magenta: 'Magenta', purple: 'Purple', blue: 'Blue', cyan: 'Cyan', teal: 'Teal', green: 'Green', gray: 'Gray', 'cool-gray': 'Cool-Gray', 'warm-gray': 'Warm-Gray', 'high-contrast': 'High-Contrast', outline: 'Outline' }; const SIZES = { sm: 'sm', md: 'md', lg: 'lg' }; // eslint-disable-next-line react/display-name -- https://github.com/carbon-design-system/carbon/issues/20452 const TagBase = /*#__PURE__*/React.forwardRef(({ children, className, decorator, id, type, filter, // remove filter in next major release - V12 renderIcon: CustomIconElement, title = 'Clear filter', // remove title in next major release - V12 disabled, onClose, // remove onClose in next major release - V12 size, as: BaseComponent, slug, ...other }, forwardRef) => { const prefix = usePrefix.usePrefix(); const tagRef = React.useRef(null); if (filter) { // eslint-disable-next-line no-console -- https://github.com/carbon-design-system/carbon/issues/20452 console.warn('The `filter` prop for Tag has been deprecated and will be removed in the next major version. Use DismissibleTag instead.'); } if (onClose) { // eslint-disable-next-line no-console -- https://github.com/carbon-design-system/carbon/issues/20452 console.warn('The `onClose` prop for Tag has been deprecated and will be removed in the next major version. Use DismissibleTag instead.'); } const ref = useMergedRefs.useMergedRefs([forwardRef, tagRef]); // eslint-disable-next-line react-hooks/rules-of-hooks -- https://github.com/carbon-design-system/carbon/issues/20452 const tagId = id || `tag-${useId.useId()}`; const [isEllipsisApplied, setIsEllipsisApplied] = React.useState(false); useIsomorphicEffect.default(() => { const newElement = tagRef.current?.getElementsByClassName(`${prefix}--tag__label`)[0]; setIsEllipsisApplied(isEllipsisActive.isEllipsisActive(newElement)); }, [prefix, tagRef]); const conditions = [`${prefix}--tag--selectable`, `${prefix}--tag--filter`, `${prefix}--tag--operational`]; const isInteractiveTag = conditions.some(el => className?.includes(el)); const tagClasses = cx(`${prefix}--tag`, className, { [`${prefix}--tag--disabled`]: disabled, [`${prefix}--tag--filter`]: filter, [`${prefix}--tag--${size}`]: size, // TODO: V12 - Remove this class [`${prefix}--layout--size-${size}`]: size, [`${prefix}--tag--${type}`]: type, [`${prefix}--tag--interactive`]: other.onClick && !isInteractiveTag && isEllipsisApplied }); const typeText = type !== undefined && type in Object.keys(TYPES) ? TYPES[type] : ''; const handleClose = event => { if (onClose) { event.stopPropagation(); onClose(event); } }; // AILabel is always size `sm` and `inline` const candidate = slug ?? decorator; const candidateIsAILabel = utils.isComponentElement(candidate, index.AILabel); const normalizedDecorator = candidateIsAILabel && !isInteractiveTag ? /*#__PURE__*/React.cloneElement(candidate, { size: 'sm', kind: 'inline' }) : null; if (filter) { const ComponentTag = BaseComponent ?? 'div'; return /*#__PURE__*/React.createElement(ComponentTag, _rollupPluginBabelHelpers.extends({ className: tagClasses, id: tagId }, other), CustomIconElement && size !== 'sm' ? /*#__PURE__*/React.createElement("div", { className: `${prefix}--tag__custom-icon` }, /*#__PURE__*/React.createElement(CustomIconElement, null)) : '', /*#__PURE__*/React.createElement(Text.Text, { title: typeof children === 'string' ? children : undefined, className: `${prefix}--tag__label` }, children !== null && children !== undefined ? children : typeText), normalizedDecorator, /*#__PURE__*/React.createElement("button", { type: "button", className: `${prefix}--tag__close-icon`, onClick: handleClose, disabled: disabled, "aria-label": title, title: title }, _Close || (_Close = /*#__PURE__*/React.createElement(iconsReact.Close, null)))); } const ComponentTag = BaseComponent ?? (other.onClick || className?.includes(`${prefix}--tag--operational`) ? 'button' : 'div'); const labelClasses = cx({ [`${prefix}--tag__label`]: !isInteractiveTag }); return /*#__PURE__*/React.createElement(ComponentTag, _rollupPluginBabelHelpers.extends({ ref: ref, disabled: disabled, className: tagClasses, id: tagId, type: ComponentTag === 'button' ? 'button' : undefined }, other), CustomIconElement && size !== 'sm' ? /*#__PURE__*/React.createElement("div", { className: `${prefix}--tag__custom-icon` }, /*#__PURE__*/React.createElement(CustomIconElement, null)) : '', isEllipsisApplied && !isInteractiveTag ? /*#__PURE__*/React.createElement(DefinitionTooltip.DefinitionTooltip, { openOnHover: false, definition: children !== null && children !== undefined ? children : typeText, className: `${prefix}--definition--tooltip--tag` }, /*#__PURE__*/React.createElement(Text.Text, { title: children !== null && children !== undefined && typeof children === 'string' ? children : typeText, className: labelClasses }, children !== null && children !== undefined ? children : typeText)) : /*#__PURE__*/React.createElement(Text.Text, { title: children !== null && children !== undefined && typeof children === 'string' ? children : typeText, className: labelClasses }, children !== null && children !== undefined ? children : typeText), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", { className: `${prefix}--tag__decorator` }, normalizedDecorator) : ''); }); const Tag = TagBase; // @ts-expect-error - `propTypes` isn't typed. Tag.propTypes = { /** * Provide an alternative tag or component to use instead of the default * wrapping element */ as: PropTypes.elementType, /** * Provide content to be rendered inside of a `Tag` */ children: PropTypes.node, /** * Provide a custom className that is applied to the containing <span> */ className: PropTypes.string, /** * **Experimental:** Provide a `decorator` component to be rendered inside the `Tag` component */ decorator: PropTypes.node, /** * Specify if the `Tag` is disabled */ disabled: PropTypes.bool, /** * Determine if `Tag` is a filter/chip */ filter: deprecate.deprecate(PropTypes.bool, 'The `filter` prop has been deprecated and will be removed in the next major version. Use DismissibleTag instead.'), /** * Specify the id for the tag. */ id: PropTypes.string, /** * Click handler for filter tag close button. */ onClose: deprecate.deprecate(PropTypes.func, 'The `onClose` prop has been deprecated and will be removed in the next major version. Use DismissibleTag instead.'), /** * A component used to render an icon. */ renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), /** * Specify the size of the Tag. Currently supports either `sm`, * `md` (default) or `lg` sizes. */ size: PropTypes.oneOf(Object.keys(SIZES)), /** * **Experimental:** Provide a `Slug` component to be rendered inside the `Tag` component */ slug: deprecate.deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'), /** * Text to show on clear filters */ title: deprecate.deprecate(PropTypes.string, 'The `title` prop has been deprecated and will be removed in the next major version. Use DismissibleTag instead.'), /** * Specify the type of the `Tag` */ type: PropTypes.oneOf(Object.keys(TYPES)) }; exports.SIZES = SIZES; exports.TYPES = TYPES; exports.default = Tag;