diff options
Diffstat (limited to 'storybook')
-rw-r--r-- | storybook/index.ts | 4 | ||||
-rw-r--r-- | storybook/storybook-registry.ts | 10 | ||||
-rw-r--r-- | storybook/storybook.tsx | 31 | ||||
-rw-r--r-- | storybook/toggle-storybook.tsx | 51 | ||||
-rw-r--r-- | storybook/toggle-storybook.web.tsx | 30 | ||||
-rw-r--r-- | storybook/views/index.ts | 3 | ||||
-rw-r--r-- | storybook/views/story-screen.tsx | 15 | ||||
-rw-r--r-- | storybook/views/story.tsx | 16 | ||||
-rw-r--r-- | storybook/views/use-case.tsx | 69 |
9 files changed, 229 insertions, 0 deletions
diff --git a/storybook/index.ts b/storybook/index.ts new file mode 100644 index 0000000..4a0399a --- /dev/null +++ b/storybook/index.ts @@ -0,0 +1,4 @@ +// this is the native storybook entry point +// import { StorybookUI } from "./config" + +export * from "./storybook" diff --git a/storybook/storybook-registry.ts b/storybook/storybook-registry.ts new file mode 100644 index 0000000..83f0ed8 --- /dev/null +++ b/storybook/storybook-registry.ts @@ -0,0 +1,10 @@ +require("../app/components/text/text.story") +require("../app/components/auto-image/auto-image.story") +require("../app/components/button/button.story") +require("../app/components/form-row/form-row.story") +require("../app/components/switch/switch.story") +require("../app/components/text-field/text-field.story") +require("../app/components/checkbox/checkbox.story") +require("../app/components/wallpaper/wallpaper.story") +require("../app/components/icon/icon.story") +require("../app/components/header/header.story") diff --git a/storybook/storybook.tsx b/storybook/storybook.tsx new file mode 100644 index 0000000..0479d4e --- /dev/null +++ b/storybook/storybook.tsx @@ -0,0 +1,31 @@ +import React, { useEffect } from "react" +import { getStorybookUI, configure } from "@storybook/react-native" +import { initFonts } from "../app/theme/fonts" + +declare let module + +configure(() => { + require("./storybook-registry") +}, module) + +const StorybookUI = getStorybookUI({ + port: 9001, + host: "localhost", + onDeviceUI: true, + asyncStorage: require("@react-native-async-storage/async-storage").default || null, +}) + +export function StorybookUIRoot() { + useEffect(() => { + ;(async () => { + await initFonts() // expo only + if (typeof __TEST__ === "undefined" || !__TEST__) { + const Reactotron = require("../app/services/reactotron") + const reactotron = new Reactotron.Reactotron() + reactotron.setup() + } + })() + }, []) + + return <StorybookUI /> +} diff --git a/storybook/toggle-storybook.tsx b/storybook/toggle-storybook.tsx new file mode 100644 index 0000000..394ecf4 --- /dev/null +++ b/storybook/toggle-storybook.tsx @@ -0,0 +1,51 @@ +import React, { useState, useEffect } from "react" +import { DevSettings } from "react-native" +import { loadString, saveString } from "../app/utils/storage" + +/** + * Toggle Storybook mode, in __DEV__ mode only. + * + * In non-__DEV__ mode, or when Storybook isn't toggled on, + * renders its children. + * + * The mode flag is persisted in async storage, which means it + * persists across reloads/restarts - this is handy when developing + * new components in Storybook. + */ +export function ToggleStorybook(props) { + const [showStorybook, setShowStorybook] = useState(false) + const [StorybookUIRoot, setStorybookUIRoot] = useState(null) + + useEffect(() => { + if (__DEV__ && DevSettings) { + // Load the setting from storage if it's there + loadString("devStorybook").then((storedSetting) => { + // Set the initial value + setShowStorybook(storedSetting === "on") + + // Add our toggle command to the menu + DevSettings.addMenuItem("Toggle Storybook", () => { + setShowStorybook((show) => { + // On toggle, flip the current value + show = !show + + // Write it back to storage + saveString("devStorybook", show ? "on" : "off") + + // Return it to change the local state + return show + }) + }) + + // Load the storybook UI once + setStorybookUIRoot(() => require("./storybook").StorybookUIRoot) + }) + } + }, []) + + if (showStorybook) { + return StorybookUIRoot ? <StorybookUIRoot /> : null + } else { + return props.children + } +} diff --git a/storybook/toggle-storybook.web.tsx b/storybook/toggle-storybook.web.tsx new file mode 100644 index 0000000..f1bd034 --- /dev/null +++ b/storybook/toggle-storybook.web.tsx @@ -0,0 +1,30 @@ +import React, { useState, useEffect } from "react" +import * as QueryString from "query-string" + +interface StorybookQueryParams { + storybook?: boolean +} + +export const ToggleStorybook = (props) => { + const [StorybookUIRoot, setStorybookUIRoot] = useState<any>(null) + const [queryParams, setQueryParams] = useState<StorybookQueryParams>({}) + + useEffect(() => { + if (__DEV__) { + // Load the storybook UI once + setStorybookUIRoot(() => require("./storybook").StorybookUIRoot) + } + }, []) + + useEffect(() => { + if (__DEV__) { + setQueryParams(QueryString.parse(window.location.search)) + } + }, [window.location.search]) + + if (queryParams?.storybook) { + return StorybookUIRoot ? <StorybookUIRoot /> : null + } else { + return props.children + } +} diff --git a/storybook/views/index.ts b/storybook/views/index.ts new file mode 100644 index 0000000..a722e53 --- /dev/null +++ b/storybook/views/index.ts @@ -0,0 +1,3 @@ +export * from "./story-screen" +export * from "./story" +export * from "./use-case" diff --git a/storybook/views/story-screen.tsx b/storybook/views/story-screen.tsx new file mode 100644 index 0000000..d83f6f5 --- /dev/null +++ b/storybook/views/story-screen.tsx @@ -0,0 +1,15 @@ +import * as React from "react" +import { ViewStyle, KeyboardAvoidingView, Platform } from "react-native" + +const ROOT: ViewStyle = { backgroundColor: "#f0f0f0", flex: 1 } + +export interface StoryScreenProps { + children?: React.ReactNode +} + +const behavior = Platform.OS === "ios" ? "padding" : undefined +export const StoryScreen = (props: StoryScreenProps) => ( + <KeyboardAvoidingView style={ROOT} behavior={behavior} keyboardVerticalOffset={50}> + {props.children} + </KeyboardAvoidingView> +) diff --git a/storybook/views/story.tsx b/storybook/views/story.tsx new file mode 100644 index 0000000..c85f7f0 --- /dev/null +++ b/storybook/views/story.tsx @@ -0,0 +1,16 @@ +import * as React from "react" +import { ScrollView, View, ViewStyle } from "react-native" + +export interface StoryProps { + children?: React.ReactNode +} + +const ROOT: ViewStyle = { flex: 1 } + +export function Story(props: StoryProps) { + return ( + <View style={ROOT}> + <ScrollView keyboardShouldPersistTaps="handled">{props.children}</ScrollView> + </View> + ) +} diff --git a/storybook/views/use-case.tsx b/storybook/views/use-case.tsx new file mode 100644 index 0000000..08b04b9 --- /dev/null +++ b/storybook/views/use-case.tsx @@ -0,0 +1,69 @@ +import * as React from "react" +import { View, Text, TextStyle, ViewStyle } from "react-native" + +const ROOT: ViewStyle = { backgroundColor: "#eee" } +const TITLE: TextStyle = { fontWeight: "600", color: "#3d3d3d" } +const TITLE_WRAPPER: ViewStyle = {} +const USE_CASE_WRAPPER: ViewStyle = { + position: "absolute", + top: 0, + left: 0, + right: 0, + borderTopColor: "#e6e6e6", + borderTopWidth: 1, + flexDirection: "row", +} +const USE_CASE: TextStyle = { + fontSize: 10, + color: "#666", + paddingHorizontal: 4, + paddingBottom: 2, +} +const USAGE: TextStyle = { color: "#666", fontSize: 10, paddingTop: 0 } +const HEADER: ViewStyle = { + paddingTop: 20, + paddingBottom: 10, + paddingHorizontal: 10, + borderBottomColor: "#e6e6e6", + borderBottomWidth: 1, +} +const COMPONENT: ViewStyle = { backgroundColor: "#fff" } + +export interface UseCaseProps { + /** The title. */ + text: string + /** When should we be using this? */ + usage?: string + /** The component use case. */ + children: React.ReactNode + /** A style override. Rarely used. */ + style?: ViewStyle + /** Don't use any padding because it's important to see the spacing. */ + noPad?: boolean + /** Don't use background color because it's important to see the color. */ + noBackground?: boolean +} + +export function UseCase(props: UseCaseProps) { + const style: ViewStyle = { + ...COMPONENT, + ...{ padding: props.noPad ? 0 : 10 }, + ...{ backgroundColor: props.noBackground ? "rgba(0,0,0,0)" : COMPONENT.backgroundColor }, + ...props.style, + } + + return ( + <View style={ROOT}> + <View style={HEADER}> + <View style={USE_CASE_WRAPPER}> + <Text style={USE_CASE}>Use Case</Text> + </View> + <View style={TITLE_WRAPPER}> + <Text style={TITLE}>{props.text}</Text> + </View> + {props.usage ? <Text style={USAGE}>{props.usage}</Text> : null} + </View> + <View style={style}>{props.children}</View> + </View> + ) +} |