Skip to content

Commit 6e15bab

Browse files
committed
fix: refactor visionos_hoverStyle to take a string and new arch support
1 parent c7b4705 commit 6e15bab

File tree

12 files changed

+80
-71
lines changed

12 files changed

+80
-71
lines changed

packages/react-native/Libraries/Components/Pressable/Pressable.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type {
2020
AccessibilityState,
2121
AccessibilityValue,
2222
} from '../View/ViewAccessibility';
23-
import type {HoverStyle} from '../View/ViewPropTypes';
23+
import type {HoverEffect} from '../View/ViewPropTypes';
2424

2525
import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
2626
import usePressability from '../../Pressability/usePressability';
@@ -33,9 +33,7 @@ import useAndroidRippleForView, {
3333
import * as React from 'react';
3434
import {useMemo, useRef, useState} from 'react';
3535

36-
const defaultHoverStyle: HoverStyle = {
37-
effectType: 'automatic',
38-
};
36+
const defaultHoverEffect: HoverEffect = 'highlight';
3937

4038
type ViewStyleProp = $ElementType<React.ElementConfig<typeof View>, 'style'>;
4139

@@ -44,7 +42,7 @@ export type StateCallbackType = $ReadOnly<{|
4442
|}>;
4543

4644
type VisionOSProps = $ReadOnly<{|
47-
visionos_hoverStyle?: ?HoverStyle,
45+
visionos_hoverEffect?: ?HoverEffect,
4846
|}>;
4947

5048
type Props = $ReadOnly<{|
@@ -245,7 +243,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
245243
style,
246244
testOnly_pressed,
247245
unstable_pressDelay,
248-
visionos_hoverStyle = defaultHoverStyle,
246+
visionos_hoverEffect = defaultHoverEffect,
249247
...restProps
250248
} = props;
251249

@@ -356,7 +354,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
356354
ref={mergedRef}
357355
style={typeof style === 'function' ? style({pressed}) : style}
358356
collapsable={false}
359-
visionos_hoverStyle={visionos_hoverStyle}>
357+
visionos_hoverEffect={visionos_hoverEffect}>
360358
{typeof children === 'function' ? children({pressed}) : children}
361359
{__DEV__ ? <PressabilityDebugView color="red" hitSlop={hitSlop} /> : null}
362360
</View>

packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
import type {ColorValue} from '../../StyleSheet/StyleSheet';
12-
import type {HoverStyle} from '../View/ViewPropTypes';
12+
import type {HoverEffect} from '../View/ViewPropTypes';
1313
import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';
1414

1515
import View from '../../Components/View/View';
@@ -34,7 +34,7 @@ type IOSProps = $ReadOnly<{|
3434
|}>;
3535

3636
type VisionOSProps = $ReadOnly<{|
37-
hoverStyle?: ?HoverStyle,
37+
hoverEffect?: ?HoverEffect,
3838
|}>;
3939

4040
type Props = $ReadOnly<{|
@@ -347,7 +347,7 @@ class TouchableHighlight extends React.Component<Props, State> {
347347
nextFocusLeft={this.props.nextFocusLeft}
348348
nextFocusRight={this.props.nextFocusRight}
349349
nextFocusUp={this.props.nextFocusUp}
350-
visionos_hoverStyle={this.props.hoverStyle}
350+
visionos_hoverEffect={this.props.hoverEffect}
351351
focusable={
352352
this.props.focusable !== false && this.props.onPress !== undefined
353353
}

packages/react-native/Libraries/Components/Touchable/TouchableOpacity.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type * as React from 'react';
1111
import {Constructor} from '../../../types/private/Utilities';
1212
import {TimerMixin} from '../../../types/private/TimerMixin';
1313
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
14-
import {HoverStyle, TVParallaxProperties} from '../View/ViewPropTypes';
14+
import {HoverEffect, TVParallaxProperties} from '../View/ViewPropTypes';
1515
import {TouchableMixin} from './Touchable';
1616
import {TouchableWithoutFeedbackProps} from './TouchableWithoutFeedback';
1717

@@ -90,7 +90,7 @@ export interface TouchableOpacityProps
9090
/**
9191
* Hover style to apply to the view. Only supported on VisionOS.
9292
*/
93-
visionos_hoverStyle?: HoverStyle | undefined;
93+
visionos_hoverEffect?: HoverEffect | undefined;
9494
}
9595

9696
/**

packages/react-native/Libraries/Components/Touchable/TouchableOpacity.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
12-
import type {HoverStyle} from '../View/ViewPropTypes';
12+
import type {HoverEffect} from '../View/ViewPropTypes';
1313
import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';
1414

1515
import Animated from '../../Animated/Animated';
@@ -22,9 +22,7 @@ import flattenStyle from '../../StyleSheet/flattenStyle';
2222
import Platform from '../../Utilities/Platform';
2323
import * as React from 'react';
2424

25-
const defaultHoverStyle: HoverStyle = {
26-
effectType: 'automatic',
27-
};
25+
const defaultHoverEffect: HoverEffect = 'highlight';
2826

2927
type TVProps = $ReadOnly<{|
3028
hasTVPreferredFocus?: ?boolean,
@@ -36,7 +34,7 @@ type TVProps = $ReadOnly<{|
3634
|}>;
3735

3836
type VisionOSProps = $ReadOnly<{|
39-
visionos_hoverStyle?: ?HoverStyle,
37+
visionos_hoverEffect?: ?HoverEffect,
4038
|}>;
4139

4240
type Props = $ReadOnly<{|
@@ -140,8 +138,8 @@ type State = $ReadOnly<{|
140138
*
141139
*/
142140
class TouchableOpacity extends React.Component<Props, State> {
143-
static defaultProps: {|visionos_hoverStyle: HoverStyle|} = {
144-
visionos_hoverStyle: defaultHoverStyle,
141+
static defaultProps: {|visionos_hoverEffect: HoverEffect|} = {
142+
visionos_hoverEffect: defaultHoverEffect,
145143
};
146144

147145
state: State = {
@@ -300,7 +298,7 @@ class TouchableOpacity extends React.Component<Props, State> {
300298
nextFocusUp={this.props.nextFocusUp}
301299
hasTVPreferredFocus={this.props.hasTVPreferredFocus}
302300
hitSlop={this.props.hitSlop}
303-
visionos_hoverStyle={this.props.visionos_hoverStyle}
301+
visionos_hoverEffect={this.props.visionos_hoverEffect}
304302
focusable={
305303
this.props.focusable !== false && this.props.onPress !== undefined
306304
}

packages/react-native/Libraries/Components/View/ViewPropTypes.d.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,7 @@ import {LayoutChangeEvent, PointerEvents} from '../../Types/CoreEventTypes';
1616
import {Touchable} from '../Touchable/Touchable';
1717
import {AccessibilityProps} from './ViewAccessibility';
1818

19-
export type HoverStyle = {
20-
/**
21-
* If true the hover effect is enabled. Defaults to true.
22-
*/
23-
enabled: boolean;
24-
/**
25-
* Hover effect type to apply to the view.
26-
*/
27-
effectType: 'automatic' | 'lift' | 'highlight';
28-
/**
29-
* Corner radius of the hover effect.
30-
*/
31-
cornerRadius?: number | undefined;
32-
};
19+
export type HoverEffect = 'lift' | 'highlight';
3320

3421
export type TVParallaxProperties = {
3522
/**
@@ -140,7 +127,7 @@ export interface ViewPropsIOS extends TVViewPropsIOS {
140127
/**
141128
* Hover style to apply to the view. Only supported on VisionOS.
142129
*/
143-
visionos_hoverStyle?: HoverStyle | undefined;
130+
visionos_hoverEffect?: HoverEffect | undefined;
144131
}
145132

146133
export interface ViewPropsAndroid {

packages/react-native/Libraries/Components/View/ViewPropTypes.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -263,20 +263,7 @@ type AndroidDrawableRipple = $ReadOnly<{|
263263
rippleRadius?: ?number,
264264
|}>;
265265

266-
export type HoverStyle = $ReadOnly<{|
267-
/**
268-
* If true the hover effect is enabled. Defaults to true.
269-
*/
270-
enabled?: ?boolean,
271-
/**
272-
* Hover effect type to apply to the view.
273-
*/
274-
effectType: 'automatic' | 'lift' | 'highlight',
275-
/**
276-
* Corner radius of the hover effect.
277-
*/
278-
cornerRadius?: ?number,
279-
|}>;
266+
export type HoverEffect = 'lift' | 'highlight';
280267

281268
type AndroidDrawable = AndroidDrawableThemeAttr | AndroidDrawableRipple;
282269

@@ -470,7 +457,7 @@ type IOSViewProps = $ReadOnly<{|
470457
/**
471458
* Hover style to apply to the view. Only supported on VisionOS.
472459
*/
473-
visionos_hoverStyle?: ?HoverStyle,
460+
visionos_hoverEffect?: ?HoverEffect,
474461
|}>;
475462

476463
export type ViewProps = $ReadOnly<{|

packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,12 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
291291
oldViewProps.borderColors != newViewProps.borderColors) {
292292
needsInvalidateLayer = YES;
293293
}
294+
295+
#if TARGET_OS_VISION
296+
if (oldViewProps.visionos_hoverEffect != newViewProps.visionos_hoverEffect) {
297+
[self updateHoverEffect:[NSString stringWithUTF8String:newViewProps.visionos_hoverEffect.c_str()]];
298+
}
299+
#endif
294300

295301
// `nativeId`
296302
if (oldViewProps.nativeId != newViewProps.nativeId) {
@@ -512,6 +518,28 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
512518
}
513519
}
514520

521+
#if TARGET_OS_VISION
522+
- (void) updateHoverEffect:(NSString*)hoverEffect {
523+
if (hoverEffect == nil || [hoverEffect isEqualToString:@""]) {
524+
self.hoverStyle = nil;
525+
return;
526+
}
527+
528+
UIShape *shape = [UIShape rectShapeWithCornerRadius:self.layer.cornerRadius];
529+
id<UIHoverEffect> effect;
530+
531+
if ([hoverEffect isEqualToString:@"lift"]) {
532+
effect = [UIHoverLiftEffect effect];
533+
} else if ([hoverEffect isEqualToString:@"highlight"]) {
534+
effect = [UIHoverHighlightEffect effect];
535+
}
536+
537+
if (hoverEffect != nil) {
538+
self.hoverStyle = [UIHoverStyle styleWithEffect:effect shape:shape];
539+
}
540+
}
541+
#endif
542+
515543
static RCTCornerRadii RCTCornerRadiiFromBorderRadii(BorderRadii borderRadii)
516544
{
517545
return RCTCornerRadii{

packages/react-native/React/Views/RCTView.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait;
124124
/**
125125
* The hover style to apply to a view, including an effect and a shape to use for displaying that effect.
126126
*/
127-
@property (nonatomic, copy) NSDictionary *hoverStyleProperties;
127+
@property (nonatomic, copy) NSString *hoverEffect;
128128
#endif
129129

130130
/**

packages/react-native/React/Views/RCTView.m

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -668,33 +668,26 @@ - (UIEdgeInsets)bordersAsInsets
668668

669669

670670
#if TARGET_OS_VISION
671-
- (void)setHoverStyleProperties:(NSDictionary *)hoverStyleProperties {
672-
_hoverStyleProperties = hoverStyleProperties;
671+
- (void)setHoverEffect:(NSString *)hoverEffect {
672+
_hoverEffect = hoverEffect;
673673

674-
BOOL enabled = _hoverStyleProperties[@"enabled"] != nil ? [_hoverStyleProperties[@"enabled"] boolValue] : YES;
675-
676-
if (!enabled || hoverStyleProperties == nil) {
674+
if (hoverEffect == nil) {
677675
self.hoverStyle = nil;
678676
return;
679677
}
680678

681-
NSString *effectType = (NSString *)[_hoverStyleProperties objectForKey:@"effectType"];
682-
NSNumber *cornerRadius = (NSNumber *)[_hoverStyleProperties objectForKey:@"cornerRadius"];
683-
684-
float cornerRadiusFloat = [cornerRadius floatValue];
679+
UIShape *shape = [UIShape rectShapeWithCornerRadius:_borderRadius];
680+
id<UIHoverEffect> effect;
685681

686-
UIShape *shape = [UIShape rectShapeWithCornerRadius:cornerRadiusFloat];
687-
id<UIHoverEffect> hoverEffect;
688-
689-
if ([effectType isEqualToString:@"lift"]) {
690-
hoverEffect = [UIHoverLiftEffect effect];
691-
} else if ([effectType isEqualToString:@"highlight"]) {
692-
hoverEffect = [UIHoverHighlightEffect effect];
693-
} else if ([effectType isEqualToString:@"automatic"]) {
694-
hoverEffect = [UIHoverAutomaticEffect effect];
682+
if ([hoverEffect isEqualToString:@"lift"]) {
683+
effect = [UIHoverLiftEffect effect];
684+
} else if ([hoverEffect isEqualToString:@"highlight"]) {
685+
effect = [UIHoverHighlightEffect effect];
695686
}
696687

697-
self.hoverStyle = [UIHoverStyle styleWithEffect:hoverEffect shape:shape];
688+
if (hoverEffect != nil) {
689+
self.hoverStyle = [UIHoverStyle styleWithEffect:effect shape:shape];
690+
}
698691
}
699692
#endif
700693

packages/react-native/React/Views/RCTViewManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ - (RCTShadowView *)shadowView
194194
RCT_REMAP_VIEW_PROPERTY(testID, reactAccessibilityElement.accessibilityIdentifier, NSString)
195195

196196
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
197-
RCT_REMAP_VISIONOS_VIEW_PROPERTY(visionos_hoverStyle, hoverStyleProperties, NSDictionary)
197+
RCT_REMAP_VISIONOS_VIEW_PROPERTY(visionos_hoverEffect, hoverEffect, NSString)
198198
RCT_REMAP_VIEW_PROPERTY(backfaceVisibility, layer.doubleSided, css_backface_visibility_t)
199199
RCT_REMAP_VIEW_PROPERTY(opacity, alpha, CGFloat)
200200
RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor, CGColor)

0 commit comments

Comments
 (0)