Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Tag Overflow #16437

Merged
merged 30 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
80cc867
feat: added ellipses to tag
guidari Mar 8, 2024
b623c74
feat: added tooltip
guidari Mar 12, 2024
cc5ce74
feat: added text prop to intereactive tags storybook
guidari Mar 14, 2024
ea50067
fix: removed children prop from interactive tags
guidari Mar 14, 2024
3dfb068
test: snapshots updated
guidari Mar 14, 2024
eff52ed
fix: fixed button propagation
guidari Mar 15, 2024
e70d8c6
fix: added text to operational tags
guidari Mar 15, 2024
46b13ec
fix: removed Tooltip from operational tag example
guidari Mar 15, 2024
1210736
test: fixed tests
guidari Mar 15, 2024
d4f5081
fix: added tooltip style
guidari Apr 2, 2024
3dae034
Merge branch 'main' into 15893-tag
guidari Apr 2, 2024
ff06ff5
fix: added a class to manipulate the onMouseEnter in Tooltip
guidari Apr 2, 2024
e74cc29
chore: an updated to interactive tag story
guidari Apr 3, 2024
076ff6c
chore: update interactive story
guidari Apr 3, 2024
0f749d8
fix: fixed dismissible tag issue and playground story
guidari Apr 4, 2024
28ed418
Merge branch 'main' into 15893-tag
guidari Apr 4, 2024
1421b1a
Merge branch 'main' into 15893-tag
guidari Apr 8, 2024
67afdde
Merge branch 'main' into 15893-tag
guidari May 9, 2024
3ab9727
fix: added new overflow spec to InteractiveTag
guidari May 10, 2024
ec6f5da
test: updated snapshot
guidari May 10, 2024
ede2ea7
fix: removed commented code
guidari May 10, 2024
8c4f594
Merge branch 'main' into 15893-tag-overflow
guidari May 10, 2024
7683d87
fix: fixed errors
guidari May 14, 2024
6764191
Merge branch '15893-tag-overflow' of github.com:guidari/carbon into 1…
guidari May 14, 2024
6046796
Merge branch 'main' into 15893-tag-overflow
guidari May 14, 2024
e83cf37
fix: yarn format
guidari May 14, 2024
a3e1ca7
fix: fixed operational tag disabled with toggletip
guidari May 15, 2024
45f7fc6
fix: fixed title in text
guidari May 15, 2024
7a0530b
fix: fixed flicker in tooltip onclick
guidari May 16, 2024
29081a1
Merge branch 'main' into 15893-tag-overflow
guidari May 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion e2e/components/InteractiveTag/InteractiveTag-test.avt.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand All @@ -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');
Expand All @@ -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 }) => {
Expand All @@ -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');
});
});
19 changes: 19 additions & 0 deletions e2e/components/Tag/Tag-test.avt.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
);
});
});
18 changes: 9 additions & 9 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2729,9 +2729,6 @@ Map {
},
"DismissibleTag" => Object {
"propTypes": Object {
"children": Object {
"type": "node",
},
"className": Object {
"type": "string",
},
Expand Down Expand Up @@ -2770,6 +2767,9 @@ Map {
"slug": Object {
"type": "node",
},
"text": Object {
"type": "string",
},
"title": Object {
"type": "string",
},
Expand Down Expand Up @@ -5626,9 +5626,6 @@ Map {
},
"OperationalTag" => Object {
"propTypes": Object {
"children": Object {
"type": "node",
},
"className": Object {
"type": "string",
},
Expand Down Expand Up @@ -5664,6 +5661,9 @@ Map {
"slug": Object {
"type": "node",
},
"text": Object {
"type": "string",
},
"type": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -6742,9 +6742,6 @@ Map {
},
"SelectableTag" => Object {
"propTypes": Object {
"children": Object {
"type": "node",
},
"className": Object {
"type": "string",
},
Expand Down Expand Up @@ -6783,6 +6780,9 @@ Map {
"slug": Object {
"type": "node",
},
"text": Object {
"type": "string",
},
},
},
"SelectableTile" => Object {
Expand Down
77 changes: 54 additions & 23 deletions packages/react/src/components/Tag/DismissibleTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <span>
*/
Expand Down Expand Up @@ -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
*/
Expand All @@ -76,22 +78,35 @@ export type DismissibleTagProps<T extends React.ElementType> = PolymorphicProps<
>;

const DismissibleTag = <T extends React.ElementType>({
children,
className,
disabled,
id,
renderIcon,
title = 'Clear filter',
title = 'Dismiss',
onClose,
slug,
size,
text,
type,
...other
}: DismissibleTagProps<T>) => {
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<HTMLButtonElement>) => {
if (onClose) {
event.stopPropagation();
Expand All @@ -107,10 +122,17 @@ const DismissibleTag = <T extends React.ElementType>({
});
}

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 (
<Tag<any>
type={type}
Expand All @@ -121,27 +143,31 @@ const DismissibleTag = <T extends React.ElementType>({
id={tagId}
{...otherProps}>
<div className={`${prefix}--interactive--tag-children`}>
{children}
<Text title={text} className={`${prefix}--tag__label`}>
{text}
</Text>
<Tooltip
label={isEllipsisApplied ? dismissLabel : title}
align="bottom"
className={tooltipClasses}
leaveDelayMs={0}
closeOnActivation>
<button
type="button"
className={`${prefix}--tag__close-icon`}
onClick={handleClose}
disabled={disabled}
aria-label={title}
title={title}>
<Close />
</button>
</Tooltip>
{normalizedSlug}
<button
type="button"
className={`${prefix}--tag__close-icon`}
onClick={handleClose}
disabled={disabled}
aria-label={title}
title={title}>
<Close />
</button>
</div>
</Tag>
);
};
DismissibleTag.propTypes = {
/**
* Provide content to be rendered inside of a `DismissibleTag`
*/
children: PropTypes.node,

/**
* Provide a custom className that is applied to the containing <span>
*/
Expand Down Expand Up @@ -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
*/
Expand Down