Skip to content

Commit 970f8a3

Browse files
authored
fix: Clear button context provider on TagGroup items so they don't throw when in a CustomDialog (#9051)
* fix: Clear button context provider on TagGroup items so they dont conflict with parent contexts * ugh lint * fix tests? * fix tests * always forget to get rid of console.log new lines
1 parent 02433d1 commit 970f8a3

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

packages/@react-spectrum/s2/src/TagGroup.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
composeRenderProps,
2121
ContextValue,
2222
Provider,
23+
ButtonContext as RACButtonContext,
2324
TextContext as RACTextContext,
2425
TagList,
2526
TagListProps,
@@ -318,20 +319,22 @@ function TagGroupInner<T>({
318319
})}>
319320
{allItems.map(item => {
320321
// pull off individual props as an allow list, don't want refs or other props getting through
322+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
323+
let {ref, ...itemProps} = item.props;
321324
return (
322325
<div
323-
style={item.props.UNSAFE_style}
326+
style={itemProps.UNSAFE_style}
324327
key={item.key}
325-
className={item.props.className({size, allowsRemoving: Boolean(onRemove)})}>
328+
className={itemProps.className({size, allowsRemoving: Boolean(onRemove)})}>
326329
<TagWrapper
327330
key={item.key}
328331
id={item.key}
329332
textValue={item.textValue}
330333
isInRealDOM
331334
size={size}
332335
allowsRemoving={!!onRemove}
333-
{...item.props}
334-
children={item.props.children({size, allowsRemoving: Boolean(onRemove), isInCtx: true})} />
336+
{...itemProps}
337+
children={itemProps.children({size, allowsRemoving: Boolean(onRemove), isInCtx: true})} />
335338
</div>
336339
);
337340
})}
@@ -522,7 +525,10 @@ export const Tag = /*#__PURE__*/ (forwardRef as forwardRefType)(function Tag({ch
522525
function TagWrapper({children, isDisabled, allowsRemoving, isInRealDOM, isEmphasized, isSelected}) {
523526
let {size = 'M'} = useSlottedContext(TagGroupContext) ?? {};
524527
return (
525-
<>
528+
<Provider
529+
values={[
530+
[RACButtonContext, null]
531+
]}>
526532
{isInRealDOM && (
527533
<div
528534
className={style({
@@ -567,6 +573,6 @@ function TagWrapper({children, isDisabled, allowsRemoving, isInRealDOM, isEmphas
567573
isStaticColor={isEmphasized && isSelected}
568574
isDisabled={isDisabled} />
569575
)}
570-
</>
576+
</Provider>
571577
);
572578
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2025 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import {act, pointerMap, render} from '@react-spectrum/test-utils-internal';
14+
import {ActionButton, CustomDialog, DialogTrigger, Tag, TagGroup} from '../src';
15+
import React from 'react';
16+
import userEvent from '@testing-library/user-event';
17+
18+
describe('CustomDialog', () => {
19+
let user;
20+
beforeAll(() => {
21+
jest.useFakeTimers();
22+
user = userEvent.setup({delay: null, pointerMap});
23+
});
24+
25+
afterEach(() => {
26+
jest.clearAllMocks();
27+
act(() => jest.runAllTimers());
28+
});
29+
30+
afterAll(function () {
31+
jest.restoreAllMocks();
32+
});
33+
34+
it('should allow you to render a taggroup inside', async () => {
35+
let {getByRole} = render(
36+
<DialogTrigger>
37+
<ActionButton>Open dialog</ActionButton>
38+
<CustomDialog isDismissible>
39+
<TagGroup
40+
label="Ice cream categories"
41+
maxRows={1}
42+
onRemove={() => {}}>
43+
<Tag>Chocolate</Tag>
44+
<Tag>Mint</Tag>
45+
<Tag>Strawberry</Tag>
46+
<Tag>Vanilla</Tag>
47+
</TagGroup>
48+
</CustomDialog>
49+
</DialogTrigger>
50+
);
51+
52+
let trigger = getByRole('button');
53+
await user.click(trigger);
54+
act(() => {jest.runAllTimers();});
55+
expect(getByRole('dialog')).toBeVisible();
56+
});
57+
});

0 commit comments

Comments
 (0)