Skip to content

Commit 898ca5a

Browse files
Merge branch 'main' into windows-cli
2 parents 27bda34 + 34532d8 commit 898ca5a

File tree

7 files changed

+247
-226
lines changed

7 files changed

+247
-226
lines changed

packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,6 +2915,7 @@ Map {
29152915
},
29162916
},
29172917
"DismissibleTag" => Object {
2918+
"$$typeof": Symbol(react.forward_ref),
29182919
"propTypes": Object {
29192920
"className": Object {
29202921
"type": "string",
@@ -2984,6 +2985,7 @@ Map {
29842985
"type": "oneOf",
29852986
},
29862987
},
2988+
"render": [Function],
29872989
},
29882990
"Dropdown" => Object {
29892991
"$$typeof": Symbol(react.forward_ref),
@@ -6845,6 +6847,7 @@ Map {
68456847
},
68466848
},
68476849
"SelectableTag" => Object {
6850+
"$$typeof": Symbol(react.forward_ref),
68486851
"propTypes": Object {
68496852
"className": Object {
68506853
"type": "string",
@@ -6891,6 +6894,7 @@ Map {
68916894
"type": "string",
68926895
},
68936896
},
6897+
"render": [Function],
68946898
},
68956899
"SelectableTile" => Object {
68966900
"$$typeof": Symbol(react.forward_ref),

packages/react/src/components/Tag/DismissibleTag.tsx

Lines changed: 117 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
*/
77

88
import PropTypes from 'prop-types';
9-
import React, { useLayoutEffect, useState, ReactNode, useRef } from 'react';
9+
import React, {
10+
useLayoutEffect,
11+
useState,
12+
ReactNode,
13+
useRef,
14+
forwardRef,
15+
ForwardedRef,
16+
} from 'react';
1017
import classNames from 'classnames';
1118
import { useId } from '../../internal/useId';
1219
import { usePrefix } from '../../internal/usePrefix';
@@ -17,6 +24,7 @@ import { Close } from '@carbon/icons-react';
1724
import { Tooltip } from '../Tooltip';
1825
import { Text } from '../Text';
1926
import { isEllipsisActive } from './isEllipsisActive';
27+
import mergeRefs from '../../tools/mergeRefs';
2028

2129
export interface DismissibleTagBaseProps {
2230
/**
@@ -87,111 +95,117 @@ export type DismissibleTagProps<T extends React.ElementType> = PolymorphicProps<
8795
DismissibleTagBaseProps
8896
>;
8997

90-
const DismissibleTag = <T extends React.ElementType>({
91-
className,
92-
decorator,
93-
disabled,
94-
id,
95-
renderIcon,
96-
title = 'Dismiss',
97-
onClose,
98-
slug,
99-
size,
100-
text,
101-
tagTitle,
102-
type,
103-
...other
104-
}: DismissibleTagProps<T>) => {
105-
const prefix = usePrefix();
106-
const tagLabelRef = useRef<HTMLDivElement>(null);
107-
const tagId = id || `tag-${useId()}`;
108-
const tagClasses = classNames(`${prefix}--tag--filter`, className);
109-
const [isEllipsisApplied, setIsEllipsisApplied] = useState(false);
110-
111-
useLayoutEffect(() => {
112-
const newElement = tagLabelRef.current?.getElementsByClassName(
113-
`${prefix}--tag__label`
114-
)[0];
115-
setIsEllipsisApplied(isEllipsisActive(newElement));
116-
}, [prefix, tagLabelRef]);
117-
const handleClose = (event: React.MouseEvent<HTMLButtonElement>) => {
118-
if (onClose) {
119-
event.stopPropagation();
120-
onClose(event);
121-
}
122-
};
123-
124-
let normalizedDecorator = React.isValidElement(slug ?? decorator)
125-
? (slug ?? decorator)
126-
: null;
127-
if (
128-
normalizedDecorator &&
129-
normalizedDecorator['type']?.displayName === 'AILabel'
130-
) {
131-
normalizedDecorator = React.cloneElement(
132-
normalizedDecorator as React.ReactElement<any>,
133-
{
134-
size: 'sm',
135-
kind: 'inline',
98+
const DismissibleTag = forwardRef(
99+
<T extends React.ElementType>(
100+
{
101+
className,
102+
decorator,
103+
disabled,
104+
id,
105+
renderIcon,
106+
title = 'Dismiss',
107+
onClose,
108+
slug,
109+
size,
110+
text,
111+
tagTitle,
112+
type,
113+
...other
114+
}: DismissibleTagProps<T>,
115+
forwardRef: ForwardedRef<HTMLDivElement>
116+
) => {
117+
const prefix = usePrefix();
118+
const tagLabelRef = useRef<HTMLDivElement>(null);
119+
const tagId = id || `tag-${useId()}`;
120+
const tagClasses = classNames(`${prefix}--tag--filter`, className);
121+
const [isEllipsisApplied, setIsEllipsisApplied] = useState(false);
122+
123+
useLayoutEffect(() => {
124+
const newElement = tagLabelRef.current?.getElementsByClassName(
125+
`${prefix}--tag__label`
126+
)[0];
127+
setIsEllipsisApplied(isEllipsisActive(newElement));
128+
}, [prefix, tagLabelRef]);
129+
const combinedRef = mergeRefs(tagLabelRef, forwardRef);
130+
const handleClose = (event: React.MouseEvent<HTMLButtonElement>) => {
131+
if (onClose) {
132+
event.stopPropagation();
133+
onClose(event);
136134
}
135+
};
136+
137+
let normalizedDecorator = React.isValidElement(slug ?? decorator)
138+
? (slug ?? decorator)
139+
: null;
140+
if (
141+
normalizedDecorator &&
142+
normalizedDecorator['type']?.displayName === 'AILabel'
143+
) {
144+
normalizedDecorator = React.cloneElement(
145+
normalizedDecorator as React.ReactElement<any>,
146+
{
147+
size: 'sm',
148+
kind: 'inline',
149+
}
150+
);
151+
}
152+
153+
const tooltipClasses = classNames(
154+
`${prefix}--icon-tooltip`,
155+
`${prefix}--tag-label-tooltip`
137156
);
138-
}
139157

140-
const tooltipClasses = classNames(
141-
`${prefix}--icon-tooltip`,
142-
`${prefix}--tag-label-tooltip`
143-
);
144-
145-
// Removing onClick from the spread operator
146-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
147-
const { onClick, ...otherProps } = other;
148-
149-
const dismissLabel = `Dismiss "${text}"`;
150-
151-
return (
152-
<Tag
153-
ref={tagLabelRef}
154-
type={type}
155-
size={size}
156-
renderIcon={renderIcon}
157-
disabled={disabled}
158-
className={tagClasses}
159-
id={tagId}
160-
{...otherProps}>
161-
<div className={`${prefix}--interactive--tag-children`}>
162-
<Text
163-
title={tagTitle ? tagTitle : text}
164-
className={`${prefix}--tag__label`}>
165-
{text}
166-
</Text>
167-
{slug ? (
168-
normalizedDecorator
169-
) : decorator ? (
170-
<div className={`${prefix}--tag__decorator`}>
171-
{normalizedDecorator}
172-
</div>
173-
) : (
174-
''
175-
)}
176-
<Tooltip
177-
label={isEllipsisApplied ? dismissLabel : title}
178-
align="bottom"
179-
className={tooltipClasses}
180-
leaveDelayMs={0}
181-
closeOnActivation>
182-
<button
183-
type="button"
184-
className={`${prefix}--tag__close-icon`}
185-
onClick={handleClose}
186-
disabled={disabled}
187-
aria-label={title}>
188-
<Close />
189-
</button>
190-
</Tooltip>
191-
</div>
192-
</Tag>
193-
);
194-
};
158+
// Removing onClick from the spread operator
159+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
160+
const { onClick, ...otherProps } = other;
161+
162+
const dismissLabel = `Dismiss "${text}"`;
163+
164+
return (
165+
<Tag
166+
ref={combinedRef}
167+
type={type}
168+
size={size}
169+
renderIcon={renderIcon}
170+
disabled={disabled}
171+
className={tagClasses}
172+
id={tagId}
173+
{...otherProps}>
174+
<div className={`${prefix}--interactive--tag-children`}>
175+
<Text
176+
title={tagTitle ? tagTitle : text}
177+
className={`${prefix}--tag__label`}>
178+
{text}
179+
</Text>
180+
{slug ? (
181+
normalizedDecorator
182+
) : decorator ? (
183+
<div className={`${prefix}--tag__decorator`}>
184+
{normalizedDecorator}
185+
</div>
186+
) : (
187+
''
188+
)}
189+
<Tooltip
190+
label={isEllipsisApplied ? dismissLabel : title}
191+
align="bottom"
192+
className={tooltipClasses}
193+
leaveDelayMs={0}
194+
closeOnActivation>
195+
<button
196+
type="button"
197+
className={`${prefix}--tag__close-icon`}
198+
onClick={handleClose}
199+
disabled={disabled}
200+
aria-label={title}>
201+
<Close />
202+
</button>
203+
</Tooltip>
204+
</div>
205+
</Tag>
206+
);
207+
}
208+
);
195209
DismissibleTag.propTypes = {
196210
/**
197211
* Provide a custom className that is applied to the containing <span>

packages/react/src/components/Tag/OperationalTag.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const OperationalTag = forwardRef(
9494
type = 'gray',
9595
...other
9696
}: OperationalTagProps<T>,
97-
forwardRef: ForwardedRef<HTMLLIElement>
97+
forwardRef: ForwardedRef<HTMLButtonElement>
9898
) => {
9999
const prefix = usePrefix();
100100
const tagRef = useRef<HTMLButtonElement>(null);

0 commit comments

Comments
 (0)