From f8229500a1473dcd1c170a61662f525e8cbd2205 Mon Sep 17 00:00:00 2001 From: jameswilddev Date: Thu, 25 Nov 2021 16:42:48 +0000 Subject: [PATCH] Add flash messages. --- .../createFlashMessageComponent/index.tsx | 110 ++ .../createFlashMessageComponent/readme.md | 76 ++ .../createFlashMessageComponent/unit.tsx | 1125 +++++++++++++++++ index.ts | 3 + readme.md | 3 + types/FlashMessageState/index.tsx | 15 + types/FlashMessageState/readme.md | 14 + types/FlashMessageStyle/index.tsx | 55 + types/FlashMessageStyle/readme.md | 45 + 9 files changed, 1446 insertions(+) create mode 100644 components/createFlashMessageComponent/index.tsx create mode 100644 components/createFlashMessageComponent/readme.md create mode 100644 components/createFlashMessageComponent/unit.tsx create mode 100644 types/FlashMessageState/index.tsx create mode 100644 types/FlashMessageState/readme.md create mode 100644 types/FlashMessageStyle/index.tsx create mode 100644 types/FlashMessageStyle/readme.md diff --git a/components/createFlashMessageComponent/index.tsx b/components/createFlashMessageComponent/index.tsx new file mode 100644 index 00000000..a8ac0a29 --- /dev/null +++ b/components/createFlashMessageComponent/index.tsx @@ -0,0 +1,110 @@ +import * as React from "react"; +import { StyleSheet, Text, TextStyle, ViewStyle } from "react-native"; +import { useRefresh } from "../../hooks/useRefresh"; +import type { FlashMessageState } from "../../types/FlashMessageState"; +import type { FlashMessageStyle } from "../../types/FlashMessageStyle"; +import { Hitbox } from "../Hitbox"; + +/** + * Creates a new React component representing a flash message. + * @template T The names of the types available. + * @param flashMessageStyle The style of the flash message to create. + * @returns The created React component. + */ +export function createFlashMessageComponent( + flashMessageStyle: FlashMessageStyle +): React.FunctionComponent<{ + /** + * When null, the flash message is closed. When non-null, the details of the + * flash message which may be displayed (the user can dismiss the current + * message). + */ + readonly state: null | FlashMessageState; +}> { + const hitboxStylesInput: { [TKey in T]?: ViewStyle } = {}; + const textStylesInput: { [TKey in T]?: TextStyle } = {}; + + for (const typeKey in flashMessageStyle.types) { + const typeValue = flashMessageStyle.types[typeKey]; + + const hitboxStyle: ViewStyle = { + backgroundColor: typeValue.backgroundColor, + }; + + if (typeValue.border !== null) { + hitboxStyle.borderWidth = typeValue.border.width; + hitboxStyle.borderColor = typeValue.border.color; + } + + if (flashMessageStyle.horizontalPadding !== 0) { + hitboxStyle.paddingHorizontal = flashMessageStyle.horizontalPadding; + } + + if (flashMessageStyle.verticalPadding !== 0) { + hitboxStyle.paddingVertical = flashMessageStyle.verticalPadding; + } + + if (flashMessageStyle.radius !== 0) { + hitboxStyle.borderRadius = flashMessageStyle.radius; + } + + hitboxStylesInput[typeKey] = hitboxStyle; + + const textStyle: TextStyle = { + fontFamily: flashMessageStyle.fontFamily, + fontSize: flashMessageStyle.fontSize, + lineHeight: flashMessageStyle.fontSize * 1.4, + color: typeValue.color, + }; + + textStylesInput[typeKey] = textStyle; + } + + const hitboxStyles = StyleSheet.create( + hitboxStylesInput as { readonly [TKey in T]: ViewStyle } + ); + + const textStyles = StyleSheet.create( + textStylesInput as { readonly [TKey in T]: TextStyle } + ); + + return ({ state }) => { + const refresh = useRefresh(); + const internalState = React.useRef({ + open: state !== null, + type: state === null ? null : state.type, + message: state === null ? null : state.message, + }); + + if (state === null) { + internalState.current.open = false; + internalState.current.type = null; + internalState.current.message = null; + } else if ( + state.type !== internalState.current.type || + state.message !== internalState.current.message + ) { + internalState.current.open = true; + internalState.current.type = state.type; + internalState.current.message = state.message; + } + + if (state !== null && internalState.current.open) { + return ( + { + console.log("let us go!"); + internalState.current.open = false; + refresh(); + }} + style={hitboxStyles[state.type]} + > + {state.message} + + ); + } else { + return null; + } + }; +} diff --git a/components/createFlashMessageComponent/readme.md b/components/createFlashMessageComponent/readme.md new file mode 100644 index 00000000..b63dc634 --- /dev/null +++ b/components/createFlashMessageComponent/readme.md @@ -0,0 +1,76 @@ +# `react-native-app-helpers/createFlashMessageComponent` + +Creates a new React component representing a flash message. + +## Usage + +```tsx +import { createFlashMessageComponent, FlashMessageState } from "react-native-app-helpers"; +import { Button } from "react-native"; + +const ExampleFlashMessage = createFlashMessageComponent( +{ + fontFamily: `Example Font Family`, + fontSize: 25, + radius: 12, + horizontalPadding: 41, + verticalPadding: 57, + types: { + exampleTypeA: { + backgroundColor: `red`, + color: `green`, + border: null, + }, + exampleTypeB: { + backgroundColor: `blue`, + color: `yellow`, + border: { + width: 15, + color: `orange`, + }, + }, + exampleTypeC: { + backgroundColor: `purple`, + color: `cyan`, + border: null, + }, + exampleTypeD: { + backgroundColor: `magenta`, + color: `black`, + border: { + width: 24, + color: `white`, + }, + }, + }, + } +); + +const ExampleScreen = () => { + const [state, setState] = React.useState>(null); + + return ( + + +