Skip to content
Draft
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
91 changes: 90 additions & 1 deletion packages/react-aria-components/test/RangeCalendar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
* governing permissions and limitations under the License.
*/

import {act, pointerMap, render, within} from '@react-spectrum/test-utils-internal';
import {
act,
createShadowRoot,
fireEvent,
installPointerEvent,
pointerMap,
render,
within
} from '@react-spectrum/test-utils-internal';
import {Button} from '../src/Button';

import {
Expand All @@ -34,6 +42,7 @@ import {
today
} from '@internationalized/date';
import {DateValue} from 'react-stately/useRangeCalendarState';
import {enableShadowDOM} from 'react-stately/private/flags/flags';
import {RangeValue} from '@react-types/shared';
import React from 'react';
import userEvent from '@testing-library/user-event';
Expand Down Expand Up @@ -666,4 +675,84 @@ describe('RangeCalendar', () => {
let heading = tree.container.querySelector('.react-aria-CalendarHeading');
expect(heading).toHaveTextContent('April 1 – 2, 2026');
});

describe('shadow DOM', () => {
installPointerEvent();

beforeAll(() => {
enableShadowDOM();
});

let pointerOpts = {pointerType: 'mouse', pointerId: 1, width: 1, height: 1, detail: 1};
let clickCell = (cell: Element) => {
fireEvent.pointerDown(cell, pointerOpts);
fireEvent.pointerUp(cell, pointerOpts);
fireEvent.click(cell, {detail: 1});
};

it('should support selecting a range by clicking two dates', () => {
let {shadowRoot, cleanup} = createShadowRoot();
let container = document.createElement('div');
shadowRoot.appendChild(container);
let onChange = jest.fn();
render(
<TestCalendar
calendarProps={{onChange, defaultFocusedValue: new CalendarDate(2019, 6, 5)}}
/>,
{container}
);

let grid = shadowRoot.querySelector<HTMLElement>('[role="grid"]')!;
let startCell = within(grid).getByText('17');
clickCell(startCell);

// The window pointerup listener receives an event retargeted to the shadow host.
// It must resolve the real target and not treat the click as a release outside
// the calendar, which would commit the selection early.
expect(startCell).toHaveAttribute('data-selection-start', 'true');
expect(startCell).toHaveAttribute('data-selection-end', 'true');
expect(onChange).not.toHaveBeenCalled();

let endCell = within(grid).getByText('23');
clickCell(endCell);

expect(startCell).toHaveAttribute('data-selection-start', 'true');
expect(endCell).toHaveAttribute('data-selection-end', 'true');
expect(onChange).toHaveBeenCalledTimes(1);
let {start, end} = onChange.mock.calls[0][0];
expect(start).toEqual(new CalendarDate(2019, 6, 17));
expect(end).toEqual(new CalendarDate(2019, 6, 23));

cleanup();
});

it('should commit the selection when releasing a drag outside the calendar', () => {
let {shadowRoot, cleanup} = createShadowRoot();
let container = document.createElement('div');
shadowRoot.appendChild(container);
let onChange = jest.fn();
render(
<TestCalendar
calendarProps={{onChange, defaultFocusedValue: new CalendarDate(2019, 6, 5)}}
/>,
{container}
);

let grid = shadowRoot.querySelector<HTMLElement>('[role="grid"]')!;
fireEvent.pointerDown(within(grid).getByText('17'), pointerOpts);
fireEvent.pointerEnter(within(grid).getByText('23'));
expect(onChange).not.toHaveBeenCalled();

// Guards the inverse path: resolving the real target must not make releases
// outside the shadow root look like they are inside the calendar.
fireEvent.pointerUp(document.body, pointerOpts);

expect(onChange).toHaveBeenCalledTimes(1);
let {start, end} = onChange.mock.calls[0][0];
expect(start).toEqual(new CalendarDate(2019, 6, 17));
expect(end).toEqual(new CalendarDate(2019, 6, 23));

cleanup();
});
});
});
4 changes: 2 additions & 2 deletions packages/react-aria/src/calendar/useRangeCalendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import {AriaLabelingProps, DOMProps, FocusableElement, RefObject} from '@react-types/shared';
import {CalendarAria, useCalendarBase} from './useCalendarBase';
import {DateValue, RangeCalendarState} from 'react-stately/useRangeCalendarState';
import {isFocusWithin, nodeContains} from '../utils/shadowdom/DOMFunctions';
import {getEventTarget, isFocusWithin, nodeContains} from '../utils/shadowdom/DOMFunctions';
import {RangeCalendarProps} from 'react-stately/useRangeCalendarState';
import {useEvent} from '../utils/useEvent';
import {useRef} from 'react';
Expand Down Expand Up @@ -76,7 +76,7 @@ export function useRangeCalendar<T extends DateValue>(
return;
}

let target = e.target as Element;
let target = getEventTarget(e) as Element;
if (
ref.current &&
isFocusWithin(ref.current) &&
Expand Down