diff --git a/e2e/components/InteractiveTag/InteractiveTag-test.avt.e2e.js b/e2e/components/InteractiveTag/InteractiveTag-test.avt.e2e.js index 0850ab819921..992826fa58ad 100644 --- a/e2e/components/InteractiveTag/InteractiveTag-test.avt.e2e.js +++ b/e2e/components/InteractiveTag/InteractiveTag-test.avt.e2e.js @@ -53,10 +53,12 @@ test.describe('@avt InteractiveTag', () => { theme: 'white', }, }); + const tooltip = page.getByRole('tooltip'); const button = page.getByRole('button').first(); await expect(button).toBeVisible(); await page.keyboard.press('Tab'); await expect(button).toBeFocused(); + await expect(tooltip).toHaveAttribute('aria-hidden', 'false'); }); test('@avt-keyboard-nav OperationalTag', async ({ page }) => { @@ -71,6 +73,10 @@ test.describe('@avt InteractiveTag', () => { await expect(button).toBeVisible(); await page.keyboard.press('Tab'); await expect(button).toBeFocused(); + await expect(page.getByRole('tooltip')).toHaveAttribute( + 'aria-hidden', + 'false' + ); await expect(button).toHaveClass(/cds--tag--red/); await page.keyboard.press('Tab'); @@ -87,7 +93,7 @@ test.describe('@avt InteractiveTag', () => { // Expecte the OperationalTag with tooltip be focusable and visible await expect(page.getByRole('button').nth(10)).toBeFocused(); await page.keyboard.press('Enter'); - await expect(page.getByText('View More')).toBeVisible(); + await expect(page.getByText('Tag 1 name').first()).toBeVisible(); }); test('@avt-keyboard-nav SelectableTag', async ({ page }) => { @@ -103,6 +109,11 @@ test.describe('@avt InteractiveTag', () => { await page.keyboard.press('Tab'); await expect(tag).toBeFocused(); await page.keyboard.press('Enter'); + await expect(page.getByRole('tooltip')).toHaveAttribute( + 'aria-hidden', + 'false' + ); await expect(tag).toHaveClass(/cds--tag--selectable-selected/); + await page.keyboard.press('Tab'); }); }); diff --git a/e2e/components/Tag/Tag-test.avt.e2e.js b/e2e/components/Tag/Tag-test.avt.e2e.js index 37debfcac4b4..5a0093b60402 100644 --- a/e2e/components/Tag/Tag-test.avt.e2e.js +++ b/e2e/components/Tag/Tag-test.avt.e2e.js @@ -32,4 +32,23 @@ test.describe('@avt Tag', () => { }); await expect(page).toHaveNoACViolations('Tag-skeleton'); }); + + test('@avt-keyboard-nav Tag', async ({ page }) => { + await visitStory(page, { + component: 'Tag', + id: 'components-tag--read-only', + globals: { + theme: 'white', + }, + }); + const button = page.getByRole('button').first(); + await expect(button).toBeVisible(); + await page.keyboard.press('Tab'); + await expect(button).toBeFocused(); + // Expect DefinitionTooltip to be visible + await expect(page.getByRole('button')).toHaveAttribute( + 'aria-expanded', + 'true' + ); + }); }); diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index f484a7b44532..5e5ec22fae25 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -2729,9 +2729,6 @@ Map { }, "DismissibleTag" => Object { "propTypes": Object { - "children": Object { - "type": "node", - }, "className": Object { "type": "string", }, @@ -2770,6 +2767,9 @@ Map { "slug": Object { "type": "node", }, + "text": Object { + "type": "string", + }, "title": Object { "type": "string", }, @@ -5626,9 +5626,6 @@ Map { }, "OperationalTag" => Object { "propTypes": Object { - "children": Object { - "type": "node", - }, "className": Object { "type": "string", }, @@ -5664,6 +5661,9 @@ Map { "slug": Object { "type": "node", }, + "text": Object { + "type": "string", + }, "type": Object { "args": Array [ Array [ @@ -6742,9 +6742,6 @@ Map { }, "SelectableTag" => Object { "propTypes": Object { - "children": Object { - "type": "node", - }, "className": Object { "type": "string", }, @@ -6783,6 +6780,9 @@ Map { "slug": Object { "type": "node", }, + "text": Object { + "type": "string", + }, }, }, "SelectableTile" => Object { diff --git a/packages/react/src/components/Tag/DismissibleTag.tsx b/packages/react/src/components/Tag/DismissibleTag.tsx index 3adc9af0823d..b9223c6bdb5c 100644 --- a/packages/react/src/components/Tag/DismissibleTag.tsx +++ b/packages/react/src/components/Tag/DismissibleTag.tsx @@ -6,22 +6,19 @@ */ import PropTypes from 'prop-types'; -import React, { ReactNode } from 'react'; +import React, { useLayoutEffect, useState, ReactNode } from 'react'; import classNames from 'classnames'; import setupGetInstanceId from '../../tools/setupGetInstanceId'; import { usePrefix } from '../../internal/usePrefix'; import { PolymorphicProps } from '../../types/common'; import Tag, { SIZES, TYPES } from './Tag'; import { Close } from '@carbon/icons-react'; +import { Tooltip } from '../Tooltip'; +import { Text } from '../Text'; const getInstanceId = setupGetInstanceId(); export interface DismissibleTagBaseProps { - /** - * Provide content to be rendered inside of a `DismissibleTag` - */ - children?: React.ReactNode; - /** * Provide a custom className that is applied to the containing */ @@ -59,6 +56,11 @@ export interface DismissibleTagBaseProps { */ slug?: ReactNode; + /** + * Provide text to be rendered inside of a the tag. + */ + text?: string; + /** * Text to show on clear filters */ @@ -76,22 +78,35 @@ export type DismissibleTagProps = PolymorphicProps< >; const DismissibleTag = ({ - children, className, disabled, id, renderIcon, - title = 'Clear filter', + title = 'Dismiss', onClose, slug, size, + text, type, ...other }: DismissibleTagProps) => { const prefix = usePrefix(); const tagId = id || `tag-${getInstanceId()}`; const tagClasses = classNames(`${prefix}--tag--filter`, className); + const [isEllipsisApplied, setIsEllipsisApplied] = useState(false); + + const isEllipsisActive = (element: any) => { + setIsEllipsisApplied(element.offsetWidth < element.scrollWidth); + return element.offsetWidth < element.scrollWidth; + }; + useLayoutEffect(() => { + const elementTagId = document.querySelector(`#${tagId}`); + const newElement = elementTagId?.getElementsByClassName( + `${prefix}--tag__label` + )[0]; + isEllipsisActive(newElement); + }, [prefix, tagId]); const handleClose = (event: React.MouseEvent) => { if (onClose) { event.stopPropagation(); @@ -107,10 +122,17 @@ const DismissibleTag = ({ }); } + const tooltipClasses = classNames( + `${prefix}--icon-tooltip`, + `${prefix}--tag-label-tooltip` + ); + // Removing onClick from the spread operator // eslint-disable-next-line @typescript-eslint/no-unused-vars const { onClick, ...otherProps } = other; + const dismissLabel = `Dismiss "${text}"`; + return ( type={type} @@ -121,27 +143,31 @@ const DismissibleTag = ({ id={tagId} {...otherProps}>
- {children} + + {text} + + + + {normalizedSlug} -
); }; DismissibleTag.propTypes = { - /** - * Provide content to be rendered inside of a `DismissibleTag` - */ - children: PropTypes.node, - /** * Provide a custom className that is applied to the containing */ @@ -179,6 +205,11 @@ DismissibleTag.propTypes = { */ slug: PropTypes.node, + /** + * Provide text to be rendered inside of a the tag. + */ + text: PropTypes.string, + /** * Text to show on clear filters */ diff --git a/packages/react/src/components/Tag/InteractiveTag.stories.js b/packages/react/src/components/Tag/InteractiveTag.stories.js index b8384d6bef09..9aeba0774ca6 100644 --- a/packages/react/src/components/Tag/InteractiveTag.stories.js +++ b/packages/react/src/components/Tag/InteractiveTag.stories.js @@ -11,11 +11,9 @@ import { default as SelectableTag } from './SelectableTag'; import { default as OperationalTag } from './OperationalTag'; import { default as DismissibleTag } from './DismissibleTag'; import { Asleep } from '@carbon/icons-react'; -import { Tooltip } from '../Tooltip'; import { Toggletip, ToggletipButton, ToggletipContent } from '../Toggletip'; import { Popover, PopoverContent } from '../Popover'; import mdx from './InteractiveTag.mdx'; -import { usePrefix } from '../../internal/usePrefix'; import './storyInteractiveTag.scss'; export default { @@ -30,9 +28,20 @@ export default { export const Selectable = (args) => { return ( - - {'Tag content'} - + <> + + + ); }; @@ -79,7 +88,6 @@ Selectable.argTypes = { }; export const Operational = (args) => { - const prefix = usePrefix(); const [open, setOpen] = useState(false); return ( @@ -89,72 +97,72 @@ export const Operational = (args) => { type="red" className="some-class" renderIcon={Asleep} - {...args}> - {'Tag content'} - + text="Tag content with a long text description" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + /> - {'Tag content'} - + text="Tag content" + {...args} + />

Interactive examples

@@ -165,23 +173,14 @@ export const Operational = (args) => { justifyContent: 'flex-start', marginTop: '1rem', }}> - - - {'Tag content'} - - - - {'Tag content'} - + {...args} + />
@@ -200,10 +199,10 @@ export const Operational = (args) => { setOpen(!open); }} renderIcon={Asleep} + text="Tag content" className="some-class" - {...args}> - {'Tag content'} - + {...args} + />
{ - {'Tag content'} - + text="Tag content with a long text description" + {...args} + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> - {'Tag content'} - + /> ); }; diff --git a/packages/react/src/components/Tag/OperationalTag.tsx b/packages/react/src/components/Tag/OperationalTag.tsx index 492da4a660a2..4b250b016473 100644 --- a/packages/react/src/components/Tag/OperationalTag.tsx +++ b/packages/react/src/components/Tag/OperationalTag.tsx @@ -6,12 +6,19 @@ */ import PropTypes from 'prop-types'; -import React, { MouseEventHandler, ReactNode } from 'react'; +import React, { + MouseEventHandler, + useLayoutEffect, + useState, + ReactNode, +} from 'react'; import classNames from 'classnames'; import setupGetInstanceId from '../../tools/setupGetInstanceId'; import { usePrefix } from '../../internal/usePrefix'; import { PolymorphicProps } from '../../types/common'; import Tag, { SIZES } from './Tag'; +import { Tooltip } from '../Tooltip'; +import { Text } from '../Text'; const getInstanceId = setupGetInstanceId(); @@ -29,11 +36,6 @@ const TYPES = { }; export interface OperationalTagBaseProps { - /** - * Provide content to be rendered inside of a `OperationalTag` - */ - children?: React.ReactNode; - /** * Provide a custom className that is applied to the containing */ @@ -67,6 +69,11 @@ export interface OperationalTagBaseProps { */ slug?: ReactNode; + /** + * Provide text to be rendered inside of a the tag. + */ + text?: string; + /** * Specify the type of the `Tag` */ @@ -79,19 +86,34 @@ export type OperationalTagProps = PolymorphicProps< >; const OperationalTag = ({ - children, className, disabled, id, renderIcon, slug, size, + text, type = 'gray', ...other }: OperationalTagProps) => { const prefix = usePrefix(); const tagId = id || `tag-${getInstanceId()}`; const tagClasses = classNames(`${prefix}--tag--operational`, className); + const [isEllipsisApplied, setIsEllipsisApplied] = useState(false); + + const isEllipsisActive = (element: any) => { + setIsEllipsisApplied(element.offsetWidth < element.scrollWidth); + return element.offsetWidth < element.scrollWidth; + }; + + useLayoutEffect(() => { + const elementTagId = document.querySelector(`#${tagId}`); + const newElement = elementTagId?.getElementsByClassName( + `${prefix}--tag__label` + )[0]; + + isEllipsisActive(newElement); + }, [prefix, tagId]); let normalizedSlug; if (slug && slug['type']?.displayName === 'Slug') { @@ -101,6 +123,37 @@ const OperationalTag = ({ }); } + const tooltipClasses = classNames( + `${prefix}--icon-tooltip`, + `${prefix}--tag-label-tooltip` + ); + + if (isEllipsisApplied) { + return ( + + + type={type} + size={size} + renderIcon={renderIcon} + disabled={disabled} + className={tagClasses} + id={tagId} + {...other}> + + {text} + + {normalizedSlug} + + + ); + } + return ( type={type} @@ -110,20 +163,15 @@ const OperationalTag = ({ className={tagClasses} id={tagId} {...other}> -
- {children} - {normalizedSlug} -
+ {normalizedSlug} + + {text} + ); }; OperationalTag.propTypes = { - /** - * Provide content to be rendered inside of a `OperationalTag` - */ - children: PropTypes.node, - /** * Provide a custom className that is applied to the containing */ @@ -156,6 +204,11 @@ OperationalTag.propTypes = { */ slug: PropTypes.node, + /** + * Provide text to be rendered inside of a the tag. + */ + text: PropTypes.string, + /** * Specify the type of the `Tag` */ diff --git a/packages/react/src/components/Tag/SelectableTag.tsx b/packages/react/src/components/Tag/SelectableTag.tsx index 5c9ae841cf62..129dbb5b45ac 100644 --- a/packages/react/src/components/Tag/SelectableTag.tsx +++ b/packages/react/src/components/Tag/SelectableTag.tsx @@ -6,21 +6,18 @@ */ import PropTypes from 'prop-types'; -import React, { ReactNode, useState } from 'react'; +import React, { useLayoutEffect, useState, ReactNode } from 'react'; import classNames from 'classnames'; import setupGetInstanceId from '../../tools/setupGetInstanceId'; import { usePrefix } from '../../internal/usePrefix'; import { PolymorphicProps } from '../../types/common'; import Tag, { SIZES } from './Tag'; +import { Tooltip } from '../Tooltip'; +import { Text } from '../Text'; const getInstanceId = setupGetInstanceId(); export interface SelectableTagBaseProps { - /** - * Provide content to be rendered inside of a `SelectableTag` - */ - children?: React.ReactNode; - /** * Provide a custom className that is applied to the containing */ @@ -57,6 +54,11 @@ export interface SelectableTagBaseProps { * **Experimental:** Provide a `Slug` component to be rendered inside the `SelectableTag` component */ slug?: ReactNode; + + /** + * Provide text to be rendered inside of a the tag. + */ + text?: string; } export type SelectableTagProps = PolymorphicProps< @@ -65,7 +67,6 @@ export type SelectableTagProps = PolymorphicProps< >; const SelectableTag = ({ - children, className, disabled, id, @@ -73,6 +74,7 @@ const SelectableTag = ({ selected = false, slug, size, + text, ...other }: SelectableTagProps) => { const prefix = usePrefix(); @@ -81,6 +83,20 @@ const SelectableTag = ({ const tagClasses = classNames(`${prefix}--tag--selectable`, className, { [`${prefix}--tag--selectable-selected`]: selectedTag, }); + const [isEllipsisApplied, setIsEllipsisApplied] = useState(false); + + const isEllipsisActive = (element: any) => { + setIsEllipsisApplied(element.offsetWidth < element.scrollWidth); + return element.offsetWidth < element.scrollWidth; + }; + + useLayoutEffect(() => { + const elementTagId = document.querySelector(`#${tagId}`); + const newElement = elementTagId?.getElementsByClassName( + `${prefix}--tag__label` + )[0]; + isEllipsisActive(newElement); + }, [prefix, tagId]); let normalizedSlug; if (slug && slug['type']?.displayName === 'Slug') { @@ -90,10 +106,41 @@ const SelectableTag = ({ }); } + const tooltipClasses = classNames( + `${prefix}--icon-tooltip`, + `${prefix}--tag-label-tooltip` + ); + // Removing onClick from the spread operator // eslint-disable-next-line @typescript-eslint/no-unused-vars const { onClick, ...otherProps } = other; + if (isEllipsisApplied) { + return ( + + + slug={slug} + size={size} + renderIcon={renderIcon} + disabled={disabled} + className={tagClasses} + id={tagId} + onClick={() => setSelectedTag(!selectedTag)} + {...otherProps}> + + {text} + + {normalizedSlug} + + + ); + } + return ( slug={slug} @@ -104,20 +151,15 @@ const SelectableTag = ({ id={tagId} onClick={() => setSelectedTag(!selectedTag)} {...otherProps}> -
- {children} - {normalizedSlug} -
+ {normalizedSlug} + + {text} + ); }; SelectableTag.propTypes = { - /** - * Provide content to be rendered inside of a `SelectableTag` - */ - children: PropTypes.node, - /** * Provide a custom className that is applied to the containing */ @@ -154,6 +196,11 @@ SelectableTag.propTypes = { * **Experimental:** Provide a `Slug` component to be rendered inside the `SelectableTag` component */ slug: PropTypes.node, + + /** + * Provide text to be rendered inside of a the tag. + */ + text: PropTypes.string, }; export default SelectableTag; diff --git a/packages/react/src/components/Tag/Tag-test.js b/packages/react/src/components/Tag/Tag-test.js index bd7715035e0c..69c5e1d3ad1a 100644 --- a/packages/react/src/components/Tag/Tag-test.js +++ b/packages/react/src/components/Tag/Tag-test.js @@ -30,11 +30,8 @@ describe('Tag', () => { }); it('should have an appropriate aria-label when (filterable)', () => { - const children = 'tag-3'; const { container } = render( - - {children} - + ); // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access const button = container.querySelector('[aria-label]'); diff --git a/packages/react/src/components/Tag/Tag.stories.js b/packages/react/src/components/Tag/Tag.stories.js index b162934e0dd2..f8ad717f4aac 100644 --- a/packages/react/src/components/Tag/Tag.stories.js +++ b/packages/react/src/components/Tag/Tag.stories.js @@ -19,7 +19,7 @@ export const ReadOnly = () => { return ( <> - {'Tag content'} + {'Tag content with a long text description'} {'Tag content'} diff --git a/packages/react/src/components/Tag/Tag.tsx b/packages/react/src/components/Tag/Tag.tsx index 51f55c62e36e..3ef10aef9486 100644 --- a/packages/react/src/components/Tag/Tag.tsx +++ b/packages/react/src/components/Tag/Tag.tsx @@ -6,7 +6,7 @@ */ import PropTypes from 'prop-types'; -import React, { ReactNode } from 'react'; +import React, { useLayoutEffect, useState, ReactNode } from 'react'; import classNames from 'classnames'; import { Close } from '@carbon/icons-react'; import setupGetInstanceId from '../../tools/setupGetInstanceId'; @@ -14,6 +14,7 @@ import { usePrefix } from '../../internal/usePrefix'; import { PolymorphicProps } from '../../types/common'; import { Text } from '../Text'; import deprecate from '../../prop-types/deprecate'; +import { DefinitionTooltip } from '../Tooltip'; const getInstanceId = setupGetInstanceId(); export const TYPES = { @@ -118,6 +119,20 @@ const Tag = ({ }: TagProps) => { const prefix = usePrefix(); const tagId = id || `tag-${getInstanceId()}`; + const [isEllipsisApplied, setIsEllipsisApplied] = useState(false); + + const isEllipsisActive = (element: any) => { + setIsEllipsisApplied(element.offsetWidth < element.scrollWidth); + return element.offsetWidth < element.scrollWidth; + }; + + useLayoutEffect(() => { + const elementTagId = document.querySelector(`#${tagId}`); + const newElement = elementTagId?.getElementsByClassName( + `${prefix}--tag__label` + )[0]; + isEllipsisActive(newElement); + }, [prefix, tagId]); const conditions = [ `${prefix}--tag--selectable`, @@ -133,7 +148,8 @@ const Tag = ({ [`${prefix}--tag--${size}`]: size, // TODO: V12 - Remove this class [`${prefix}--layout--size-${size}`]: size, [`${prefix}--tag--${type}`]: type, - [`${prefix}--tag--interactive`]: other.onClick && !isInteractiveTag, + [`${prefix}--tag--interactive`]: + other.onClick && !isInteractiveTag && isEllipsisApplied, }); const typeText = @@ -166,9 +182,10 @@ const Tag = ({ ) : ( '' )} + + title={typeof children === 'string' ? children : undefined} + className={`${prefix}--tag__label`}> {children !== null && children !== undefined ? children : typeText} {normalizedSlug} @@ -191,6 +208,11 @@ const Tag = ({ ? 'button' : 'div'); + const labelClasses = classNames({ + [`${prefix}--tag__label`]: !isInteractiveTag, + [`${prefix}--tag--${type}`]: type && !isInteractiveTag, + }); + return ( ({ ) : ( '' )} - - {children !== null && children !== undefined ? children : typeText} - + {isEllipsisApplied && !isInteractiveTag ? ( + + + {children !== null && children !== undefined ? children : typeText} + + + ) : ( + + {children !== null && children !== undefined ? children : typeText} + + )} + {normalizedSlug} ); diff --git a/packages/react/src/components/Tag/storyInteractiveTag.scss b/packages/react/src/components/Tag/storyInteractiveTag.scss index faf601110188..407126a219b2 100644 --- a/packages/react/src/components/Tag/storyInteractiveTag.scss +++ b/packages/react/src/components/Tag/storyInteractiveTag.scss @@ -3,3 +3,9 @@ #operational-tag > .cds--popover--caret { --cds-popover-offset: 5px; } + +#operational-tag > .cds--popover-caret, +.cds--popover { + --cds-popover-offset: 5px; + --cds-popover-caret-height: 5px; +} diff --git a/packages/react/src/components/Tooltip/Tooltip.tsx b/packages/react/src/components/Tooltip/Tooltip.tsx index f3718d5078c3..ccd00475933b 100644 --- a/packages/react/src/components/Tooltip/Tooltip.tsx +++ b/packages/react/src/components/Tooltip/Tooltip.tsx @@ -101,19 +101,23 @@ function Tooltip({ const tooltipRef = useRef(null); const [open, setOpen] = useDelayedState(defaultOpen); const [isDragging, setIsDragging] = useState(false); + const [focusByMouse, setFocusByMouse] = useState(false); const [isPointerIntersecting, setIsPointerIntersecting] = useState(false); const id = useId('tooltip'); const prefix = usePrefix(); const child = React.Children.only(children); const triggerProps = { - onFocus: () => setOpen(true), - onBlur: () => setOpen(false), + onFocus: () => !focusByMouse && setOpen(true), + onBlur: () => { + setOpen(false); + setFocusByMouse(false); + }, onClick: () => closeOnActivation && setOpen(false), // This should be placed on the trigger in case the element is disabled onMouseEnter, onMouseLeave, - onMouseDown: onDragStart, + onMouseDown, onMouseMove: onMouseMove, onTouchStart: onDragStart, }; @@ -155,8 +159,16 @@ function Tooltip({ } function onMouseEnter() { - setIsPointerIntersecting(true); - setOpen(true, enterDelayMs); + // Interactive Tags should not support onMouseEnter + if (!rest?.onMouseEnter?.()) { + setIsPointerIntersecting(true); + setOpen(true, enterDelayMs); + } + } + + function onMouseDown() { + setFocusByMouse(true); + onDragStart(); } function onMouseLeave() { @@ -209,7 +221,7 @@ function Tooltip({ }, [isDragging, onDragStop]); return ( - {...rest} align={align} className={cx(`${prefix}--tooltip`, customClassName)} diff --git a/packages/styles/scss/components/tag/_tag.scss b/packages/styles/scss/components/tag/_tag.scss index e893df81e3b7..5376098b6bf7 100644 --- a/packages/styles/scss/components/tag/_tag.scss +++ b/packages/styles/scss/components/tag/_tag.scss @@ -48,7 +48,7 @@ margin: $spacing-02; cursor: default; // restricts size of contained elements - max-inline-size: 100%; + max-inline-size: convert.to-rem(208px); min-block-size: layout.size('height'); // ensures tag stays pill shaped; min-inline-size: convert.to-rem(32px); @@ -72,30 +72,31 @@ padding-inline-start: $spacing-03; } + &:not(.#{$prefix}--tag--selectable) { + border: 0; + } + &:not(:first-child) { margin-inline-start: 0; } } + .#{$prefix}--tag--operational > span, + .#{$prefix}--tag--selectable > span, .#{$prefix}--tag__label { + display: block; overflow: hidden; - max-inline-size: 100%; text-overflow: ellipsis; white-space: nowrap; } .#{$prefix}--tag--interactive:focus { - box-shadow: inset 0 0 0 1px $focus; - outline: none; - } - - .#{$prefix}--tag--interactive:hover { - cursor: pointer; + outline: 2px solid $focus; + outline-offset: 1px; } // tags used for filtering .#{$prefix}--tag--filter { - cursor: pointer; padding-block-end: 0; padding-block-start: 0; padding-inline-end: 0; @@ -105,11 +106,6 @@ } } - .#{$prefix}--interactive--tag-children { - display: inline-flex; - place-items: center; - } - .#{$prefix}--tag--selectable { border: 1px solid $border-inverse; background-color: $layer; @@ -251,7 +247,9 @@ ); } - .#{$prefix}--tag--outline:not(.#{$prefix}--tag--operational) { + .#{$prefix}--tag--outline:not(.#{$prefix}--tag--operational):not(span):not( + [disabled] + ) { @include tag-theme($background, $text-primary, $layer-hover); outline: 1px solid $background-inverse; @@ -408,5 +406,56 @@ .#{$prefix}--tag__close-icon:focus { @include high-contrast-mode('focus'); } + + .#{$prefix}--tag-label-tooltip { + max-inline-size: -webkit-fill-available; + } + + .#{$prefix}--tag__custom-icon + .#{$prefix}--tag-label-tooltip { + max-inline-size: convert.to-rem(176px); + } + + .#{$prefix}--tag--filter + .#{$prefix}--tag__custom-icon + + .#{$prefix}--tag-label-tooltip { + max-inline-size: convert.to-rem(158px); + } /* stylelint-enable */ + + .#{$prefix}--interactive--tag-children { + display: inline-flex; + max-inline-size: convert.to-rem(200px); + place-items: center; + } + + .#{$prefix}--tag--filter + .#{$prefix}--tag__custom-icon + + span + > .#{$prefix}--interactive--tag-children { + max-inline-size: convert.to-rem(184px); + } + + .#{$prefix}--tag .#{$prefix}--definition-term { + -webkit-border-after: none; + border-block-end: none; + cursor: default; + max-inline-size: convert.to-rem(192px); + } + + .#{$prefix}--tag + .#{$prefix}--tag__custom-icon + + span + > .#{$prefix}--definition-term { + max-inline-size: convert.to-rem(176px); + } + + .#{$prefix}--tag > .#{$prefix}--popover-container { + display: flex; + } + + .#{$prefix}--toggletip-button:has( + .#{$prefix}--tag--operational.#{$prefix}--tag--disabled + ) { + pointer-events: none; + } }