-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aa9cd08
commit c81be37
Showing
8 changed files
with
1,627 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import * as React from "react"; | ||
import type { ControlStyle } from "../.."; | ||
import { createInputComponent } from "../createInputComponent"; | ||
|
||
/** | ||
* Creates a new input component pre-configured as a nullable text input. | ||
* @param controlStyle The style of the component to create. | ||
* @param leftIcon The icon to show on the left side, if any, else, null. | ||
* @param rightIcon The icon to show on the right side, if any, else, null. | ||
* @param minimumLength When non-null, entered values must be greater for | ||
* validation to succeed. | ||
* @param maximumLength When non-null, entered values must be greater or equal | ||
* for validation to succeed. | ||
* @returns The created component. | ||
*/ | ||
export const createNullableTextInputComponent = ( | ||
controlStyle: ControlStyle, | ||
leftIcon: null | React.ReactNode | JSX.Element, | ||
rightIcon: null | React.ReactNode | JSX.Element, | ||
minimumLength: null | number, | ||
maximumLength: null | number | ||
): React.FunctionComponent<{ | ||
/** | ||
* The value to edit. When undefined, it is treated as an invalid empty | ||
* string. | ||
*/ | ||
readonly value: undefined | null | string; | ||
|
||
/** | ||
* Invoked when the user edits the text in the box. | ||
* @param parsed The value parsed, or undefined should it not be parseable. | ||
* @param complete True when the user has finished editing, otherwise, false. | ||
*/ | ||
onChange(parsed: undefined | null | string, complete: boolean): void; | ||
|
||
/** | ||
* When true, the text box is rendered semi-transparently and does not accept | ||
* focus or input. | ||
*/ | ||
readonly disabled: boolean; | ||
|
||
/** | ||
* Text to be shown when no value has been entered. | ||
*/ | ||
readonly placeholder: string; | ||
|
||
/** | ||
* The value entered must not appear in this list. | ||
*/ | ||
readonly unique: ReadonlyArray<string>; | ||
}> => { | ||
const NullableTextInputComponent = createInputComponent< | ||
null | string, | ||
ReadonlyArray<string> | ||
>( | ||
(value) => (value === null ? `` : value.trim().replace(/\s+/g, ` `)), | ||
(unparsed, context) => { | ||
if (unparsed.trim() === ``) { | ||
return null; | ||
} else { | ||
const parsed = unparsed.trim().replace(/\s+/g, ` `); | ||
|
||
if (minimumLength !== null && parsed.length < minimumLength) { | ||
return undefined; | ||
} else if (maximumLength !== null && parsed.length > maximumLength) { | ||
return undefined; | ||
} else { | ||
const match = parsed.toLowerCase(); | ||
|
||
for (const option of context) { | ||
if (option.trim().replace(/\s+/g, ` `).toLowerCase() === match) { | ||
return undefined; | ||
} | ||
} | ||
|
||
return parsed; | ||
} | ||
} | ||
}, | ||
controlStyle, | ||
false, | ||
`off`, | ||
`default`, | ||
false, | ||
false | ||
); | ||
|
||
return ({ value, onChange, disabled, placeholder, unique }) => ( | ||
<NullableTextInputComponent | ||
leftIcon={leftIcon} | ||
rightIcon={rightIcon} | ||
value={value} | ||
onChange={onChange} | ||
disabled={disabled} | ||
placeholder={placeholder} | ||
context={unique} | ||
secureTextEntry={false} | ||
onSubmit={() => { | ||
/* No-op. */ | ||
}} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# `react-native-app-helpers/createNullableTextInputComponent` | ||
|
||
Creates a new input component pre-configured as a nullable text input. | ||
|
||
## Usage | ||
|
||
```tsx | ||
import { createNullableTextInputComponent } from "react-native-app-helpers"; | ||
|
||
const ExampleInput = createNullableTextInputComponent( | ||
{ | ||
fontFamily: `Example Font Family`, | ||
fontSize: 37, | ||
paddingVertical: 12, | ||
paddingHorizontal: 29, | ||
blurredValid: { | ||
textColor: `#FFEE00`, | ||
placeholderColor: `#E7AA32`, | ||
backgroundColor: `#32AE12`, | ||
radius: 5, | ||
border: { | ||
width: 4, | ||
color: `#FF00FF`, | ||
}, | ||
}, | ||
blurredInvalid: { | ||
textColor: `#99FE88`, | ||
placeholderColor: `#CACA3A`, | ||
backgroundColor: `#259284`, | ||
radius: 10, | ||
border: { | ||
width: 6, | ||
color: `#9A9A8E`, | ||
}, | ||
}, | ||
focusedValid: { | ||
textColor: `#55EA13`, | ||
placeholderColor: `#273346`, | ||
backgroundColor: `#CABA99`, | ||
radius: 3, | ||
border: { | ||
width: 5, | ||
color: `#646464`, | ||
}, | ||
}, | ||
focusedInvalid: { | ||
textColor: `#ABAADE`, | ||
placeholderColor: `#47ADAD`, | ||
backgroundColor: `#32AA88`, | ||
radius: 47, | ||
border: { | ||
width: 12, | ||
color: `#98ADAA`, | ||
}, | ||
}, | ||
disabledValid: { | ||
textColor: `#AE2195`, | ||
placeholderColor: `#FFAAEE`, | ||
backgroundColor: `#772728`, | ||
radius: 100, | ||
border: { | ||
width: 14, | ||
color: `#5E5E5E`, | ||
}, | ||
}, | ||
disabledInvalid: { | ||
textColor: `#340297`, | ||
placeholderColor: `#233832`, | ||
backgroundColor: `#938837`, | ||
radius: 2, | ||
border: { | ||
width: 19, | ||
color: `#573829`, | ||
}, | ||
}, | ||
}, | ||
<Text>Shown to the left</Text>, | ||
<Text>Shown to the right</Text>, | ||
null, | ||
-14, | ||
null, | ||
3, | ||
); | ||
|
||
const ExampleScreen = () => { | ||
// Useful for realtime submit button updates. | ||
const [incompleteValue, setIncompleteValue] = React.useState<undefined | null | number>(undefined); | ||
|
||
// Useful for persistence. | ||
const [completeValue, setCompleteValue] = React.useState<undefined | null | number>(undefined); | ||
|
||
return ( | ||
<React.Fragment> | ||
<ExampleInput | ||
value={incompleteValue} | ||
onChange={(value, complete) => { | ||
if (complete) { | ||
setCompleteValue(value); | ||
} else { | ||
setIncompleteValue(value); | ||
} | ||
}} | ||
disabled={false} | ||
placeholder="Shown when no text has been entered" | ||
unique={[`Not`, `In`, `This`, `List`]} | ||
/> | ||
<Text>Incomplete: {incompleteValue}</Text> | ||
<Text>Complete: {completeValue}</Text> | ||
<Text>Submitted: {submittedValue}</Text> | ||
</React.Fragment> | ||
); | ||
} | ||
``` |
Oops, something went wrong.