Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ref property to Buttons #2903

Merged
merged 6 commits into from
May 17, 2024
Merged
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
40 changes: 36 additions & 4 deletions src/components/GestureButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export interface RawButtonProps extends NativeViewGestureHandlerProps {
touchSoundDisabled?: boolean;
}

interface ButtonWithRefProps {
innerRef?: React.ForwardedRef<React.ComponentType<any>>;
}

export interface BaseButtonProps extends RawButtonProps {
/**
* Called when the button gets pressed (analogous to `onPress` in
Expand Down Expand Up @@ -94,6 +98,8 @@ export interface BaseButtonProps extends RawButtonProps {
delayLongPress?: number;
}

interface BaseButtonWithRefProps extends BaseButtonProps, ButtonWithRefProps {}

export interface RectButtonProps extends BaseButtonProps {
/**
* Background color that will be dimmed when button is in active state.
Expand All @@ -108,6 +114,8 @@ export interface RectButtonProps extends BaseButtonProps {
activeOpacity?: number;
}

interface RectButtonWithRefProps extends RectButtonProps, ButtonWithRefProps {}

export interface BorderlessButtonProps extends BaseButtonProps {
/**
* iOS only.
Expand All @@ -117,12 +125,16 @@ export interface BorderlessButtonProps extends BaseButtonProps {
activeOpacity?: number;
}

interface BorderlessButtonWithRefProps
extends BorderlessButtonProps,
ButtonWithRefProps {}

export const RawButton = createNativeWrapper(GestureHandlerButton, {
shouldCancelWhenOutside: false,
shouldActivateOnStart: false,
});

export class BaseButton extends React.Component<BaseButtonProps> {
class InnerBaseButton extends React.Component<BaseButtonWithRefProps> {
static defaultProps = {
delayLongPress: 600,
};
Expand Down Expand Up @@ -222,6 +234,7 @@ export class BaseButton extends React.Component<BaseButtonProps> {

return (
<RawButton
ref={this.props.innerRef}
rippleColor={processColor(rippleColor)}
{...rest}
onGestureEvent={this.onGestureEvent}
Expand All @@ -231,6 +244,11 @@ export class BaseButton extends React.Component<BaseButtonProps> {
}
}

export const BaseButton = React.forwardRef<
any,
Omit<BaseButtonProps, 'innerRef'>
>((props, ref) => <InnerBaseButton innerRef={ref} {...props} />);

const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);

const btnStyles = StyleSheet.create({
Expand All @@ -243,7 +261,7 @@ const btnStyles = StyleSheet.create({
},
});

export class RectButton extends React.Component<RectButtonProps> {
class InnerRectButton extends React.Component<RectButtonWithRefProps> {
static defaultProps = {
activeOpacity: 0.105,
underlayColor: 'black',
Expand Down Expand Up @@ -272,6 +290,7 @@ export class RectButton extends React.Component<RectButtonProps> {
return (
<BaseButton
{...rest}
ref={this.props.innerRef}
style={resolvedStyle}
onActiveStateChange={this.onActiveStateChange}>
<Animated.View
Expand All @@ -294,7 +313,12 @@ export class RectButton extends React.Component<RectButtonProps> {
}
}

export class BorderlessButton extends React.Component<BorderlessButtonProps> {
export const RectButton = React.forwardRef<
any,
Omit<RectButtonProps, 'innerRef'>
>((props, ref) => <InnerRectButton innerRef={ref} {...props} />);

class InnerBorderlessButton extends React.Component<BorderlessButtonWithRefProps> {
static defaultProps = {
activeOpacity: 0.3,
borderless: true,
Expand All @@ -316,11 +340,14 @@ export class BorderlessButton extends React.Component<BorderlessButtonProps> {
};

render() {
const { children, style, ...rest } = this.props;
const { children, style, innerRef, ...rest } = this.props;

return (
<AnimatedBaseButton
{...rest}
// @ts-ignore We don't want `innerRef` to be accessible from public API.
// However in this case we need to set it indirectly on `BaseButton`, hence we use ts-ignore
innerRef={innerRef}
onActiveStateChange={this.onActiveStateChange}
style={[style, Platform.OS === 'ios' && { opacity: this.opacity }]}>
{children}
Expand All @@ -329,4 +356,9 @@ export class BorderlessButton extends React.Component<BorderlessButtonProps> {
}
}

export const BorderlessButton = React.forwardRef<
any,
Omit<BorderlessButtonProps, 'innerRef'>
>((props, ref) => <InnerBorderlessButton innerRef={ref} {...props} />);

export { default as PureNativeButton } from './GestureHandlerButton';
Loading