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
6 changes: 2 additions & 4 deletions packages/@react-spectrum/s2/src/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export interface ComboboxStyleProps {
size?: 'S' | 'M' | 'L' | 'XL'
}
export interface ComboBoxProps<T extends object> extends
Omit<AriaComboBoxProps<T>, 'children' | 'style' | 'className' | 'defaultFilter' | 'allowsEmptyCollection' | keyof GlobalDOMAttributes>,
Omit<AriaComboBoxProps<T>, 'children' | 'style' | 'className' | 'defaultFilter' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>,
ComboboxStyleProps,
StyleProps,
SpectrumLabelableProps,
Expand Down Expand Up @@ -354,6 +354,7 @@ export const ComboBox = /*#__PURE__*/ (forwardRef as forwardRefType)(function Co
return (
<AriaComboBox
{...comboBoxProps}
isTriggerUpWhenOpen
allowsEmptyCollection
style={UNSAFE_style}
className={UNSAFE_className + style(field(), getAllowedOverrides())({
Expand Down Expand Up @@ -643,9 +644,6 @@ const ComboboxInner = forwardRef(function ComboboxInner(props: ComboBoxProps<any
)}
<Button
ref={buttonRef}
// Prevent press scale from sticking while ComboBox is open.
// @ts-ignore
isPressed={false}
style={renderProps => pressScale(buttonRef)(renderProps)}
className={renderProps => inputButton({
...renderProps,
Expand Down
6 changes: 2 additions & 4 deletions packages/@react-spectrum/s2/src/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps';


export interface DatePickerProps<T extends DateValue> extends
Omit<AriaDatePickerProps<T>, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>,
Omit<AriaDatePickerProps<T>, 'children' | 'className' | 'style' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>,
Pick<CalendarProps<T>, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>,
Pick<PopoverProps, 'shouldFlip'>,
StyleProps,
Expand Down Expand Up @@ -155,6 +155,7 @@ export const DatePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(function
ref={ref}
isRequired={isRequired}
{...dateFieldProps}
isTriggerUpWhenOpen
style={UNSAFE_style}
className={(UNSAFE_className || '') + style(field(), getAllowedOverrides())({
isInForm: !!formContext,
Expand Down Expand Up @@ -277,9 +278,6 @@ export function CalendarButton(props: {isOpen: boolean, size: 'S' | 'M' | 'L' |
return (
<Button
ref={buttonRef}
// Prevent press scale from sticking while DatePicker is open.
// @ts-ignore
isPressed={false}
onFocusChange={setButtonHasFocus}
style={pressScale(buttonRef)}
className={renderProps => inputButton({
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-spectrum/s2/src/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps';


export interface DateRangePickerProps<T extends DateValue> extends
Omit<AriaDateRangePickerProps<T>, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>,
Omit<AriaDateRangePickerProps<T>, 'children' | 'className' | 'style' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>,
Pick<RangeCalendarProps<T>, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>,
Pick<PopoverProps, 'shouldFlip'>,
StyleProps,
Expand Down Expand Up @@ -89,6 +89,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
ref={ref}
isRequired={isRequired}
{...dateFieldProps}
isTriggerUpWhenOpen
style={UNSAFE_style}
className={(UNSAFE_className || '') + style(field(), getAllowedOverrides())({
isInForm: !!formContext,
Expand Down
11 changes: 2 additions & 9 deletions packages/@react-spectrum/s2/src/DialogTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
*/

import {DialogTrigger as AriaDialogTrigger, DialogTriggerProps as AriaDialogTriggerProps} from 'react-aria-components';
import {PressResponder} from '@react-aria/interactions';
import {ReactNode} from 'react';

export interface DialogTriggerProps extends AriaDialogTriggerProps {}
export type DialogTriggerProps = Omit<AriaDialogTriggerProps, 'isTriggerUpWhenOpen'>;

/**
* DialogTrigger serves as a wrapper around a Dialog and its associated trigger, linking the Dialog's
Expand All @@ -23,12 +22,6 @@ export interface DialogTriggerProps extends AriaDialogTriggerProps {}
*/
export function DialogTrigger(props: DialogTriggerProps): ReactNode {
return (
<AriaDialogTrigger {...props}>
{/* RAC sets isPressed via PressResponder when the dialog is open.
We don't want press scaling to appear to get "stuck", so override this. */}
<PressResponder isPressed={false}>
{props.children}
</PressResponder>
</AriaDialogTrigger>
<AriaDialogTrigger {...props} isTriggerUpWhenOpen />
);
}
4 changes: 1 addition & 3 deletions packages/@react-spectrum/s2/src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps';
// viewbox on LinkOut is super weird just because i copied the icon from designs...
// need to strip id's from icons

export interface MenuTriggerProps extends AriaMenuTriggerProps {
export interface MenuTriggerProps extends Omit<AriaMenuTriggerProps, 'isTriggerUpWhenOpen'> {
/**
* Alignment of the menu relative to the trigger.
*
Expand Down Expand Up @@ -547,8 +547,6 @@ export function MenuItem(props: MenuItemProps): ReactNode {
* linking the Menu's open state with the trigger's press state.
*/
function MenuTrigger(props: MenuTriggerProps): ReactNode {
// RAC sets isPressed via PressResponder when the menu is open.
// We don't want press scaling to appear to get "stuck", so override this.
// For mouse interactions, menus open on press start. When the popover underlay appears
// it covers the trigger button, causing onPressEnd to fire immediately and no press scaling
// to occur. We override this by listening for pointerup on the document ourselves.
Expand Down
6 changes: 2 additions & 4 deletions packages/@react-spectrum/s2/src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export interface PickerStyleProps {

type SelectionMode = 'single' | 'multiple';
export interface PickerProps<T extends object, M extends SelectionMode = 'single'> extends
Omit<AriaSelectProps<T, M>, 'children' | 'style' | 'className' | 'allowsEmptyCollection' | keyof GlobalDOMAttributes>,
Omit<AriaSelectProps<T, M>, 'children' | 'style' | 'className' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>,
PickerStyleProps,
StyleProps,
SpectrumLabelableProps,
Expand Down Expand Up @@ -351,6 +351,7 @@ export const Picker = /*#__PURE__*/ (forwardRef as forwardRefType)(function Pick
return (
<AriaSelect
{...pickerProps}
isTriggerUpWhenOpen
aria-describedby={spinnerId}
placeholder={placeholder}
style={UNSAFE_style}
Expand Down Expand Up @@ -522,9 +523,6 @@ const PickerButton = createHideableComponent(function PickerButton<T extends obj
<Button
ref={buttonRef}
style={renderProps => pressScale(buttonRef)(renderProps)}
// Prevent press scale from sticking while Picker is open.
// @ts-ignore
isPressed={false}
className={renderProps => inputButton({
...renderProps,
size: size,
Expand Down
129 changes: 73 additions & 56 deletions packages/@react-spectrum/s2/src/TabsPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,24 @@ import {edgeToText} from '../style/spectrum-theme' with {type: 'macro'};
import {
FieldLabel
} from './Field';
import {FocusableRef, FocusableRefValue, SpectrumLabelableProps} from '@react-types/shared';
import {FocusableRef, FocusableRefValue, PressEvent, SpectrumLabelableProps} from '@react-types/shared';
import {forwardRefType} from './types';
import {HeaderContext, HeadingContext, Text, TextContext} from './Content';
import {IconContext} from './Icon';
import {Placement, useLocale} from 'react-aria';
import {Popover} from './Popover';
import {PressResponder} from '@react-aria/interactions';
import {pressScale} from './pressScale';
import {raw} from '../style/style-macro' with {type: 'macro'};
import React, {createContext, forwardRef, ReactNode, useContext, useRef} from 'react';
import React, {createContext, forwardRef, ReactNode, useContext, useRef, useState} from 'react';
import {useFocusableRef} from '@react-spectrum/utils';
import {useFormProps} from './Form';
import {useGlobalListeners} from '@react-aria/utils';
import {useSpectrumContextProps} from './useSpectrumContextProps';
export interface PickerStyleProps {
}
export interface PickerProps<T extends object> extends
Omit<AriaSelectProps<T>, 'children' | 'style' | 'className' | 'placeholder'>,
Omit<AriaSelectProps<T>, 'children' | 'style' | 'className' | 'placeholder' | 'isTriggerUpWhenOpen'>,
PickerStyleProps,
StyleProps,
SpectrumLabelableProps,
Expand Down Expand Up @@ -182,70 +184,85 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
let {direction: dir} = useLocale();
let RTLFlipOffset = dir === 'rtl' ? -1 : 1;

// For mouse interactions, pickers open on press start. When the popover underlay appears
// it covers the trigger button, causing onPressEnd to fire immediately and no press scaling
// to occur. We override this by listening for pointerup on the document ourselves.
let [isPressed, setPressed] = useState(false);
let {addGlobalListener} = useGlobalListeners();
let onPressStart = (e: PressEvent) => {
if (e.pointerType !== 'mouse') {
return;
}
setPressed(true);
addGlobalListener(document, 'pointerup', () => {
setPressed(false);
}, {once: true, capture: true});
};

return (
<div>
<AriaSelect
{...pickerProps}
isTriggerUpWhenOpen
className=""
aria-labelledby={`${labelBehavior === 'hide' ? valueId : ''} ${ariaLabelledby}`}>
{({isOpen}) => (
<>
<FieldLabel isQuiet={isQuiet} />
<Button
ref={domRef}
style={renderProps => pressScale(domRef)(renderProps)}
// Prevent press scale from sticking while Picker is open.
// @ts-ignore
isPressed={false}
className={renderProps => inputButton({
...renderProps,
size: 'M',
isOpen,
isQuiet,
density
})}>
<SelectValue className={valueStyles + ' ' + raw('&> * {display: none;}')}>
{({defaultChildren}) => {
return (
<Provider
values={[
[IconContext, {
slots: {
icon: {
render: centerBaseline({slot: 'icon', styles: iconCenterWrapper({labelBehavior})}),
styles: icon
<PressResponder onPressStart={onPressStart} isPressed={isPressed}>
<Button
ref={domRef}
style={renderProps => pressScale(domRef)(renderProps)}
className={renderProps => inputButton({
...renderProps,
size: 'M',
isOpen,
isQuiet,
density
})}>
<SelectValue className={valueStyles + ' ' + raw('&> * {display: none;}')}>
{({defaultChildren}) => {
return (
<Provider
values={[
[IconContext, {
slots: {
icon: {
render: centerBaseline({slot: 'icon', styles: iconCenterWrapper({labelBehavior})}),
styles: icon
}
}
}
}],
[TextContext, {
slots: {
// Default slot is useful when converting other collections to PickerItems.
[DEFAULT_SLOT]: {
id: valueId,
styles: style({
display: {
default: 'block',
labelBehavior: {
hide: 'none'
}
},
flexGrow: 1,
truncate: true
})({labelBehavior})
}],
[TextContext, {
slots: {
// Default slot is useful when converting other collections to PickerItems.
[DEFAULT_SLOT]: {
id: valueId,
styles: style({
display: {
default: 'block',
labelBehavior: {
hide: 'none'
}
},
flexGrow: 1,
truncate: true
})({labelBehavior})
}
}
}
}],
[InsideSelectValueContext, true]
]}>
{defaultChildren}
</Provider>
);
}}
</SelectValue>
<ChevronIcon
size={size}
className={iconStyles} />
</Button>
}],
[InsideSelectValueContext, true]
]}>
{defaultChildren}
</Provider>
);
}}
</SelectValue>
<ChevronIcon
size={size}
className={iconStyles} />
</Button>
</PressResponder>
<Popover
hideArrow
offset={menuOffset}
Expand Down
6 changes: 4 additions & 2 deletions packages/react-aria-components/src/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ export interface ComboBoxProps<T extends object> extends Omit<AriaComboBoxProps<
*/
formValue?: 'text' | 'key',
/** Whether the combo box allows the menu to be open when the collection is empty. */
allowsEmptyCollection?: boolean
allowsEmptyCollection?: boolean,
/** Whether the trigger is up when the overlay is open. */
isTriggerUpWhenOpen?: boolean
}

export const ComboBoxContext = createContext<ContextValue<ComboBoxProps<any>, HTMLDivElement>>(null);
Expand Down Expand Up @@ -207,7 +209,7 @@ function ComboBoxInner<T extends object>({props, collection, comboBoxRef: ref}:
values={[
[ComboBoxStateContext, state],
[LabelContext, {...labelProps, ref: labelRef}],
[ButtonContext, {...buttonProps, ref: buttonRef, isPressed: state.isOpen}],
[ButtonContext, {...buttonProps, ref: buttonRef, isPressed: !props.isTriggerUpWhenOpen && state.isOpen}],
[InputContext, {...inputProps, ref: inputRef}],
[OverlayTriggerStateContext, state],
[PopoverContext, {
Expand Down
12 changes: 8 additions & 4 deletions packages/react-aria-components/src/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,18 @@ export interface DatePickerProps<T extends DateValue> extends Omit<AriaDatePicke
* The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state.
* @default 'react-aria-DatePicker'
*/
className?: ClassNameOrFunction<DatePickerRenderProps>
className?: ClassNameOrFunction<DatePickerRenderProps>,
/** Whether the trigger is up when the overlay is open. */
isTriggerUpWhenOpen?: boolean
}
export interface DateRangePickerProps<T extends DateValue> extends Omit<AriaDateRangePickerProps<T>, 'label' | 'description' | 'errorMessage' | 'validationState' | 'validationBehavior'>, Pick<DateRangePickerStateOptions<T>, 'shouldCloseOnSelect'>, RACValidation, RenderProps<DateRangePickerRenderProps>, SlotProps, GlobalDOMAttributes<HTMLDivElement> {
/**
* The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state.
* @default 'react-aria-DateRangePicker'
*/
className?: ClassNameOrFunction<DateRangePickerRenderProps>
className?: ClassNameOrFunction<DateRangePickerRenderProps>,
/** Whether the trigger is up when the overlay is open. */
isTriggerUpWhenOpen?: boolean
}

export const DatePickerContext = createContext<ContextValue<DatePickerProps<any>, HTMLDivElement>>(null);
Expand Down Expand Up @@ -174,7 +178,7 @@ export const DatePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(function
[DatePickerStateContext, state],
[GroupContext, {...groupProps, ref: groupRef, isInvalid: state.isInvalid}],
[DateFieldContext, fieldProps],
[ButtonContext, {...buttonProps, isPressed: state.isOpen}],
[ButtonContext, {...buttonProps, isPressed: !props.isTriggerUpWhenOpen && state.isOpen}],
[LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
[CalendarContext, calendarProps],
[OverlayTriggerStateContext, state],
Expand Down Expand Up @@ -283,7 +287,7 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
values={[
[DateRangePickerStateContext, state],
[GroupContext, {...groupProps, ref: groupRef, isInvalid: state.isInvalid}],
[ButtonContext, {...buttonProps, isPressed: state.isOpen}],
[ButtonContext, {...buttonProps, isPressed: !props.isTriggerUpWhenOpen && state.isOpen}],
[LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
[RangeCalendarContext, calendarProps],
[OverlayTriggerStateContext, state],
Expand Down
4 changes: 3 additions & 1 deletion packages/react-aria-components/src/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import React, {createContext, ForwardedRef, forwardRef, JSX, ReactNode, useCallb
import {RootMenuTriggerStateContext} from './Menu';

export interface DialogTriggerProps extends OverlayTriggerProps {
/** Whether the trigger is up when the overlay is open. */
isTriggerUpWhenOpen?: boolean,
children: ReactNode
}

Expand Down Expand Up @@ -86,7 +88,7 @@ export function DialogTrigger(props: DialogTriggerProps): JSX.Element {
style: {'--trigger-width': buttonWidth} as React.CSSProperties
}]
]}>
<PressResponder {...triggerProps} ref={buttonRef} isPressed={state.isOpen}>
<PressResponder {...triggerProps} ref={buttonRef} isPressed={!props.isTriggerUpWhenOpen && state.isOpen}>
{props.children}
</PressResponder>
</Provider>
Expand Down
Loading