Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions packages/@adobe/react-spectrum/test/calendar/RangeCalendar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1549,14 +1549,14 @@ describe('RangeCalendar', () => {
jest.setSystemTime(new Date('2025-11-01'));
});

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

let {getByText, getAllByText} = render(
<RangeCalendar
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
onChange={onChange}
interactOutsideBehavior="select" />
commitBehavior="select" />
);

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

it('should clear the selection when interactOutsideBehavior is "clear"', async () => {
it('should clear the selection when commitBehavior is "clear"', async () => {
const onChange = jest.fn();
let {getByText, getAllByText, getByRole} = render(
<RangeCalendar
defaultValue={{start: new CalendarDate(2025, 11, 13), end: new CalendarDate(2025, 11, 15)}}
onChange={onChange}
interactOutsideBehavior="clear" />
commitBehavior="clear" />
);

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

it('should clear the selection when interactOutsideBehavior is "clear" no default selected range', async () => {
it('should clear the selection when commitBehavior is "clear" no default selected range', async () => {
const onChange = jest.fn();
let {getByText, getByRole} = render(
<RangeCalendar
onChange={onChange}
interactOutsideBehavior="clear" />
commitBehavior="clear" />
);

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

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

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

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

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

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

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

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

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

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

let originalStartCell = getByRole('gridcell', {name: '13'});
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-spectrum/s2/src/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ export function ComboBoxItem(props: ComboBoxItemProps): ReactNode {
);
}

export interface ComboBoxSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, keyof GlobalDOMAttributes> {}
export interface ComboBoxSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes> {}
export function ComboBoxSection<T extends object>(props: ComboBoxSectionProps<T>): ReactNode {
let {size} = useContext(InternalComboboxContext);
return (
Expand Down
6 changes: 3 additions & 3 deletions packages/@react-spectrum/s2/src/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps';

export interface DateRangePickerProps<T extends DateValue> extends
Omit<AriaDateRangePickerProps<T>, 'children' | 'className' | 'style' | 'render' | keyof GlobalDOMAttributes>,
Pick<RangeCalendarProps<T>, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable' | 'interactOutsideBehavior'>,
Pick<RangeCalendarProps<T>, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable' | 'commitBehavior'>,
Pick<PopoverProps, 'shouldFlip'>,
StyleProps,
SpectrumLabelableProps,
Expand Down Expand Up @@ -80,7 +80,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
placeholderValue,
maxVisibleMonths = 1,
createCalendar,
interactOutsideBehavior,
commitBehavior,
...dateFieldProps
} = props;
let formContext = useContext(FormContext);
Expand Down Expand Up @@ -155,7 +155,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
<RangeCalendar
visibleMonths={maxVisibleMonths}
createCalendar={createCalendar}
interactOutsideBehavior={interactOutsideBehavior}
commitBehavior={commitBehavior}
errorMessage={resolvedErrorMessage} />
{showTimeField && (
<div className={style({display: 'flex', gap: 16, contain: 'inline-size', marginTop: 24})}>
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-spectrum/s2/src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ function DefaultProvider({context, value, children}: {context: React.Context<any
return <context.Provider value={value}>{children}</context.Provider>;
}

export interface PickerSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes>, StyleProps {}
export interface PickerSectionProps<T extends object> extends Omit<ListBoxSectionProps<T>, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes> {}
export function PickerSection<T extends object>(props: PickerSectionProps<T>): ReactNode {
let {size} = useContext(InternalPickerContext);
return (
Expand Down
7 changes: 4 additions & 3 deletions packages/@react-spectrum/s2/stories/TableView.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ import User from '../s2wf-icons/S2_Icon_User_20_N.svg';
import {useTreeData} from 'react-stately/useTreeData';

let onActionFunc = action('onAction');
let noOnAction = undefined;
let noOnAction = null;
const onActionOptions = {onActionFunc, noOnAction};

const events = ['onResizeStart', 'onResize', 'onResizeEnd', 'onSelectionChange', 'onSortChange'];

const meta: Meta<typeof TableView> = {
Expand All @@ -62,7 +63,7 @@ const meta: Meta<typeof TableView> = {
tags: ['autodocs'],
args: {...getActionArgs(events)},
argTypes: {
...categorizeArgTypes('Events', ['onAction', 'onLoadMore', ...events]),
...categorizeArgTypes('Events', ['onAction', 'onLoadMore', 'onResizeStart', 'onResize', 'onResizeEnd', 'onSelectionChange', 'onSortChange']),
children: {table: {disable: true}},
onAction: {
options: Object.keys(onActionOptions), // An array of serializable values
Expand Down Expand Up @@ -1783,7 +1784,7 @@ export const TableWithNestedRows: StoryObj<typeof TableView> = {
<Cell>5/22/1980</Cell>
</Row>
</Row>
<Row id="apps" isDisabled>
<Row id="apps">
<Cell>Applications</Cell>
<Cell>Folder</Cell>
<Cell>4/7/2025</Cell>
Expand Down
8 changes: 4 additions & 4 deletions packages/@react-spectrum/s2/stories/TreeView.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ import {useAsyncList} from 'react-stately/useAsyncList';
import {useListData} from 'react-stately/useListData';

let onActionFunc = action('onAction');
let noOnAction = undefined;
let noOnAction = null;
const onActionOptions = {onActionFunc, noOnAction};
const events = ['onSelectionChange'];
const events = ['onSelectionChange', 'onAction'];

const meta: Meta<typeof TreeView> = {
component: TreeView,
Expand All @@ -57,7 +57,7 @@ const meta: Meta<typeof TreeView> = {
tags: ['autodocs'],
args: {...getActionArgs(events)},
argTypes: {
...categorizeArgTypes('Events', ['onAction', ...events]),
...categorizeArgTypes('Events', events),
children: {table: {disable: true}},
onAction: {
options: Object.keys(onActionOptions), // An array of serializable values
Expand All @@ -81,7 +81,7 @@ const TreeExampleStatic = (args: TreeViewProps<any>): ReactElement => (
<div style={{width: '300px', resize: 'both', height: '320px', overflow: 'auto'}}>
<TreeView
{...args}
disabledKeys={['projects']}
disabledKeys={['projects-1']}
aria-label="test static tree"
onExpandedChange={action('onExpandedChange')}
onSelectionChange={action('onSelectionChange')}>
Expand Down
6 changes: 3 additions & 3 deletions packages/@react-spectrum/s2/style/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type {StyleString} from './types';
*
* @example
* ```tsx
* import {space} from '@react-spectrum/s2/style' with {type: 'macro'};
* import {space, style} from '@react-spectrum/s2/style' with {type: 'macro'};
*
* const styles = style({
* gap: space(12) // 12/16 = 0.75rem
Expand All @@ -49,7 +49,7 @@ export function space(px: number): `[${string}]` {
*
* @example
* ```tsx
* import {fontRelative} from '@react-spectrum/s2/style' with {type: 'macro'};
* import {fontRelative, style} from '@react-spectrum/s2/style' with {type: 'macro'};
*
* const styles = style({
* gap: fontRelative(2) // 2/14 = ~0.143em
Expand Down Expand Up @@ -135,7 +135,7 @@ const iconSizes = {
* ```tsx
* import {iconStyle} from '@react-spectrum/s2/style' with {type: 'macro'};
* import Edit from '@react-spectrum/s2/icons/Edit';
*
*
* <Edit styles={iconStyle({size: 'XL', color: 'positive'})} />
* ```
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/s2-docs/pages/react-aria/RangeCalendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ export const description = 'Displays one or more date grids and allows users to
component={VanillaRangeCalendar}
docs={vanillaDocs.exports.RangeCalendar}
links={vanillaDocs.links}
props={['isDisabled', 'interactOutsideBehavior']}
props={['isDisabled', 'commitBehavior']}
type="vanilla"
files={["starters/docs/src/RangeCalendar.tsx", "starters/docs/src/RangeCalendar.css"]} />
<VisualExample
component={TailwindRangeCalendar}
docs={vanillaDocs.exports.RangeCalendar}
links={vanillaDocs.links}
props={['isDisabled', 'interactOutsideBehavior']}
props={['isDisabled', 'commitBehavior']}
type="tailwind"
files={["starters/tailwind/src/RangeCalendar.tsx"]} />
</ExampleSwitcher>
Expand Down
26 changes: 25 additions & 1 deletion packages/dev/s2-docs/pages/react-aria/TagGroup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ import {TagGroup, Tag} from 'vanilla-starter/TagGroup';
<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>
</InlineAlert>

## Selection
## Selection and actions

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.

Expand Down Expand Up @@ -137,6 +137,30 @@ function Example(props) {
}
```

Use the `onAction` prop to handle item actions.

```tsx render wide
"use client";
import {TagGroup, Tag} from 'vanilla-starter/TagGroup';

function Example() {
return (
<TagGroup
label="Music genres"
///- begin highlight -///
onAction={key => alert(`Clicked ${key}`)}
///- end highlight -///
>
<Tag id="rock">Rock</Tag>
<Tag id="jazz">Jazz</Tag>
<Tag id="pop">Pop</Tag>
<Tag id="classical">Classical</Tag>
<Tag id="edm">EDM</Tag>
</TagGroup>
);
}
```

## Examples

<ExampleList tag="taggroup" pages={props.pages} />
Expand Down
21 changes: 21 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/frameworks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ export const description = 'How to integrate with your framework.';
}
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
<TabPanel id="react-router">
Expand Down Expand Up @@ -184,6 +187,9 @@ export const description = 'How to integrate with your framework.';
});
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
<TabPanel id="parcel">
Expand Down Expand Up @@ -213,6 +219,9 @@ export const description = 'How to integrate with your framework.';
}
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
<TabPanel id="vite">
Expand Down Expand Up @@ -243,6 +252,9 @@ export const description = 'How to integrate with your framework.';
});
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
<TabPanel id="webpack">
Expand Down Expand Up @@ -270,6 +282,9 @@ export const description = 'How to integrate with your framework.';
};
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
<TabPanel id="rollup">
Expand Down Expand Up @@ -297,6 +312,9 @@ export const description = 'How to integrate with your framework.';
};
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
<TabPanel id="esbuild">
Expand Down Expand Up @@ -324,6 +342,9 @@ export const description = 'How to integrate with your framework.';
});
```
</Step>
<Step>
<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.
</Step>
</StepList>
</TabPanel>
</Tabs>
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/s2/RangeCalendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const description = 'Allows a user to select a contiguous range of dates.
component={RangeCalendar}
docs={docs.exports.RangeCalendar}
links={docs.links}
props={['visibleMonths', 'pageBehavior', 'firstDayOfWeek', 'isDisabled', 'interactOutsideBehavior']}
props={['visibleMonths', 'pageBehavior', 'firstDayOfWeek', 'isDisabled', 'commitBehavior']}
initialProps={{'aria-label': 'Trip dates'}}
controlOptions={{
visibleMonths: {
Expand Down
Loading
Loading