Skip to content

Commit 27ac1ef

Browse files
committed
Remove PlatformMethods
1 parent e4c9444 commit 27ac1ef

62 files changed

Lines changed: 1301 additions & 716 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/components/Card.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
'use client';
22

3-
import type { ButtonMethods } from '@react-universal/components';
43
import { Button } from '@react-universal/components';
54
import { Div, H2, Span } from '@react-universal/elements';
65
import { useCallback, useState } from 'react';
76

87
interface CardProps {
98
children?: React.ReactNode;
109
href?: string;
11-
ref?: React.Ref<HTMLAnchorElement & ButtonMethods>;
10+
ref?: React.Ref<HTMLAnchorElement>;
1211
title?: string;
1312
}
1413

packages/components/src/Box/Box.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
import type { SxProps } from '@react-universal/core';
44
import { styled } from '@react-universal/core';
5-
import type { ViewMethods, ViewProps } from '../View';
5+
import type { ViewProps } from '../View';
66
import { View } from '../View';
77

8-
export interface BoxMethods extends ViewMethods {}
9-
108
export interface BoxProps extends ViewProps {
119
/**
1210
* The system prop that allows defining system overrides as well as additional
@@ -19,4 +17,4 @@ export const Box = styled(View, {
1917
name: 'Box',
2018
})({
2119
flexDirection: 'row',
22-
}) as React.FC<BoxProps & { ref?: React.Ref<HTMLElement & BoxMethods> }>;
20+
}) as React.FC<BoxProps & { ref?: React.Ref<HTMLElement> }>;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export type { BoxMethods, BoxProps } from './Box';
1+
export type { BoxProps } from './Box';
22
export { Box } from './Box';

packages/components/src/Button/Button.native.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
normalizeLayoutEvent,
3+
normalizeMouseEvent,
34
normalizeResponderEvent,
45
normalizeRole,
56
styled,
@@ -26,14 +27,18 @@ export const Button: React.FC<ButtonProps & { ref?: React.Ref<any> }> = ({
2627
lang,
2728
onBlur,
2829
onClick,
30+
onClickCapture,
2931
onFocus,
3032
onFocusVisible,
33+
onHoverIn,
34+
onHoverOut,
3135
onLayout,
3236
onLongPress,
3337
onMoveShouldSetResponder,
3438
onMoveShouldSetResponderCapture,
3539
onPress,
3640
onPressIn,
41+
onPressMove,
3742
onPressOut,
3843
onResponderEnd,
3944
onResponderGrant,
@@ -80,14 +85,18 @@ export const Button: React.FC<ButtonProps & { ref?: React.Ref<any> }> = ({
8085
role={normalizeRole(role) ?? 'button'}
8186
style={_style}
8287
onBlur={handleBlur}
83-
onClick={normalizeResponderEvent(onClick)}
88+
onClick={normalizeMouseEvent(onClick)}
89+
onClickCapture={normalizeMouseEvent(onClickCapture)}
8490
onFocus={handleFocus}
91+
onHoverIn={onHoverIn as any}
92+
onHoverOut={onHoverOut as any}
8593
onLayout={normalizeLayoutEvent(onLayout)}
8694
onLongPress={normalizeResponderEvent(onLongPress)}
8795
onMoveShouldSetResponder={normalizeResponderEvent(onMoveShouldSetResponder)}
8896
onMoveShouldSetResponderCapture={normalizeResponderEvent(onMoveShouldSetResponderCapture)}
8997
onPress={normalizeResponderEvent(onPress)}
9098
onPressIn={normalizeResponderEvent(onPressIn)}
99+
onPressMove={normalizeResponderEvent(onPressMove)}
91100
onPressOut={normalizeResponderEvent(onPressOut)}
92101
onResponderEnd={normalizeResponderEvent(onResponderEnd)}
93102
onResponderGrant={normalizeResponderEvent(onResponderGrant)}

packages/components/src/Button/Button.tsx

Lines changed: 55 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
11
'use client';
22

3-
import type { ResponderEvent } from '@react-universal/core';
4-
import { styled, useOwnerState } from '@react-universal/core';
5-
import { runIfFunction } from '@react-universal/utils';
3+
import { styled, useOwnerState, usePressEvents } from '@react-universal/core';
4+
import { composeEventHandlers, runIfFunction } from '@react-universal/utils';
65
import { useComposedRefs } from '@tamagui/compose-refs';
76
import { useRef, useState } from 'react';
8-
import type {
9-
BlurEvent as RNBlurEvent,
10-
FocusEvent as RNFocusEvent,
11-
MouseEvent as RNMouseEvent,
12-
} from 'react-native';
7+
import type { BlurEvent as RNBlurEvent, FocusEvent as RNFocusEvent } from 'react-native';
138
import { View } from '../View';
14-
import type { ButtonMethods, ButtonOwnerState, ButtonProps } from './Button.types';
9+
import type { ButtonOwnerState, ButtonProps } from './Button.types';
1510

1611
const ButtonRoot = styled(View, {
1712
name: 'Button',
1813
slot: 'Root',
1914
shouldForwardProp: (prop) => prop !== 'ownerState' && prop !== 'theme' && prop !== 'sx',
2015
})<{
2116
disabled?: boolean;
22-
onMouseDown?: React.MouseEventHandler<HTMLElement>;
2317
ownerState: ButtonOwnerState;
2418
type?: 'button' | 'submit' | 'reset';
2519
}>({
@@ -39,19 +33,33 @@ const ButtonRoot = styled(View, {
3933
},
4034
});
4135

42-
export const Button: React.FC<ButtonProps & { ref?: React.Ref<HTMLElement & ButtonMethods> }> = ({
36+
export const Button: React.FC<ButtonProps & { ref?: React.Ref<HTMLElement> }> = ({
4337
as: _as,
4438
children,
39+
delayLongPress,
4540
disabled = false,
4641
href,
4742
onBlur,
43+
onClick,
44+
onResponderTerminationRequest,
45+
onContextMenu,
4846
onFocus,
4947
onFocusVisible,
48+
onResponderTerminate,
49+
onResponderMove,
50+
onStartShouldSetResponder,
51+
onMouseEnter,
52+
onMouseLeave,
5053
onHoverIn,
5154
onHoverOut,
5255
onKeyDown,
53-
onKeyUp,
56+
onLongPress,
5457
onPress,
58+
onPressIn,
59+
onPressMove,
60+
onResponderRelease,
61+
onPressOut,
62+
onResponderGrant,
5563
ref,
5664
style,
5765
tabIndex,
@@ -68,16 +76,18 @@ export const Button: React.FC<ButtonProps & { ref?: React.Ref<HTMLElement & Butt
6876
setFocusVisible(false);
6977
}
7078

71-
const handleMouseEnter = (event: RNMouseEvent) => {
79+
const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
7280
setHovered(true);
7381
onHoverIn?.(event);
82+
onMouseEnter?.(event);
7483
};
7584

76-
const handleMouseLeave = (event: RNMouseEvent) => {
85+
const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
7786
if (focusVisible) {
7887
event.preventDefault();
7988
}
8089
onHoverOut?.(event);
90+
onMouseLeave?.(event);
8191
};
8292

8393
const handleBlur = (event: RNBlurEvent) => {
@@ -102,77 +112,16 @@ export const Button: React.FC<ButtonProps & { ref?: React.Ref<HTMLElement & Butt
102112
onFocus?.(event);
103113
};
104114

105-
const isNativeButton = () =>
106-
hostRef.current?.tagName === 'BUTTON' ||
107-
(hostRef.current?.tagName === 'A' && (hostRef.current as HTMLAnchorElement).href);
108-
109-
const handleClick = (event: ResponderEvent) => {
110-
if (!disabled) {
111-
onPress?.(event);
112-
}
113-
};
114-
115-
const handleMouseDown = () => {
116-
if (!disabled) {
117-
setPressed(true);
118-
document.addEventListener(
119-
'mouseup',
120-
() => {
121-
setPressed(false);
122-
},
123-
{ once: true },
124-
);
125-
}
126-
};
127-
128-
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
129-
onKeyDown?.(event);
130-
131-
if (event.defaultPrevented) {
132-
return;
133-
}
134-
135-
if (event.target === event.currentTarget && !isNativeButton() && event.key === ' ') {
136-
event.preventDefault();
137-
}
138-
139-
if (event.target === event.currentTarget && event.key === ' ' && !disabled) {
140-
setPressed(true);
141-
}
142-
143-
// Keyboard accessibility for non interactive elements
144-
if (
145-
event.target === event.currentTarget &&
146-
!isNativeButton() &&
147-
event.key === 'Enter' &&
148-
!disabled
149-
) {
150-
event.preventDefault();
151-
onPress?.(event as any);
152-
}
153-
};
154-
155-
const handleKeyUp = (event: React.KeyboardEvent<HTMLElement>) => {
156-
// calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
157-
// https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
158-
159-
if (event.target === event.currentTarget) {
160-
setPressed(false);
161-
}
162-
163-
onKeyUp?.(event);
164-
165-
// Keyboard accessibility for non interactive elements
166-
if (
167-
event.target === event.currentTarget &&
168-
!isNativeButton() &&
169-
!disabled &&
170-
event.key === ' ' &&
171-
!event.defaultPrevented
172-
) {
173-
onPress?.(event as any);
174-
}
175-
};
115+
const pressEventHandlers = usePressEvents(hostRef, {
116+
delayLongPress,
117+
disabled,
118+
onLongPress,
119+
onPress,
120+
onPressChange: setPressed,
121+
onPressIn,
122+
onPressMove,
123+
onPressOut,
124+
});
176125

177126
const handleRef = useComposedRefs<any>(hostRef, ref);
178127

@@ -193,13 +142,30 @@ export const Button: React.FC<ButtonProps & { ref?: React.Ref<HTMLElement & Butt
193142
style={runIfFunction(style, { focusVisible, hovered, pressed })}
194143
type={href == null ? (type ?? 'button') : undefined}
195144
onBlur={handleBlur}
196-
onClick={handleClick}
145+
onClick={composeEventHandlers(pressEventHandlers.onClick, onClick)}
146+
onContextMenu={composeEventHandlers(pressEventHandlers.onContextMenu, onContextMenu)}
197147
onFocus={handleFocus}
198-
onKeyDown={handleKeyDown}
199-
onKeyUp={handleKeyUp}
200-
onMouseDown={handleMouseDown}
148+
onKeyDown={composeEventHandlers(pressEventHandlers.onKeyDown, onKeyDown)}
201149
onMouseEnter={handleMouseEnter}
202150
onMouseLeave={handleMouseLeave}
151+
onResponderGrant={composeEventHandlers(pressEventHandlers.onResponderGrant, onResponderGrant)}
152+
onResponderMove={composeEventHandlers(pressEventHandlers.onResponderMove, onResponderMove)}
153+
onResponderRelease={composeEventHandlers(
154+
pressEventHandlers.onResponderRelease,
155+
onResponderRelease,
156+
)}
157+
onResponderTerminate={composeEventHandlers(
158+
pressEventHandlers.onResponderTerminate,
159+
onResponderTerminate,
160+
)}
161+
onResponderTerminationRequest={composeEventHandlers(
162+
pressEventHandlers.onResponderTerminationRequest,
163+
onResponderTerminationRequest,
164+
)}
165+
onStartShouldSetResponder={composeEventHandlers(
166+
pressEventHandlers.onStartShouldSetResponder,
167+
onStartShouldSetResponder,
168+
)}
203169
{...props}
204170
>
205171
{runIfFunction(children, { focusVisible, hovered, pressed })}

packages/components/src/Button/Button.types.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import type { ResponderEvent, StyleProp, SxProps } from '@react-universal/core';
22
import type { PressableProps as RNPressableProps, ViewProps as RNViewProps } from 'react-native';
3-
import type { ViewMethods, ViewProps, ViewStyle } from '../View';
4-
5-
export interface ButtonMethods extends ViewMethods {}
3+
import type { ViewProps, ViewStyle } from '../View';
64

75
export interface ButtonStateCallbackType {
86
readonly focusVisible: boolean;
@@ -13,15 +11,26 @@ export interface ButtonStateCallbackType {
1311
export interface ButtonProps
1412
extends Omit<
1513
RNPressableProps,
16-
keyof RNViewProps | 'disabled' | 'onLongPress' | 'onPress' | 'onPressIn' | 'onPressOut'
14+
| keyof RNViewProps
15+
| 'disabled'
16+
| 'onHoverIn'
17+
| 'onHoverOut'
18+
| 'onLongPress'
19+
| 'onPress'
20+
| 'onPressIn'
21+
| 'onPressMove'
22+
| 'onPressOut'
1723
>,
1824
Omit<ViewProps, 'children' | 'style'> {
1925
children?: React.ReactNode | ((state: ButtonStateCallbackType) => React.ReactNode);
2026
disabled?: boolean;
2127
onFocusVisible?: RNPressableProps['onFocus'];
28+
onHoverIn?: (event: React.MouseEvent<HTMLElement>) => void;
29+
onHoverOut?: (event: React.MouseEvent<HTMLElement>) => void;
2230
onLongPress?: (event: ResponderEvent) => void;
2331
onPress?: (event: ResponderEvent) => void;
2432
onPressIn?: (event: ResponderEvent) => void;
33+
onPressMove?: (event: ResponderEvent) => void;
2534
onPressOut?: (event: ResponderEvent) => void;
2635
style?: StyleProp<ViewStyle> | ((state: ButtonStateCallbackType) => StyleProp<ViewStyle>);
2736
/**
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
11
export { Button } from './Button';
2-
export type {
3-
ButtonMethods,
4-
ButtonProps,
5-
ButtonStateCallbackType,
6-
} from './Button.types';
2+
export type { ButtonProps, ButtonStateCallbackType } from './Button.types';

packages/components/src/Container/Container.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { clamp, max, styled, useOwnerState } from '@react-universal/core';
44
import type { AnyObject } from '@react-universal/utils';
55
import { View } from '../View';
6-
import type { ContainerMethods, ContainerOwnerState, ContainerProps } from './Container.types';
6+
import type { ContainerOwnerState, ContainerProps } from './Container.types';
77

88
const MIN_WIDTH = '20rem';
99
const MAX_WIDTH = '90rem';
@@ -44,9 +44,11 @@ const ContainerRoot = styled(View, {
4444
},
4545
}));
4646

47-
export const Container: React.FC<
48-
ContainerProps & { ref?: React.Ref<HTMLElement & ContainerMethods> }
49-
> = ({ fixed = false, maxWidth = false, ...props }) => {
47+
export const Container: React.FC<ContainerProps & { ref?: React.Ref<HTMLElement> }> = ({
48+
fixed = false,
49+
maxWidth = false,
50+
...props
51+
}) => {
5052
const ownerState = useOwnerState({
5153
fixed,
5254
maxWidth,

packages/components/src/Container/Container.types.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import type { Breakpoint, SxProps } from '@react-universal/core';
2-
import type { ViewMethods, ViewProps } from '../View';
3-
4-
export interface ContainerMethods extends ViewMethods {}
2+
import type { ViewProps } from '../View';
53

64
export interface ContainerProps extends ViewProps {
75
/**
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { Container } from './Container';
2-
export type { ContainerMethods, ContainerProps } from './Container.types';
2+
export type { ContainerProps } from './Container.types';

0 commit comments

Comments
 (0)