Skip to content

Commit

Permalink
fix: submit on last field, keyboard dismiss + fix go to next field in…
Browse files Browse the repository at this point in the history
… modals
  • Loading branch information
RichardLindhout committed May 25, 2023
1 parent da2cbf4 commit 51fbf2f
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 275 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Simple form library for React Native with great UX for developer and end-user ap
- Email, username, password, number, numberText, decimal, decimalText,
- Great typescript support!
- Nested object with dot notation
- Nested forms
- ~~Nested forms~~ (don't work well yet)
- Great decimal support with support for , notation and automatically convert it to a Number object

See a demo: https://twitter.com/RichardLindhout/status/1344009881863516165
Expand Down
153 changes: 88 additions & 65 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
Form,
useFormState,
} from 'react-native-use-form';
import { Appbar, Button, Surface, Text, Title } from 'react-native-paper';
import { Appbar, Button, Text } from 'react-native-paper';
import TextInputWithError from './TextInputWithError';
import { useRef } from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
Expand All @@ -30,7 +30,9 @@ type FormType = {
password: string;
age: number | undefined;
money: number | undefined;
description: string | undefined;
postalCode: string | undefined;
postalCodeDisabled: string | undefined;
organization: {
name: string;
telephone: string;
Expand All @@ -52,9 +54,11 @@ export default function App() {
email: '',
telephone: '',
password: '',
age: 0,
money: 0,
age: undefined,
money: undefined,
description: '',
postalCode: '',
postalCodeDisabled: '',
organization: {
name: '',
telephone: '',
Expand Down Expand Up @@ -135,6 +139,16 @@ export default function App() {
label: 'Postalcode',
})}
/>
<TextInputWithError
editable={false}
mode="outlined"
{...fh.text('postalCode', {
enhance: (v) => {
return (v || '').toUpperCase();
},
label: 'Postalcode (disabled)',
})}
/>

<TextInputWithError
mode="outlined"
Expand Down Expand Up @@ -189,8 +203,17 @@ export default function App() {
label: 'Organization revenue',
})}
/>
<AddressEdit {...fh.raw('address')} />
<AddressCompanyEdit {...fh.raw('address.company')} />
<TextInputWithError
mode="outlined"
{...fh.text('description', {
label: 'Description',
required: true,
minLength: 3,
maxLength: 10,
})}
/>
{/*<AddressEdit {...fh.raw('address')} />*/}
{/*<AddressCompanyEdit {...fh.raw('address.company')} />*/}
<Button
mode="contained"
onPress={submit}
Expand All @@ -206,66 +229,66 @@ export default function App() {
);
}

function AddressEdit({
value,
onChange,
...rest
}: {
value: AddressType | null | undefined;
onChange: (v: AddressType | null | undefined) => void;
}) {
const [{ formProps }, fh] = useFormState<AddressType>(
value || { street: '', houseNumber: '', company: { name: '' } },
{
onChange,
}
);
return (
<Surface {...rest}>
<Title>Nested form</Title>
<Form {...formProps}>
<TextInputWithError
mode="outlined"
label="Street"
{...fh.streetAddress('street', { required: true })}
/>
<TextInputWithError
mode="outlined"
label="House number"
{...fh.streetAddress('houseNumber')}
/>
</Form>
</Surface>
);
}

function AddressCompanyEdit({
value,
onChange,
...rest
}: {
value: AddressCompany | undefined | null;
onChange: (v: AddressCompany | undefined | null) => void;
}) {
const [{ formProps }, fh] = useFormState<AddressCompany>(
value || { name: '' },
{
onChange,
}
);
return (
<Surface {...rest} style={{ padding: 12 }}>
<Title>Nested form</Title>
<Form {...formProps}>
<TextInputWithError
mode="outlined"
label="Street"
{...fh.text('name')}
/>
</Form>
</Surface>
);
}
// function AddressEdit({
// value,
// onChange,
// ...rest
// }: {
// value: AddressType | null | undefined;
// onChange: (v: AddressType | null | undefined) => void;
// }) {
// const [{ formProps }, fh] = useFormState<AddressType>(
// value || { street: '', houseNumber: '', company: { name: '' } },
// {
// onChange,
// }
// );
// return (
// <Surface {...rest}>
// <Title>Nested form</Title>
// <Form {...formProps}>
// <TextInputWithError
// mode="outlined"
// label="Street"
// {...fh.streetAddress('street', { required: true })}
// />
// <TextInputWithError
// mode="outlined"
// label="House number"
// {...fh.streetAddress('houseNumber')}
// />
// </Form>
// </Surface>
// );
// }
//
// function AddressCompanyEdit({
// value,
// onChange,
// ...rest
// }: {
// value: AddressCompany | undefined | null;
// onChange: (v: AddressCompany | undefined | null) => void;
// }) {
// const [{ formProps }, fh] = useFormState<AddressCompany>(
// value || { name: '' },
// {
// onChange,
// }
// );
// return (
// <Surface {...rest} style={{ padding: 12 }}>
// <Title>Nested form</Title>
// <Form {...formProps}>
// <TextInputWithError
// mode="outlined"
// label="Street"
// {...fh.text('name')}
// />
// </Form>
// </Surface>
// );
// }

const telephoneRegex = {
regex: new RegExp(/^\d+$/),
Expand Down
23 changes: 3 additions & 20 deletions src/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
import * as React from 'react';
import { FormContext } from './FormContext';
import type { IndexerType, ReferencerType } from './types';

export default function Form({
children,
referencer,
indexer,
}: {
children: any;
indexer: IndexerType;
referencer: ReferencerType;
}) {
return (
<FormContext.Provider
value={{
indexer,
referencer,
}}
>
{children}
</FormContext.Provider>
);
const empty = {};
export default function Form({ children }: { children: any }) {
return <FormContext.Provider value={empty}>{children}</FormContext.Provider>;
}
14 changes: 3 additions & 11 deletions src/FormContext.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import * as React from 'react';
import type { IndexerType, ReferencerType } from './types';
// import { MutableRefObject } from 'react';

export type FormContextType = {
indexer: IndexerType;
referencer: ReferencerType;
export type FormContextType = {};
const empty = {};

// refForKey: MutableRefObject<FormRefKeyMap>;
};

export const FormContext = React.createContext<FormContextType | undefined>(
undefined
);
export const FormContext = React.createContext<FormContextType>(empty);
2 changes: 2 additions & 0 deletions src/hasVirtualKeyboard.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const hasVirtualKeyboard = true;
export default hasVirtualKeyboard;
22 changes: 22 additions & 0 deletions src/hasVirtualKeyboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const hasTouch = 'ontouchstart' in window;

// const screenIsPortrait = window.matchMedia('(orientation: portrait)').matches;
// return screenIsPortrait ? 'portrait' : 'landscape';
// let heightPerOrientation: Record<string, number> = {
// [getOrientation()]: window.innerHeight,
// };
// window.addEventListener('resize', () => {
// const initialHeight = heightPerOrientation[getOrientation()];
// if (initialHeight) {
// if (window.innerHeight < initialHeight) {
// console.log('Virtual keyboard likely opened');
// } else {
// console.log('Virtual keyboard likely closed');
// initialHeight = window.innerHeight;
// }
// }
// });

const screenIsLarge = window.matchMedia('(min-width: 1000px)').matches;
const hasVirtualKeyboard = hasTouch && !screenIsLarge;
export default hasVirtualKeyboard;
18 changes: 2 additions & 16 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
TextInputFocusEventData,
TextInputProps,
} from 'react-native';
import type { TextInput } from 'react-native';

import type { ScrollView, View } from 'react-native';

type GetIndexedField<T, K> = K extends keyof NonNullable<T>
Expand Down Expand Up @@ -133,10 +133,7 @@ export type FormStateType<T> = {
// ) => void;
// clearErrors: () => void;
submit: () => void;
formProps: {
indexer: IndexerType;
referencer: ReferencerType;
};
formProps: {};
setValues: React.Dispatch<SetStateAction<T>>;
hasError: <K extends DotNestedKeys<T>>(key: K) => boolean;
};
Expand Down Expand Up @@ -245,14 +242,3 @@ type FormTextType<T> = <K extends DotNestedKeys<T>>(
export type FieldsLastCharacters<T> = {
[key in keyof T]?: string | undefined;
};

type ReferencerReturns = TextInputProps & { ref: React.Ref<TextInput> };
export type ReferencerType = (
key: string,
formIndex: number
) => ReferencerReturns;

export type IndexerType = {
add: () => number;
i: number;
};
16 changes: 0 additions & 16 deletions src/useFormContext.ts

This file was deleted.

Loading

0 comments on commit 51fbf2f

Please sign in to comment.