Skip to content

Commit 16cbaf2

Browse files
TagGroup beta updates (#3692)
1 parent 3541651 commit 16cbaf2

File tree

8 files changed

+56
-217
lines changed

8 files changed

+56
-217
lines changed

packages/@react-aria/tag/src/TagKeyboardDelegate.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,15 @@ export class TagKeyboardDelegate<T> extends GridKeyboardDelegate<T, GridCollecti
1818
getFirstKey() {
1919
let key = this.collection.getFirstKey();
2020
let item = this.collection.getItem(key);
21-
let newKey = [...item.childNodes][0].key;
2221

23-
if (this.disabledKeys.has(newKey)) {
24-
newKey = this.getKeyBelow(newKey);
25-
}
26-
return newKey;
22+
return [...item.childNodes][0].key;
2723
}
2824

2925
getLastKey() {
3026
let key = this.collection.getLastKey();
3127
let item = this.collection.getItem(key);
32-
let newKey = [...item.childNodes][0].key;
3328

34-
if (this.disabledKeys.has(newKey)) {
35-
newKey = this.getKeyAbove(newKey);
36-
}
37-
return newKey;
29+
return [...item.childNodes][0].key;
3830
}
3931

4032
getKeyRightOf(key: Key) {
@@ -62,13 +54,8 @@ export class TagKeyboardDelegate<T> extends GridKeyboardDelegate<T, GridCollecti
6254
// If focus was on a cell, focus the cell with the same index in the next row.
6355
if (this.isCell(startItem)) {
6456
let item = this.collection.getItem(key);
65-
let newKey = [...item.childNodes][startItem.index].key;
6657

67-
// Ignore disabled tags
68-
if (this.disabledKeys.has(newKey)) {
69-
return this.getKeyBelow(newKey);
70-
}
71-
return newKey;
58+
return [...item.childNodes][startItem.index].key;
7259
}
7360

7461
// Otherwise, focus the next row
@@ -97,13 +84,7 @@ export class TagKeyboardDelegate<T> extends GridKeyboardDelegate<T, GridCollecti
9784
// If focus was on a cell, focus the cell with the same index in the previous row.
9885
if (this.isCell(startItem)) {
9986
let item = this.collection.getItem(key);
100-
let newKey = [...item.childNodes][startItem.index].key;
101-
102-
// ignore disabled tags
103-
if (this.disabledKeys.has(newKey)) {
104-
return this.getKeyAbove(newKey);
105-
}
106-
return newKey;
87+
return [...item.childNodes][startItem.index].key;
10788
}
10889

10990
// Otherwise, focus the previous row

packages/@react-aria/tag/src/useTag.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@ export interface TagAria {
3131
export function useTag(props: TagProps<any>, state: GridState<any, any>): TagAria {
3232
let {isFocused} = props;
3333
const {
34-
isDisabled,
35-
isRemovable,
34+
allowsRemoving,
3635
onRemove,
37-
children,
3836
item,
3937
tagRef,
4038
tagRowRef
@@ -56,14 +54,14 @@ export function useTag(props: TagProps<any>, state: GridState<any, any>): TagAri
5654
focusMode: 'cell'
5755
}, state, tagRef);
5856

59-
function onKeyDown(e: KeyboardEvent<Element>) {
57+
function onKeyDown(e: KeyboardEvent) {
6058
if (e.key === 'Delete' || e.key === 'Backspace' || e.key === ' ') {
61-
onRemove(children, e);
59+
onRemove(item.childNodes[0].key);
6260
e.preventDefault();
6361
}
6462
}
6563
const pressProps = {
66-
onPress: e => onRemove?.(children, e)
64+
onPress: () => onRemove?.(item.childNodes[0].key)
6765
};
6866

6967
isFocused = isFocused || state.selectionManager.focusedKey === item.childNodes[0].key;
@@ -72,19 +70,17 @@ export function useTag(props: TagProps<any>, state: GridState<any, any>): TagAri
7270
clearButtonProps: mergeProps(pressProps, {
7371
'aria-label': removeString,
7472
'aria-labelledby': `${buttonId} ${labelId}`,
75-
id: buttonId,
76-
isDisabled
73+
id: buttonId
7774
}),
7875
labelProps: {
7976
id: labelId
8077
},
8178
tagRowProps: otherRowProps,
8279
tagProps: mergeProps(domProps, gridCellProps, {
83-
'aria-disabled': isDisabled,
8480
'aria-errormessage': props['aria-errormessage'],
8581
'aria-label': props['aria-label'],
86-
onKeyDown: !isDisabled && isRemovable ? onKeyDown : null,
87-
tabIndex: (isFocused || state.selectionManager.focusedKey == null) && !isDisabled ? 0 : -1
82+
onKeyDown: allowsRemoving ? onKeyDown : null,
83+
tabIndex: (isFocused || state.selectionManager.focusedKey == null) ? 0 : -1
8884
})
8985
};
9086
}

packages/@react-aria/tag/src/useTagGroup.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@
1212

1313
import {DOMAttributes, DOMProps} from '@react-types/shared';
1414
import {filterDOMProps, mergeProps} from '@react-aria/utils';
15-
import {Key, ReactNode, useState} from 'react';
15+
import {ReactNode, useState} from 'react';
1616
import {useFocusWithin} from '@react-aria/interactions';
1717

1818
export interface AriaTagGroupProps extends DOMProps {
1919
children: ReactNode,
20-
disabledKeys?: Iterable<Key>,
21-
isDisabled?: boolean,
2220
isReadOnly?: boolean, // removes close button
2321
validationState?: 'valid' | 'invalid'
2422
}
@@ -27,23 +25,17 @@ export interface TagGroupAria {
2725
tagGroupProps: DOMAttributes
2826
}
2927

30-
export function useTagGroup(props: AriaTagGroupProps, listState): TagGroupAria {
31-
let {isDisabled} = props;
28+
export function useTagGroup(props: AriaTagGroupProps): TagGroupAria {
3229
let [isFocusWithin, setFocusWithin] = useState(false);
3330
let {focusWithinProps} = useFocusWithin({
3431
onFocusWithinChange: setFocusWithin
3532
});
36-
let allKeys = [...listState.collection.getKeys()];
37-
if (!allKeys.some(key => !listState.disabledKeys.has(key))) {
38-
isDisabled = true;
39-
}
4033
let domProps = filterDOMProps(props);
4134
return {
4235
tagGroupProps: mergeProps(domProps, {
4336
'aria-atomic': false,
4437
'aria-relevant': 'additions',
4538
'aria-live': isFocusWithin ? 'polite' : 'off',
46-
'aria-disabled': isDisabled === true,
4739
...focusWithinProps
4840
} as DOMAttributes)
4941
};

packages/@react-spectrum/tag/src/Tag.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ import {useTag} from '@react-aria/tag';
2424
export function Tag<T>(props: SpectrumTagProps<T>) {
2525
const {
2626
children,
27-
isDisabled,
28-
isRemovable,
27+
allowsRemoving,
2928
item,
3029
state,
3130
onRemove,
@@ -34,15 +33,14 @@ export function Tag<T>(props: SpectrumTagProps<T>) {
3433

3534
// @ts-ignore
3635
let {styleProps} = useStyleProps(otherProps);
37-
let {hoverProps, isHovered} = useHover({isDisabled});
36+
let {hoverProps, isHovered} = useHover({});
3837
let {isFocused, isFocusVisible, focusProps} = useFocusRing({within: true});
3938
let tagRef = useRef();
4039
let tagRowRef = useRef();
4140
let {clearButtonProps, labelProps, tagProps, tagRowProps} = useTag({
4241
...props,
43-
isDisabled,
4442
isFocused,
45-
isRemovable,
43+
allowsRemoving,
4644
item,
4745
onRemove,
4846
tagRef,
@@ -59,10 +57,8 @@ export function Tag<T>(props: SpectrumTagProps<T>) {
5957
styles,
6058
'spectrum-Tags-item',
6159
{
62-
'is-disabled': isDisabled,
6360
'focus-ring': isFocusVisible,
6461
'is-focused': isFocused,
65-
'not-removable': !isRemovable,
6662
'is-hovered': isHovered
6763
},
6864
styleProps.className
@@ -71,11 +67,11 @@ export function Tag<T>(props: SpectrumTagProps<T>) {
7167
<SlotProvider
7268
slots={{
7369
icon: {UNSAFE_className: classNames(styles, 'spectrum-Tag-icon'), size: 'XS'},
74-
text: {UNSAFE_className: classNames(styles, 'spectrum-Tag-content', {'tags-removable': isRemovable}), ...labelProps}
70+
text: {UNSAFE_className: classNames(styles, 'spectrum-Tag-content', {'tags-removable': allowsRemoving}), ...labelProps}
7571
}}>
7672

7773
{typeof children === 'string' ? <Text>{children}</Text> : children}
78-
{isRemovable && <TagRemoveButton item={item} {...clearButtonProps} UNSAFE_className={classNames(styles, 'spectrum-Tag-action')} />}
74+
{allowsRemoving && <TagRemoveButton item={item} {...clearButtonProps} UNSAFE_className={classNames(styles, 'spectrum-Tag-action')} />}
7975
</SlotProvider>
8076
</div>
8177
</div>

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

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ import {useProviderProps} from '@react-spectrum/provider';
2828
function TagGroup<T extends object>(props: SpectrumTagGroupProps<T>, ref: DOMRef<HTMLDivElement>) {
2929
props = useProviderProps(props);
3030
let {
31-
isDisabled,
32-
isRemovable,
31+
allowsRemoving,
3332
onRemove,
3433
...otherProps
3534
} = props;
@@ -52,15 +51,15 @@ function TagGroup<T extends object>(props: SpectrumTagGroupProps<T>, ref: DOMRef
5251
};
5352
})
5453
// eslint-disable-next-line react-hooks/exhaustive-deps
55-
}), [listState.collection, isRemovable]);
54+
}), [listState.collection, allowsRemoving]);
5655
let state = useGridState({
5756
...props,
5857
collection: gridCollection,
5958
focusMode: 'cell'
6059
});
6160
let keyboardDelegate = new TagKeyboardDelegate({
6261
collection: state.collection,
63-
disabledKeys: state.disabledKeys,
62+
disabledKeys: new Set(),
6463
ref: domRef,
6564
direction,
6665
focusMode: 'cell'
@@ -69,7 +68,7 @@ function TagGroup<T extends object>(props: SpectrumTagGroupProps<T>, ref: DOMRef
6968
...props,
7069
keyboardDelegate
7170
}, state, domRef);
72-
const {tagGroupProps} = useTagGroup(props, listState);
71+
const {tagGroupProps} = useTagGroup(props);
7372

7473
// Don't want the grid to be focusable or accessible via keyboard
7574
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -81,9 +80,6 @@ function TagGroup<T extends object>(props: SpectrumTagGroupProps<T>, ref: DOMRef
8180
classNames(
8281
styles,
8382
'spectrum-Tags',
84-
{
85-
'is-disabled': isDisabled
86-
},
8783
styleProps.className
8884
)
8985
}
@@ -95,8 +91,7 @@ function TagGroup<T extends object>(props: SpectrumTagGroupProps<T>, ref: DOMRef
9591
key={item.key}
9692
item={item}
9793
state={state}
98-
isDisabled={isDisabled || state.disabledKeys.has(item?.childNodes[0]?.key)}
99-
isRemovable={isRemovable}
94+
allowsRemoving={allowsRemoving}
10095
onRemove={onRemove}>
10196
{item.childNodes[0].rendered}
10297
</Tag>

packages/@react-spectrum/tag/stories/TagGroup.stories.tsx

Lines changed: 23 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {action} from '@storybook/addon-actions';
1414
import Audio from '@spectrum-icons/workflow/Audio';
1515
import {Icon} from '@react-spectrum/icon';
1616
import {Item, TagGroup} from '../src';
17-
import React from 'react';
17+
import React, {useState} from 'react';
1818
import {storiesOf} from '@storybook/react';
1919
import {Text} from '@react-spectrum/text';
2020

@@ -23,11 +23,6 @@ storiesOf('TagGroup', module)
2323
'default',
2424
() => render({})
2525
)
26-
.add(
27-
'disabledKeys',
28-
() => render({
29-
disabledKeys: ['1']
30-
}))
3126
.add('icons', () => (
3227
<TagGroup aria-label="tag group" items={[{key: '1', label: 'Cool Tag 1'}, {key: '2', label: 'Cool Tag 2'}]}>
3328
{item => (
@@ -40,33 +35,29 @@ storiesOf('TagGroup', module)
4035
)}
4136
</TagGroup>
4237
))
43-
.add(
44-
'isDisabled',
45-
() => render({
46-
isDisabled: true
47-
}))
4838
.add(
4939
'onRemove',
50-
() => render({
51-
isRemovable: true,
52-
onRemove: action('onRemove')
53-
})
54-
)
55-
.add(
56-
'onRemove + disabledKeys',
57-
() => render({
58-
disabledKeys: ['2'],
59-
isRemovable: true,
60-
onRemove: action('onRemove')
61-
})
62-
)
63-
.add(
64-
'onRemove + isDisabled',
65-
() => render({
66-
isDisabled: true,
67-
isRemovable: true,
68-
onRemove: action('onRemove')
69-
})
40+
() => {
41+
const [items, setItems] = useState([
42+
{key: 1, label: 'Cool Tag 1'},
43+
{key: 2, label: 'Another cool tag'},
44+
{key: 3, label: 'This tag'},
45+
{key: 4, label: 'What tag?'},
46+
{key: 5, label: 'This tag is cool too'},
47+
{key: 6, label: 'Shy tag'}
48+
]);
49+
const onRemove = (key) => {
50+
const newItems = [...items].filter((item) => key !== item.key.toString());
51+
setItems(newItems);
52+
action('onRemove')(key);
53+
};
54+
55+
return (<TagGroup allowsRemoving aria-label="tag group" items={items} onRemove={key => onRemove(key)}>
56+
{item => (
57+
<Item key={item.key}>{item.label}</Item>
58+
)}
59+
</TagGroup>);
60+
}
7061
)
7162
.add('wrapping', () => (
7263
<div style={{width: '200px'}}>
@@ -81,7 +72,7 @@ storiesOf('TagGroup', module)
8172
</div>
8273
)
8374
)
84-
.add('truncation', () => (
75+
.add('label truncation', () => (
8576
<div style={{width: '100px'}}>
8677
<TagGroup aria-label="tag group">
8778
<Item key="1">Cool Tag 1 with a really long label</Item>
@@ -100,12 +91,6 @@ storiesOf('TagGroup', module)
10091
}
10192
</TagGroup>
10293
)
103-
)
104-
.add(
105-
'with announcing',
106-
() => (
107-
<WithAnnouncing />
108-
)
10994
);
11095

11196
function render(props: any = {}) {
@@ -118,14 +103,3 @@ function render(props: any = {}) {
118103
);
119104
}
120105

121-
function WithAnnouncing() {
122-
let tags = ['Testing tag', 'Other testing label'];
123-
124-
return (
125-
<React.Fragment>
126-
<TagGroup aria-label="tag group">
127-
{tags.map((t, index) => <Item key={index}>{t}</Item>)}
128-
</TagGroup>
129-
</React.Fragment>
130-
);
131-
}

0 commit comments

Comments
 (0)