Skip to content

Commit

Permalink
Migrate 'FormSubmit' component to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
pasyukevich committed Nov 30, 2023
1 parent 56a368b commit 9f7dd2a
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 72 deletions.
27 changes: 0 additions & 27 deletions src/components/FormSubmit/formSubmitPropTypes.js

This file was deleted.

18 changes: 0 additions & 18 deletions src/components/FormSubmit/index.native.js

This file was deleted.

18 changes: 18 additions & 0 deletions src/components/FormSubmit/index.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import {View} from 'react-native';
import {FormSubmitProps, FormSubmitRef} from './types';

function FormSubmit({style, children}: FormSubmitProps, ref: FormSubmitRef) {
return (
<View
ref={ref}
style={style}
>
{children}
</View>
);
}

FormSubmit.displayName = 'FormSubmit';

export default React.forwardRef(FormSubmit);
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import lodashGet from 'lodash/get';
import React, {useEffect} from 'react';
import React, {KeyboardEvent as ReactKeyboardEvent, useEffect} from 'react';
import {View} from 'react-native';
import * as ComponentUtils from '@libs/ComponentUtils';
import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
import CONST from '@src/CONST';
import * as formSubmitPropTypes from './formSubmitPropTypes';
import {FormSubmitProps, FormSubmitRef} from './types';

function FormSubmit({innerRef, children, onSubmit, style}) {
function FormSubmit({children, onSubmit, style}: FormSubmitProps, ref: FormSubmitRef) {
/**
* Calls the submit callback when ENTER is pressed on a form element.
* @param {Object} event
*/
const submitForm = (event) => {
const submitForm = (event: ReactKeyboardEvent) => {
// ENTER is pressed with modifier key or during text composition, do not submit the form
if (event.shiftKey || event.key !== CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey || isEnterWhileComposition(event)) {
return;
}

const tagName = lodashGet(event, 'target.tagName', '');
const eventTarget = event.target as HTMLElement;

const tagName = eventTarget?.tagName ?? '';

// ENTER is pressed on INPUT or SELECT element, call the submit callback.
if (tagName === 'INPUT' || tagName === 'SELECT') {
Expand All @@ -26,22 +26,30 @@ function FormSubmit({innerRef, children, onSubmit, style}) {
}

// Pressing Enter on TEXTAREA element adds a new line. When `dataset.submitOnEnter` prop is passed, call the submit callback.
if (tagName === 'TEXTAREA' && lodashGet(event, 'target.dataset.submitOnEnter', 'false') === 'true') {
if (tagName === 'TEXTAREA' && (eventTarget?.dataset?.submitOnEnter ?? 'false') === 'true') {
event.preventDefault();
onSubmit();
return;
}

// ENTER is pressed on checkbox element, call the submit callback.
if (lodashGet(event, 'target.role') === 'checkbox') {
if (eventTarget?.role === 'checkbox') {
onSubmit();
}
};

const preventDefaultFormBehavior = (e) => e.preventDefault();
const preventDefaultFormBehavior = (e: SubmitEvent) => e.preventDefault();

useEffect(() => {
const form = innerRef.current;
if (!(ref && 'current' in ref)) {
return;
}

const form = ref.current as HTMLFormElement | null;

if (!form) {
return;
}

// Prevent the browser from applying its own validation, which affects the email input
form.setAttribute('novalidate', '');
Expand All @@ -55,15 +63,15 @@ function FormSubmit({innerRef, children, onSubmit, style}) {

form.removeEventListener('submit', preventDefaultFormBehavior);
};
}, [innerRef]);
}, [ref]);

return (
// React-native-web prevents event bubbling on TextInput for key presses
// https://github.com/necolas/react-native-web/blob/fa47f80d34ee6cde2536b2a2241e326f84b633c4/packages/react-native-web/src/exports/TextInput/index.js#L272
// Thus use capture phase.
<View
role={ComponentUtils.ACCESSIBILITY_ROLE_FORM}
ref={innerRef}
ref={ref}
onKeyDownCapture={submitForm}
style={style}
>
Expand All @@ -72,17 +80,6 @@ function FormSubmit({innerRef, children, onSubmit, style}) {
);
}

FormSubmit.propTypes = formSubmitPropTypes.propTypes;
FormSubmit.defaultProps = formSubmitPropTypes.defaultProps;

const FormSubmitWithRef = React.forwardRef((props, ref) => (
<FormSubmit
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
innerRef={ref}
/>
));

FormSubmitWithRef.displayName = 'FormSubmitWithRef';
FormSubmit.displayName = 'FormSubmitWithRef';

export default FormSubmitWithRef;
export default React.forwardRef(FormSubmit);
12 changes: 12 additions & 0 deletions src/components/FormSubmit/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, {ForwardedRef} from 'react';
import {StyleProp, View, ViewStyle} from 'react-native';

type FormSubmitProps = {
children: React.ReactNode;
onSubmit: () => void;
style?: StyleProp<ViewStyle>;
};

type FormSubmitRef = ForwardedRef<View>;

export type {FormSubmitProps, FormSubmitRef};
3 changes: 2 additions & 1 deletion src/libs/KeyboardShortcut/isEnterWhileComposition.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import {NativeSyntheticEvent} from 'react-native';
import * as Browser from '@libs/Browser';
import CONST from '@src/CONST';
Expand All @@ -6,7 +7,7 @@ import CONST from '@src/CONST';
* Check if the Enter key was pressed during IME confirmation (i.e. while the text is being composed).
* See {@link https://en.wikipedia.org/wiki/Input_method}
*/
const isEnterWhileComposition = (event: KeyboardEvent): boolean => {
const isEnterWhileComposition = (event: KeyboardEvent | React.KeyboardEvent): boolean => {
// if on mobile chrome, the enter key event is never fired when the enter key is pressed while composition.
if (Browser.isMobileChrome()) {
return false;
Expand Down

0 comments on commit 9f7dd2a

Please sign in to comment.