Skip to content
Open
7 changes: 3 additions & 4 deletions packages/@react-spectrum/s2/src/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
import {ActionButtonGroupContext} from './ActionButtonGroup';
import {AvatarContext} from './Avatar';
import {baseColor, focusRing, fontRelative, lightDark, style} from '../style' with { type: 'macro' };
import {ButtonProps, ButtonRenderProps, ContextValue, OverlayTriggerStateContext, Provider, Button as RACButton, useSlottedContext} from 'react-aria-components';
import {ButtonProps, ButtonRenderProps, ContextValue, Provider, Button as RACButton, useSlottedContext} from 'react-aria-components';
import {centerBaseline} from './CenterBaseline';
import {control, getAllowedOverrides, staticColor, StyleProps} from './style-utils' with { type: 'macro' };
import {createContext, forwardRef, ReactNode, useContext} from 'react';
import {createContext, forwardRef, ReactNode} from 'react';
import {FocusableRef, FocusableRefValue, GlobalDOMAttributes} from '@react-types/shared';
import {IconContext} from './Icon';
import {ImageContext} from './Image';
Expand Down Expand Up @@ -282,7 +282,6 @@ export const ActionButton = forwardRef(function ActionButton(props: ActionButton
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/s2');
let {isPending = false} = props;
let domRef = useFocusableRef(ref);
let overlayTriggerState = useContext(OverlayTriggerStateContext);
let ctx = useSlottedContext(ActionButtonGroupContext);
let isInGroup = !!ctx;
let {
Expand All @@ -306,7 +305,7 @@ export const ActionButton = forwardRef(function ActionButton(props: ActionButton
className={renderProps => (props.UNSAFE_className || '') + btnStyles({
...renderProps,
// Retain hover styles when an overlay is open.
isHovered: renderProps.isHovered || overlayTriggerState?.isOpen || false,
isHovered: renderProps.isHovered || renderProps.isExpanded || false,
isDisabled: renderProps.isDisabled || isProgressVisible,
staticColor,
isStaticColor: !!staticColor,
Expand Down
5 changes: 2 additions & 3 deletions packages/@react-spectrum/s2/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,6 @@ export const Button = forwardRef(function Button(props: ButtonProps, ref: Focusa
staticColor
} = props;
let domRef = useFocusableRef(ref);
let overlayTriggerState = useContext(OverlayTriggerStateContext);

let {isProgressVisible} = usePendingState(isPending);

Expand All @@ -340,7 +339,7 @@ export const Button = forwardRef(function Button(props: ButtonProps, ref: Focusa
className={renderProps => (props.UNSAFE_className || '') + button({
...renderProps,
// Retain hover styles when an overlay is open.
isHovered: renderProps.isHovered || overlayTriggerState?.isOpen || false,
isHovered: renderProps.isHovered || renderProps.isExpanded || false,
isDisabled: renderProps.isDisabled || isProgressVisible,
variant,
fillStyle,
Expand All @@ -355,7 +354,7 @@ export const Button = forwardRef(function Button(props: ButtonProps, ref: Focusa
className={gradient({
...renderProps,
// Retain hover styles when an overlay is open.
isHovered: renderProps.isHovered || overlayTriggerState?.isOpen || false,
isHovered: renderProps.isHovered || renderProps?.isExpanded || false,
isDisabled: renderProps.isDisabled || isProgressVisible,
variant
})} />
Expand Down
9 changes: 1 addition & 8 deletions packages/@react-spectrum/s2/src/DialogTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*/

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 {}
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} />
);
}
27 changes: 3 additions & 24 deletions packages/@react-spectrum/s2/src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ import {centerBaseline} from './CenterBaseline';
import {centerPadding, control, controlFont, controlSize, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'};
import CheckmarkIcon from '../ui-icons/Checkmark';
import ChevronRightIcon from '../ui-icons/Chevron';
import {createContext, forwardRef, JSX, ReactNode, useContext, useRef, useState} from 'react';
import {createContext, forwardRef, JSX, ReactNode, useContext, useRef} from 'react';
import {divider} from './Divider';
import {DOMRef, DOMRefValue, GlobalDOMAttributes, PressEvent} from '@react-types/shared';
import {DOMRef, DOMRefValue, GlobalDOMAttributes} from '@react-types/shared';
import {edgeToText} from '../style/spectrum-theme' with {type: 'macro'};
import {forwardRefType} from './types';
import {HeaderContext, HeadingContext, KeyboardContext, Text, TextContext} from './Content';
Expand All @@ -46,9 +46,7 @@ import {InPopoverContext, Popover, PopoverContext} from './Popover';
import LinkOutIcon from '../ui-icons/LinkOut';
import {mergeStyles} from '../style/runtime';
import {Placement, useLocale} from 'react-aria';
import {PressResponder} from '@react-aria/interactions';
import {pressScale} from './pressScale';
import {useGlobalListeners} from '@react-aria/utils';
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
Expand Down Expand Up @@ -543,23 +541,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.
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});
};

let {align = 'start', direction = 'bottom', shouldFlip} = props;
let placement: Placement;
switch (direction) {
Expand All @@ -585,9 +566,7 @@ function MenuTrigger(props: MenuTriggerProps): ReactNode {
<PopoverContext.Provider value={{hideArrow: true, offset: 8, crossOffset: 0, placement, shouldFlip}}>
<InPopoverContext.Provider value={false}>
<AriaMenuTrigger {...props}>
<PressResponder onPressStart={onPressStart} isPressed={isPressed}>
{props.children}
</PressResponder>
{props.children}
</AriaMenuTrigger>
</InPopoverContext.Provider>
</PopoverContext.Provider>
Expand Down
178 changes: 78 additions & 100 deletions packages/@react-spectrum/s2/src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
SelectValue,
Virtualizer
} from 'react-aria-components';
import {AsyncLoadable, FocusableRef, FocusableRefValue, GlobalDOMAttributes, HelpTextProps, LoadingState, PressEvent, RefObject, SpectrumLabelableProps} from '@react-types/shared';
import {AsyncLoadable, FocusableRef, FocusableRefValue, GlobalDOMAttributes, HelpTextProps, LoadingState, RefObject, SpectrumLabelableProps} from '@react-types/shared';
import {AvatarContext} from './Avatar';
import {baseColor, focusRing, style} from '../style' with {type: 'macro'};
import {box, iconStyles as checkboxIconStyles} from './Checkbox';
Expand Down Expand Up @@ -72,15 +72,14 @@ import intlMessages from '../intl/*.json';
import {mergeStyles} from '../style/runtime';
import {Placement} from 'react-aria';
import {Popover} from './Popover';
import {PressResponder} from '@react-aria/interactions';
import {pressScale} from './pressScale';
import {ProgressCircle} from './ProgressCircle';
import {raw} from '../style/style-macro' with {type: 'macro'};
import React, {createContext, forwardRef, ReactNode, useContext, useMemo, useRef, useState} from 'react';
import React, {createContext, forwardRef, ReactNode, useContext, useMemo, useRef} from 'react';
import {useFocusableRef} from '@react-spectrum/utils';
import {useGlobalListeners, useSlotId} from '@react-aria/utils';
import {useLocale, useLocalizedStringFormatter} from '@react-aria/i18n';
import {useScale} from './utils';
import {useSlotId} from '@react-aria/utils';
import {useSpectrumContextProps} from './useSpectrumContextProps';

export interface PickerStyleProps {
Expand Down Expand Up @@ -487,7 +486,6 @@ interface PickerButtonInnerProps<T extends object> extends PickerStyleProps, Omi
buttonRef: RefObject<HTMLButtonElement | null>
}

// Needs to be hidable component or otherwise the PressResponder throws a warning when rendered in the fake DOM and tries to register
const PickerButton = createHideableComponent(function PickerButton<T extends object>(props: PickerButtonInnerProps<T>) {
let {
isOpen,
Expand All @@ -502,105 +500,85 @@ const PickerButton = createHideableComponent(function PickerButton<T extends obj
} = props;
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/s2');

// For mouse interactions, pickers open on press start. When the popover underlay appears
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this code is in S2 MenuTrigger too, so we should move that into RAC too I guess. The RAC Menu examples don't have any press scaling anymore.

// 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 (
<PressResponder onPressStart={onPressStart} isPressed={isPressed}>
<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,
isOpen,
isQuiet
})}>
{(renderProps) => (
<>
<SelectValue className={valueStyles({isQuiet}) + ' ' + raw('&> :not([slot=icon], [slot=avatar], [slot=label], [data-slot=label]) {display: none;}')}>
{({selectedItems, defaultChildren}) => {
return (
<Provider
values={[
[IconContext, {
slots: {
icon: {
render: centerBaseline({slot: 'icon', styles: iconCenterWrapper}),
styles: icon
}
<Button
ref={buttonRef}
style={renderProps => pressScale(buttonRef)(renderProps)}
className={renderProps => inputButton({
...renderProps,
size: size,
isOpen,
isQuiet
})}>
{(renderProps) => (
<>
<SelectValue className={valueStyles({isQuiet}) + ' ' + raw('&> :not([slot=icon], [slot=avatar], [slot=label], [data-slot=label]) {display: none;}')}>
{({selectedItems, defaultChildren}) => {
return (
<Provider
values={[
[IconContext, {
slots: {
icon: {
render: centerBaseline({slot: 'icon', styles: iconCenterWrapper}),
styles: icon
}
}],
[AvatarContext, {
slots: {
avatar: {
size: avatarSize[size ?? 'M'],
styles: avatar
}
}
}],
[AvatarContext, {
slots: {
avatar: {
size: avatarSize[size ?? 'M'],
styles: avatar
}
}],
[TextContext, {
slots: {
description: {},
[DEFAULT_SLOT]: {
styles: style({
display: 'block',
flexGrow: 1,
truncate: true
}),
// @ts-ignore
'data-slot': 'label'
},
label: {
styles: style({
display: 'block',
flexGrow: 1,
truncate: true
}),
// @ts-ignore not technically necessary, but good for consistency
'data-slot': 'label'
}
}
}],
[TextContext, {
slots: {
description: {},
[DEFAULT_SLOT]: {
styles: style({
display: 'block',
flexGrow: 1,
truncate: true
}),
// @ts-ignore
'data-slot': 'label'
},
label: {
styles: style({
display: 'block',
flexGrow: 1,
truncate: true
}),
// @ts-ignore not technically necessary, but good for consistency
'data-slot': 'label'
}
}],
[InsideSelectValueContext, true]
]}>
{selectedItems.length <= 1
? defaultChildren
: <Text slot="label">{stringFormatter.format('picker.selectedCount', {count: selectedItems.length})}</Text>
}
</Provider>
);
}}
</SelectValue>
{isInvalid && <FieldErrorIcon isDisabled={isDisabled} />}
{loadingState === 'loading' && !isOpen && loadingCircle}
<ChevronIcon
size={size}
className={iconStyles({isLoading: loadingState === 'loading'})} />
{isFocusVisible && isQuiet && <span className={quietFocusLine} /> }
{isInvalid && !isDisabled && !isQuiet &&
// @ts-ignore known limitation detecting functions from the theme
<div className={invalidBorder({...renderProps, size})} />
}
</>
)}
</Button>
</PressResponder>
}
}],
[InsideSelectValueContext, true]
]}>
{selectedItems.length <= 1
? defaultChildren
: <Text slot="label">{stringFormatter.format('picker.selectedCount', {count: selectedItems.length})}</Text>
}
</Provider>
);
}}
</SelectValue>
{isInvalid && <FieldErrorIcon isDisabled={isDisabled} />}
{loadingState === 'loading' && !isOpen && loadingCircle}
<ChevronIcon
size={size}
className={iconStyles({isLoading: loadingState === 'loading'})} />
{isFocusVisible && isQuiet && <span className={quietFocusLine} /> }
{isInvalid && !isDisabled && !isQuiet &&
// @ts-ignore known limitation detecting functions from the theme
<div className={invalidBorder({...renderProps, size})} />
}
</>
)}
</Button>
);
});

Expand Down
3 changes: 0 additions & 3 deletions packages/@react-spectrum/s2/src/TabsPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,6 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
<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',
Expand Down
Loading