diff options
Diffstat (limited to 'app/components/checkbox')
-rw-r--r-- | app/components/checkbox/checkbox.props.ts | 44 | ||||
-rw-r--r-- | app/components/checkbox/checkbox.story.tsx | 121 | ||||
-rw-r--r-- | app/components/checkbox/checkbox.tsx | 53 |
3 files changed, 218 insertions, 0 deletions
diff --git a/app/components/checkbox/checkbox.props.ts b/app/components/checkbox/checkbox.props.ts new file mode 100644 index 0000000..01a13d0 --- /dev/null +++ b/app/components/checkbox/checkbox.props.ts @@ -0,0 +1,44 @@ +import { StyleProp, ViewStyle } from "react-native" +import { TxKeyPath } from "../../i18n" + +export interface CheckboxProps { + /** + * Additional container style. Useful for margins. + */ + style?: StyleProp<ViewStyle> + + /** + * Additional outline style. + */ + outlineStyle?: StyleProp<ViewStyle> + + /** + * Additional fill style. Only visible when checked. + */ + fillStyle?: StyleProp<ViewStyle> + + /** + * Is the checkbox checked? + */ + value?: boolean + + /** + * The text to display if there isn't a tx. + */ + text?: string + + /** + * The i18n lookup key. + */ + tx?: TxKeyPath + + /** + * Multiline or clipped single line? + */ + multiline?: boolean + + /** + * Fires when the user tabs to change the value. + */ + onToggle?: (newValue: boolean) => void +} diff --git a/app/components/checkbox/checkbox.story.tsx b/app/components/checkbox/checkbox.story.tsx new file mode 100644 index 0000000..f8d80d8 --- /dev/null +++ b/app/components/checkbox/checkbox.story.tsx @@ -0,0 +1,121 @@ +/* eslint-disable react-native/no-inline-styles */ +/* eslint-disable react-native/no-color-literals */ + +import * as React from "react" +import { View, ViewStyle } from "react-native" +import { storiesOf } from "@storybook/react-native" +import { StoryScreen, Story, UseCase } from "../../../storybook/views" +import { Checkbox } from "./checkbox" +import { Toggle } from "react-powerplug" + +declare let module + +const arrayStyle: ViewStyle[] = [{ paddingVertical: 40 }, { alignSelf: "flex-end" }] +const arrayOutlineStyle: ViewStyle[] = [{ borderColor: "#b443c9" }, { borderWidth: 25 }] +const arrayFillStyle: ViewStyle[] = [{ backgroundColor: "#55e0ff" }] + +storiesOf("Checkbox", module) + .addDecorator((fn) => <StoryScreen>{fn()}</StoryScreen>) + .add("Behaviour", () => ( + <Story> + <UseCase text="The Checkbox" usage="Use the checkbox to represent on/off states."> + <Toggle initial={false}> + {({ on, toggle }) => <Checkbox value={on} onToggle={toggle} text="Toggle me" />} + </Toggle> + </UseCase> + <UseCase text="value = true" usage="This is permanently on."> + <Checkbox value={true} text="Always on" /> + </UseCase> + <UseCase text="value = false" usage="This is permanantly off."> + <Checkbox value={false} text="Always off" /> + </UseCase> + </Story> + )) + .add("Styling", () => ( + <Story> + <UseCase text="multiline = true" usage="For really really long text"> + <Toggle initial={false}> + {({ on, toggle }) => ( + <View> + <Checkbox + text="We’re an App Design & Development Team. Experts in mobile & web technologies. We create beautiful, functional mobile apps and websites." + value={on} + multiline + onToggle={toggle} + /> + </View> + )} + </Toggle> + </UseCase> + <UseCase text=".style" usage="Override the container style"> + <Toggle initial={false}> + {({ on, toggle }) => ( + <View> + <Checkbox + text="Hello there!" + value={on} + style={{ + backgroundColor: "purple", + marginLeft: 40, + paddingVertical: 30, + paddingLeft: 60, + }} + onToggle={toggle} + /> + </View> + )} + </Toggle> + </UseCase> + <UseCase text=".outlineStyle" usage="Override the outline style"> + <Toggle initial={false}> + {({ on, toggle }) => ( + <View> + <Checkbox + text="Outline is the box frame" + value={on} + outlineStyle={{ + borderColor: "green", + borderRadius: 10, + borderWidth: 4, + width: 60, + height: 20, + }} + onToggle={toggle} + /> + </View> + )} + </Toggle> + </UseCase> + <UseCase text=".fillStyle" usage="Override the fill style"> + <Toggle initial={false}> + {({ on, toggle }) => ( + <View> + <Checkbox + text="Fill er up" + value={on} + fillStyle={{ backgroundColor: "red", borderRadius: 8 }} + onToggle={toggle} + /> + </View> + )} + </Toggle> + </UseCase> + + <UseCase text="Array style" usage="Use array styles"> + <Toggle initial={false}> + {({ on, toggle }) => ( + <View> + <Checkbox + text="Check it twice" + value={on} + onToggle={toggle} + style={arrayStyle} + outlineStyle={arrayOutlineStyle} + fillStyle={arrayFillStyle} + /> + </View> + )} + </Toggle> + </UseCase> + </Story> + )) diff --git a/app/components/checkbox/checkbox.tsx b/app/components/checkbox/checkbox.tsx new file mode 100644 index 0000000..fc3992a --- /dev/null +++ b/app/components/checkbox/checkbox.tsx @@ -0,0 +1,53 @@ +import * as React from "react" +import { TextStyle, TouchableOpacity, View, ViewStyle } from "react-native" +import { Text } from "../text/text" +import { color, spacing } from "../../theme" +import { CheckboxProps } from "./checkbox.props" + +const ROOT: ViewStyle = { + flexDirection: "row", + paddingVertical: spacing[1], + alignSelf: "flex-start", +} + +const DIMENSIONS = { width: 16, height: 16 } + +const OUTLINE: ViewStyle = { + ...DIMENSIONS, + marginTop: 2, // finicky and will depend on font/line-height/baseline/weather + justifyContent: "center", + alignItems: "center", + borderWidth: 1, + borderColor: color.primaryDarker, + borderRadius: 1, +} + +const FILL: ViewStyle = { + width: DIMENSIONS.width - 4, + height: DIMENSIONS.height - 4, + backgroundColor: color.primary, +} + +const LABEL: TextStyle = { paddingLeft: spacing[2] } + +export function Checkbox(props: CheckboxProps) { + const numberOfLines = props.multiline ? 0 : 1 + + const rootStyle = [ROOT, props.style] + const outlineStyle = [OUTLINE, props.outlineStyle] + const fillStyle = [FILL, props.fillStyle] + + const onPress = props.onToggle ? () => props.onToggle && props.onToggle(!props.value) : null + + return ( + <TouchableOpacity + activeOpacity={1} + disabled={!props.onToggle} + onPress={onPress} + style={rootStyle} + > + <View style={outlineStyle}>{props.value && <View style={fillStyle} />}</View> + <Text text={props.text} tx={props.tx} numberOfLines={numberOfLines} style={LABEL} /> + </TouchableOpacity> + ) +} |