Quick Intro to Storybook with React Native

Aaron K Saunders - Oct 14 '21 - - Dev Community

Overview

We start with a blank Expo application and show how to install and configure Storybook with React Native to run on your mobile device. We then add a new story which is a calendar component that allows you to pick a date from the calendar and return the response to the parent of the component

Source Code

This is the source code I used in the sample project I created. We walked through the installation and configuration process described in the Storybook React Native documentation

// picker.stories.js
import { action } from "@storybook/addon-actions";
import { storiesOf } from "@storybook/react-native";
import React from "react";
import { CalendarPicker } from "../../../components/CalendarPicker";
import CenterView from "../CenterView";

storiesOf("Pickers", module)
  .addDecorator((getStory) => <CenterView>{getStory()}</CenterView>)
  .add("basic calendar", () => (
    <CalendarPicker
      onCancelDate={action("onCancelDate")}
      onSaveDate={action("onSaveDate")}
    />
  ));
Enter fullscreen mode Exit fullscreen mode
// components/CalendarPicker.js
import React, { useState } from "react";
import { Text, View, Button, StyleSheet, TouchableOpacity } from "react-native";
import { Agenda, Calendar, LocaleConfig } from "react-native-calendars";

LocaleConfig.locales["en"] = {
  formatAccessibilityLabel: "dddd d 'of' MMMM 'of' yyyy",
  monthNames: [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
  ],
  monthNamesShort: [
    "jan",
    "feb",
    "mar",
    "apr",
    "may",
    "jun",
    "jul",
    "aug",
    "sep",
    "oct",
    "nov",
    "dec",
  ],
  dayNames: [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
  ],
  dayNamesShort: ["S", "M", "T", "W", "T", "F", "S"],
  // numbers: ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'] // number localization example
};
LocaleConfig.defaultLocale = "en";

export function CalendarPicker({ onSaveDate, onCancelDate }) {
  const [selectedDate, setSelectedDate] = useState(null);
  return (
    <View style={styles.container}>
      <Calendar
        style={{
          marginBottom: 10,
          width: "100%",
        }}
        // Initially visible month. Default = Date()
        // current={"2012-03-01"}
        // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
        // minDate={"2012-05-10"}
        // Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
        // maxDate={"2012-05-30"}
        // Handler which gets executed on day press. Default = undefined
        onDayPress={(day) => {
          console.log("selected day", day);
          setSelectedDate(day);
        }}
        // Handler which gets executed on day long press. Default = undefined
        onDayLongPress={(day) => {
          console.log("selected day", day);
        }}
        // Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
        // monthFormat={"yyyy MM"}
        // Handler which gets executed when visible month changes in calendar. Default = undefined
        onMonthChange={(month) => {
          console.log("month changed", month);
        }}
        // Hide month navigation arrows. Default = false
        // hideArrows={true}
        // Replace default arrows with custom ones (direction can be 'left' or 'right')
        // renderArrow={(direction) => <Arrow />}
        // Do not show days of other months in month page. Default = false
        hideExtraDays={true}
        // If hideArrows = false and hideExtraDays = false do not switch month when tapping on greyed out
        // day from another month that is visible in calendar page. Default = false
        disableMonthChange={false}
        // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday
        firstDay={1}
        // Hide day names. Default = false
        // hideDayNames={true}
        // Show week numbers to the left. Default = false
        showWeekNumbers={false}
        // Handler which gets executed when press arrow icon left. It receive a callback can go back month
        onPressArrowLeft={(subtractMonth) => subtractMonth()}
        // Handler which gets executed when press arrow icon right. It receive a callback can go next month
        onPressArrowRight={(addMonth) => addMonth()}
        // Disable left arrow. Default = false
        disableArrowLeft={false}
        // Disable right arrow. Default = false
        disableArrowRight={false}
        // Disable all touch events for disabled days. can be override with disableTouchEvent in markedDates
        disableAllTouchEventsForDisabledDays={true}
        // Replace default month and year title with custom one. the function receive a date as parameter
        // renderHeader={(date) => {
        //   /*Return JSX*/
        // }}
        // Enable the option to swipe between months. Default = false
        enableSwipeMonths={true}
      />
      <View
        style={{
          backgroundColor: "grey",
          alignItems: "center",
          paddingHorizontal: 20,
          paddingVertical: 12,
          borderRadius: 8,
        }}
      >
        <View>
          <Text
            style={{ fontSize: "large", fontWeight: "bold", color: "white" }}
          >
            SELECTED DATE
          </Text>
        </View>
        <View>
          <Text
            style={{ fontSize: "large", fontWeight: "bold", color: "white" }}
          >
            {selectedDate?.dateString}
          </Text>
        </View>
      </View>
      <View
        style={{
          flexDirection: "row",
          justifyContent: "space-evenly",
          paddingHorizontal: 12,
        }}
      >
        <TouchableOpacity
          onPress={() => pickDocument()}
          style={{
            backgroundColor: "green",
            padding: 8,
            margin: 12,
            alignItems: "center",
            width: "45%",
            borderRadius: 8,
          }}
        >
          <Text
            style={{
              color: "white",
              fontWeight: "bold",
              textTransform: "uppercase",
              textAlign: "center",
            }}
            onPress={() => onSaveDate(selectedDate)}
          >
            SAVE SELECTED DATE
          </Text>
        </TouchableOpacity>
        <TouchableOpacity
          onPress={() => onCancelDate(null)}
          style={{
            backgroundColor: "red",
            padding: 8,
            margin: 12,
            alignItems: "center",
            width: "45%",
            borderRadius: 8,
            alignContent: "center",
            justifyContent: "center",
          }}
        >
          <Text
            style={{
              color: "white",
              fontWeight: "bold",
              textTransform: "uppercase",
            }}
          >
            CANCEL
          </Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
    // borderColor: "grey",
    // borderWidth: 1,
  },
});
Enter fullscreen mode Exit fullscreen mode
// storybook/stories/index.js
import "./Button/Button.stories";
import "./Welcome/Welcome.stories";
import "./Picker/Picker.stories"; //<== NEW
Enter fullscreen mode Exit fullscreen mode

Links

React Native Video Playlist

ko-fi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .