Skip to content

Commit 3b53af0

Browse files
committed
Add example with TagGroup
1 parent 47a3fca commit 3b53af0

File tree

5 files changed

+47
-9
lines changed

5 files changed

+47
-9
lines changed

packages/react-aria-components/src/Select.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import {AriaSelectProps, HiddenSelect, useFocusRing, useListFormatter, useLocalizedStringFormatter, useSelect} from 'react-aria';
1414
import {ButtonContext} from './Button';
1515
import {Collection, Node, SelectState, useSelectState} from 'react-stately';
16-
import {CollectionBuilder} from '@react-aria/collections';
16+
import {CollectionBuilder, createHideableComponent} from '@react-aria/collections';
1717
import {ContextValue, Provider, RACValidation, removeDataAttributes, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
1818
import {FieldErrorContext} from './FieldError';
1919
import {filterDOMProps, mergeProps, useResizeObserver} from '@react-aria/utils';
@@ -238,7 +238,9 @@ export interface SelectValueRenderProps<T> {
238238
/** The object values of the currently selected items. */
239239
selectedItems: (T | null)[],
240240
/** The textValue of the currently selected items. */
241-
selectedText: string
241+
selectedText: string,
242+
/** The state of the select. */
243+
state: SelectState<T, 'single' | 'multiple'>
242244
}
243245

244246
export interface SelectValueProps<T extends object> extends Omit<HTMLAttributes<HTMLElement>, keyof RenderProps<unknown>>, RenderProps<SelectValueRenderProps<T>> {}
@@ -249,9 +251,9 @@ export const SelectValueContext = createContext<ContextValue<SelectValueProps<an
249251
* SelectValue renders the current value of a Select, or a placeholder if no value is selected.
250252
* It is usually placed within the button element.
251253
*/
252-
export const SelectValue = /*#__PURE__*/ (forwardRef as forwardRefType)(function SelectValue<T extends object>(props: SelectValueProps<T>, ref: ForwardedRef<HTMLSpanElement>) {
254+
export const SelectValue = /*#__PURE__*/ createHideableComponent(function SelectValue<T extends object>(props: SelectValueProps<T>, ref: ForwardedRef<HTMLSpanElement>) {
253255
[props, ref] = useContextProps(props, ref, SelectValueContext);
254-
let state = useContext(SelectStateContext)!;
256+
let state = useContext(SelectStateContext)! as SelectState<T, 'single' | 'multiple'>;
255257
let {placeholder} = useSlottedContext(SelectContext)!;
256258
let rendered = state.selectedItems.map((item) => {
257259
let rendered = item.props?.children;
@@ -312,7 +314,8 @@ export const SelectValue = /*#__PURE__*/ (forwardRef as forwardRefType)(function
312314
selectedItem: state.selectedItems[0]?.value as T ?? null,
313315
selectedItems: useMemo(() => state.selectedItems.map(item => item.value as T ?? null), [state.selectedItems]),
314316
selectedText,
315-
isPlaceholder: state.selectedItems.length === 0
317+
isPlaceholder: state.selectedItems.length === 0,
318+
state
316319
}
317320
});
318321

packages/react-aria-components/src/TagGroup.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ export const TagListContext = createContext<ContextValue<TagListProps<any>, HTML
6161
export const TagGroup = /*#__PURE__*/ (forwardRef as forwardRefType)(function TagGroup(props: TagGroupProps, ref: ForwardedRef<HTMLDivElement>) {
6262
[props, ref] = useContextProps(props, ref, TagGroupContext);
6363
return (
64-
<CollectionBuilder content={props.children}>
65-
{collection => <TagGroupInner props={props} forwardedRef={ref} collection={collection} />}
66-
</CollectionBuilder>
64+
<ListStateContext.Provider value={null}>
65+
<CollectionBuilder content={props.children}>
66+
{collection => <TagGroupInner props={props} forwardedRef={ref} collection={collection} />}
67+
</CollectionBuilder>
68+
</ListStateContext.Provider>
6769
);
6870
});
6971

packages/react-aria-components/stories/Select.stories.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {LoadingSpinner, MyListBoxItem} from './utils';
1616
import {Meta, StoryFn, StoryObj} from '@storybook/react';
1717
import React, {JSX} from 'react';
1818
import styles from '../example/index.css';
19+
import {Tag, TagGroup} from 'vanilla-starter/TagGroup';
1920
import {useAsyncList} from 'react-stately';
2021
import './styles.css';
2122

@@ -83,6 +84,35 @@ export const SelectRenderProps: SelectStory = (args) => (
8384
</Select>
8485
);
8586

87+
export const SelectWithTagGroup: SelectStory = (args) => (
88+
<Select {...args} data-testid="select-example" id="select-example-id">
89+
<Label style={{display: 'block'}}>States</Label>
90+
<div style={{display: 'flex', gap: 8, alignItems: 'start', maxWidth: 250}}>
91+
<SelectValue>
92+
{({selectedItems, state}) => (
93+
<TagGroup
94+
aria-label="Selected states"
95+
items={selectedItems as {name: string}[]}
96+
renderEmptyState={() => 'No selected items'}
97+
onRemove={(keys) => {
98+
for (let key of keys) {
99+
state.selectionManager.toggleSelection(key);
100+
}
101+
}}>
102+
{item => <Tag>{item.name}</Tag>}
103+
</TagGroup>
104+
)}
105+
</SelectValue>
106+
<Button>+</Button>
107+
</div>
108+
<Popover placement="bottom end">
109+
<ListBox className={styles.menu} items={usStateOptions}>
110+
{state => <MyListBoxItem>{state.name}</MyListBoxItem>}
111+
</ListBox>
112+
</Popover>
113+
</Select>
114+
);
115+
86116
let makeItems = (length: number) => Array.from({length}, (_, i) => ({
87117
id: i,
88118
name: `Item ${i}`

starters/docs/src/TagGroup.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
display: flex;
2727
align-items: center;
2828
transition: border-color 200ms;
29+
white-space: nowrap;
30+
overflow: hidden;
31+
text-overflow: ellipsis;
2932

3033
&[data-hovered] {
3134
border-color: var(--border-color-hover);

starters/docs/src/TagGroup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function TagGroup<T extends object>(
3636
return (
3737
(
3838
<AriaTagGroup {...props}>
39-
<Label>{label}</Label>
39+
{label && <Label>{label}</Label>}
4040
<TagList items={items} renderEmptyState={renderEmptyState}>
4141
{children}
4242
</TagList>

0 commit comments

Comments
 (0)