Skip to content

Commit 988c120

Browse files
LFDanLudevongovett
andauthored
docs: Update RangeCalendar for api consitency, add docs for nonce, and TagGroup onAction docs (adobe#9910)
* update RangeCalendar interactOutsideBehavior to commitBehavior * nonce docs * modify warning for missing dialog labelling * update taggroup selection docs to include actions * slight change to description copy for clarity * expandable tableview migration update and nits * review comments * add onAction to RAC Tags * add test for onAction set on Tag directly * fix combobox section className type --------- Co-authored-by: Devon Govett <devongovett@gmail.com>
1 parent 21c4dfb commit 988c120

File tree

15 files changed

+127
-43
lines changed

15 files changed

+127
-43
lines changed

packages/@adobe/react-spectrum/test/calendar/RangeCalendar.test.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,14 +1549,14 @@ describe('RangeCalendar', () => {
15491549
jest.setSystemTime(new Date('2025-11-01'));
15501550
});
15511551

1552-
it('should select the last hovered date when interactOutsideBehavior is "select"', async () => {
1552+
it('should select the last hovered date when commitBehavior is "select"', async () => {
15531553
const onChange = jest.fn();
15541554

15551555
let {getByText, getAllByText} = render(
15561556
<RangeCalendar
15571557
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
15581558
onChange={onChange}
1559-
interactOutsideBehavior="select" />
1559+
commitBehavior="select" />
15601560
);
15611561

15621562
await user.click(getByText('25'));
@@ -1568,13 +1568,13 @@ describe('RangeCalendar', () => {
15681568
expect(onChange).toHaveBeenCalledWith({start: new CalendarDate(2025, 11, 20), end: new CalendarDate(2025, 11, 25)});
15691569
});
15701570

1571-
it('should clear the selection when interactOutsideBehavior is "clear"', async () => {
1571+
it('should clear the selection when commitBehavior is "clear"', async () => {
15721572
const onChange = jest.fn();
15731573
let {getByText, getAllByText, getByRole} = render(
15741574
<RangeCalendar
15751575
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
15761576
onChange={onChange}
1577-
interactOutsideBehavior="clear" />
1577+
commitBehavior="clear" />
15781578
);
15791579

15801580
let startCell = getByRole('gridcell', {name: '25'});
@@ -1592,12 +1592,12 @@ describe('RangeCalendar', () => {
15921592
expect(endCell).not.toHaveAttribute('aria-selected');
15931593
});
15941594

1595-
it('should clear the selection when interactOutsideBehavior is "clear" no default selected range', async () => {
1595+
it('should clear the selection when commitBehavior is "clear" no default selected range', async () => {
15961596
const onChange = jest.fn();
15971597
let {getByText, getByRole} = render(
15981598
<RangeCalendar
15991599
onChange={onChange}
1600-
interactOutsideBehavior="clear" />
1600+
commitBehavior="clear" />
16011601
);
16021602

16031603
let startCell = getByRole('gridcell', {name: '25'});
@@ -1614,13 +1614,13 @@ describe('RangeCalendar', () => {
16141614
expect(endCell).not.toHaveAttribute('aria-selected');
16151615
});
16161616

1617-
it('should reset to the initial range when interactOutsideBehavior is "reset"', async () => {
1617+
it('should reset to the initial range when commitBehavior is "reset"', async () => {
16181618
const onChange = jest.fn();
16191619
let {getByText, getAllByText, getByRole} = render(
16201620
<RangeCalendar
16211621
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
16221622
onChange={onChange}
1623-
interactOutsideBehavior="reset" />
1623+
commitBehavior="reset" />
16241624
);
16251625

16261626
let originalStartCell = getByRole('gridcell', {name: '13'});
@@ -1645,13 +1645,13 @@ describe('RangeCalendar', () => {
16451645
expect(originalEndCell).toHaveAttribute('aria-selected', 'true');
16461646
});
16471647

1648-
it('should reset to the initial range when interactOutsideBehavior is "reset" (controlled value)', async () => {
1648+
it('should reset to the initial range when commitBehavior is "reset" (controlled value)', async () => {
16491649
const onChange = jest.fn();
16501650
let {getByText, getAllByText, getByRole} = render(
16511651
<RangeCalendar
16521652
value={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
16531653
onChange={onChange}
1654-
interactOutsideBehavior="reset" />
1654+
commitBehavior="reset" />
16551655
);
16561656

16571657
let originalStartCell = getByRole('gridcell', {name: '13'});
@@ -1673,13 +1673,13 @@ describe('RangeCalendar', () => {
16731673
});
16741674

16751675
describe('blur (e.g. tabbing away)', () => {
1676-
it('should select the hovered range when interactOutsideBehavior is "select" and calendar blurs', async () => {
1676+
it('should select the hovered range when commitBehavior is "select" and calendar blurs', async () => {
16771677
const onChange = jest.fn();
16781678
let {getByText, getByRole} = render(
16791679
<RangeCalendar
16801680
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
16811681
onChange={onChange}
1682-
interactOutsideBehavior="select" />
1682+
commitBehavior="select" />
16831683
);
16841684

16851685
let startCell = getByRole('gridcell', {name: '13'});
@@ -1701,13 +1701,13 @@ describe('RangeCalendar', () => {
17011701
expect(newEndCell).toHaveAttribute('aria-selected', 'true');
17021702
});
17031703

1704-
it('should clear the selection when interactOutsideBehavior is "clear" and calendar blurs', async () => {
1704+
it('should clear the selection when commitBehavior is "clear" and calendar blurs', async () => {
17051705
const onChange = jest.fn();
17061706
let {getByText, getByRole} = render(
17071707
<RangeCalendar
17081708
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
17091709
onChange={onChange}
1710-
interactOutsideBehavior="clear" />
1710+
commitBehavior="clear" />
17111711
);
17121712

17131713
let startCell = getByRole('gridcell', {name: '13'});
@@ -1727,13 +1727,13 @@ describe('RangeCalendar', () => {
17271727
expect(newEndCell).not.toHaveAttribute('aria-selected', 'true');
17281728
});
17291729

1730-
it('should reset to the initial range when interactOutsideBehavior is "reset" and calendar blurs', async () => {
1730+
it('should reset to the initial range when commitBehavior is "reset" and calendar blurs', async () => {
17311731
const onChange = jest.fn();
17321732
let {getByText, getByRole} = render(
17331733
<RangeCalendar
17341734
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
17351735
onChange={onChange}
1736-
interactOutsideBehavior="reset" />
1736+
commitBehavior="reset" />
17371737
);
17381738

17391739
let originalStartCell = getByRole('gridcell', {name: '13'});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ export function ComboBoxItem(props: ComboBoxItemProps): ReactNode {
432432
);
433433
}
434434

435-
export interface ComboBoxSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, keyof GlobalDOMAttributes> {}
435+
export interface ComboBoxSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes> {}
436436
export function ComboBoxSection<T extends object>(props: ComboBoxSectionProps<T>): ReactNode {
437437
let {size} = useContext(InternalComboboxContext);
438438
return (

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps';
3535

3636
export interface DateRangePickerProps<T extends DateValue> extends
3737
Omit<AriaDateRangePickerProps<T>, 'children' | 'className' | 'style' | 'render' | keyof GlobalDOMAttributes>,
38-
Pick<RangeCalendarProps<T>, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable' | 'interactOutsideBehavior'>,
38+
Pick<RangeCalendarProps<T>, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable' | 'commitBehavior'>,
3939
Pick<PopoverProps, 'shouldFlip'>,
4040
StyleProps,
4141
SpectrumLabelableProps,
@@ -80,7 +80,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
8080
placeholderValue,
8181
maxVisibleMonths = 1,
8282
createCalendar,
83-
interactOutsideBehavior,
83+
commitBehavior,
8484
...dateFieldProps
8585
} = props;
8686
let formContext = useContext(FormContext);
@@ -155,7 +155,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
155155
<RangeCalendar
156156
visibleMonths={maxVisibleMonths}
157157
createCalendar={createCalendar}
158-
interactOutsideBehavior={interactOutsideBehavior}
158+
commitBehavior={commitBehavior}
159159
errorMessage={resolvedErrorMessage} />
160160
{showTimeField && (
161161
<div className={style({display: 'flex', gap: 16, contain: 'inline-size', marginTop: 24})}>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ function DefaultProvider({context, value, children}: {context: React.Context<any
740740
return <context.Provider value={value}>{children}</context.Provider>;
741741
}
742742

743-
export interface PickerSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes>, StyleProps {}
743+
export interface PickerSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes> {}
744744
export function PickerSection<T extends object>(props: PickerSectionProps<T>): ReactNode {
745745
let {size} = useContext(InternalPickerContext);
746746
return (

packages/@react-spectrum/s2/style/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export type {StyleString} from './types';
2828
*
2929
* @example
3030
* ```tsx
31-
* import {space} from '@react-spectrum/s2/style' with {type: 'macro'};
31+
* import {space, style} from '@react-spectrum/s2/style' with {type: 'macro'};
3232
*
3333
* const styles = style({
3434
* gap: space(12) // 12/16 = 0.75rem
@@ -49,7 +49,7 @@ export function space(px: number): `[${string}]` {
4949
*
5050
* @example
5151
* ```tsx
52-
* import {fontRelative} from '@react-spectrum/s2/style' with {type: 'macro'};
52+
* import {fontRelative, style} from '@react-spectrum/s2/style' with {type: 'macro'};
5353
*
5454
* const styles = style({
5555
* gap: fontRelative(2) // 2/14 = ~0.143em
@@ -135,7 +135,7 @@ const iconSizes = {
135135
* ```tsx
136136
* import {iconStyle} from '@react-spectrum/s2/style' with {type: 'macro'};
137137
* import Edit from '@react-spectrum/s2/icons/Edit';
138-
*
138+
*
139139
* <Edit styles={iconStyle({size: 'XL', color: 'positive'})} />
140140
* ```
141141
*/

packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ export const description = 'Displays one or more date grids and allows users to
2121
component={VanillaRangeCalendar}
2222
docs={vanillaDocs.exports.RangeCalendar}
2323
links={vanillaDocs.links}
24-
props={['isDisabled', 'interactOutsideBehavior']}
24+
props={['isDisabled', 'commitBehavior']}
2525
type="vanilla"
2626
files={["starters/docs/src/RangeCalendar.tsx", "starters/docs/src/RangeCalendar.css"]} />
2727
<VisualExample
2828
component={TailwindRangeCalendar}
2929
docs={vanillaDocs.exports.RangeCalendar}
3030
links={vanillaDocs.links}
31-
props={['isDisabled', 'interactOutsideBehavior']}
31+
props={['isDisabled', 'commitBehavior']}
3232
type="tailwind"
3333
files={["starters/tailwind/src/RangeCalendar.tsx"]} />
3434
</ExampleSwitcher>

packages/dev/s2-docs/pages/react-aria/TagGroup.mdx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ import {TagGroup, Tag} from 'vanilla-starter/TagGroup';
101101
<Content>Due to [HTML spec limitations](https://github.com/w3c/html-aria/issues/473), tags cannot be rendered as `<a>` elements. React Aria handles link clicks with JavaScript and triggers native navigation. When using a client-side router, use the `onAction` event to programmatically trigger navigation instead of the `href` prop.</Content>
102102
</InlineAlert>
103103

104-
## Selection
104+
## Selection and actions
105105

106106
Use the `selectionMode` prop to enable single or multiple selection. The selected items can be controlled via the `selectedKeys` prop, matching the `id` prop of the items. Items can be disabled with the `isDisabled` prop. See the [selection guide](selection?component=TagGroup) for more details.
107107

@@ -137,6 +137,30 @@ function Example(props) {
137137
}
138138
```
139139

140+
Use the `onAction` prop to handle item actions.
141+
142+
```tsx render wide
143+
"use client";
144+
import {TagGroup, Tag} from 'vanilla-starter/TagGroup';
145+
146+
function Example() {
147+
return (
148+
<TagGroup
149+
label="Music genres"
150+
///- begin highlight -///
151+
onAction={key => alert(`Clicked ${key}`)}
152+
///- end highlight -///
153+
>
154+
<Tag id="rock">Rock</Tag>
155+
<Tag id="jazz">Jazz</Tag>
156+
<Tag id="pop">Pop</Tag>
157+
<Tag id="classical">Classical</Tag>
158+
<Tag id="edm">EDM</Tag>
159+
</TagGroup>
160+
);
161+
}
162+
```
163+
140164
## Examples
141165

142166
<ExampleList tag="taggroup" pages={props.pages} />

packages/dev/s2-docs/pages/react-aria/frameworks.mdx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ export const description = 'How to integrate with your framework.';
7373
}
7474
```
7575
</Step>
76+
<Step>
77+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `<meta property="csp-nonce">` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag.
78+
</Step>
7679
</StepList>
7780
</TabPanel>
7881
<TabPanel id="react-router">
@@ -184,6 +187,9 @@ export const description = 'How to integrate with your framework.';
184187
});
185188
```
186189
</Step>
190+
<Step>
191+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `<meta property="csp-nonce">` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag.
192+
</Step>
187193
</StepList>
188194
</TabPanel>
189195
<TabPanel id="parcel">
@@ -213,6 +219,9 @@ export const description = 'How to integrate with your framework.';
213219
}
214220
```
215221
</Step>
222+
<Step>
223+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `<meta property="csp-nonce">` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag.
224+
</Step>
216225
</StepList>
217226
</TabPanel>
218227
<TabPanel id="vite">
@@ -243,6 +252,9 @@ export const description = 'How to integrate with your framework.';
243252
});
244253
```
245254
</Step>
255+
<Step>
256+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, configure [`html.cspNonce`](https://vite.dev/config/shared-options.html#html-cspnonce) in `vite.config.ts`. React Aria automatically reads the nonce that Vite injects.
257+
</Step>
246258
</StepList>
247259
</TabPanel>
248260
<TabPanel id="webpack">
@@ -270,6 +282,9 @@ export const description = 'How to integrate with your framework.';
270282
};
271283
```
272284
</Step>
285+
<Step>
286+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, configure [`__webpack_nonce__`](https://webpack.js.org/guides/csp/) in your entry script. React Aria automatically reads the nonce from the webpack global.
287+
</Step>
273288
</StepList>
274289
</TabPanel>
275290
<TabPanel id="rollup">
@@ -297,6 +312,9 @@ export const description = 'How to integrate with your framework.';
297312
};
298313
```
299314
</Step>
315+
<Step>
316+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `<meta property="csp-nonce">` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag.
317+
</Step>
300318
</StepList>
301319
</TabPanel>
302320
<TabPanel id="esbuild">
@@ -324,6 +342,9 @@ export const description = 'How to integrate with your framework.';
324342
});
325343
```
326344
</Step>
345+
<Step>
346+
<Counter />If you are using a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) with a nonce, add a `<meta property="csp-nonce">` tag to your document head, setting the `content` attribute to the generated nonce value. React Aria automatically reads the nonce from this tag.
347+
</Step>
327348
</StepList>
328349
</TabPanel>
329350
</Tabs>

packages/dev/s2-docs/pages/s2/RangeCalendar.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const description = 'Allows a user to select a contiguous range of dates.
1515
component={RangeCalendar}
1616
docs={docs.exports.RangeCalendar}
1717
links={docs.links}
18-
props={['visibleMonths', 'pageBehavior', 'firstDayOfWeek', 'isDisabled', 'interactOutsideBehavior']}
18+
props={['visibleMonths', 'pageBehavior', 'firstDayOfWeek', 'isDisabled', 'commitBehavior']}
1919
initialProps={{'aria-label': 'Trip dates'}}
2020
controlOptions={{
2121
visibleMonths: {

packages/dev/s2-docs/pages/s2/TagGroup.mdx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ import {Link} from '@react-spectrum/s2/Link';
201201
</TagGroup>
202202
```
203203

204-
## Selection
204+
## Selection and actions
205205

206206
Use the `selectionMode` prop to enable single or multiple selection. The selected items can be controlled via the `selectedKeys` prop, matching the `id` prop of the items. Items can be disabled with the `isDisabled` prop. See the [selection guide](selection?component=TagGroup) for more details.
207207

@@ -235,6 +235,30 @@ function Example(props) {
235235
}
236236
```
237237

238+
Use the `onAction` prop to handle item actions.
239+
240+
```tsx render wide
241+
"use client";
242+
import {TagGroup, Tag} from '@react-spectrum/s2/TagGroup';
243+
244+
function Example() {
245+
return (
246+
<TagGroup
247+
label="Music genre"
248+
///- begin highlight -///
249+
onAction={key => alert(`Clicked ${key}`)}
250+
///- end highlight -///
251+
>
252+
<Tag id="rock">Rock</Tag>
253+
<Tag id="jazz">Jazz</Tag>
254+
<Tag id="pop">Pop</Tag>
255+
<Tag id="classical">Classical</Tag>
256+
<Tag id="edm">EDM</Tag>
257+
</TagGroup>
258+
);
259+
}
260+
```
261+
238262

239263
## Group actions
240264

0 commit comments

Comments
 (0)