パッケージを作成フォームを作成する反応


したい予約フォームを作成するairbnb.com or booking.com 何週間も費やさずに、バグを修正してください.
react-booking-form Githubのパッケージを使用するだけで行うことができます!

プレビュー



ライブプレイグラウンド

Tooescript + TailWindCSSの例
ここでは、簡単で迅速な方法を開始します.

セットアップ
このチュートリアルでは、典型的には、TypeScriptで基本的な反応アプリケーションを起動する方法に精通している必要があります.ギャツビーをインストールしたと仮定しましょうTS starter package :
npx gatsby new hotel-website https://github.com/jpedroschmitz/gatsby-starter-ts
パッケージを追加します
yarn add react-booking-form react-icons
ではノードサーバを起動しますyarn start そして、あなたの上に何かがあるかどうかチェックしてくださいlocalhost:8000 🚀

2 .ライブラリのインポート
この部分は簡単でまっすぐ進む.
新しいファイルを作る./src/pages/BookingForm.tsx
import {
  DateInput,
  FormSchema,
  GuestsSelect,
  LocationSelect,
  useReactBookingForm,
  BookingForm as BookingFormType,
} from "react-booking-form"
import "flatpickr/dist/themes/material_green.css"
注意:カレンダー(他のCSSテーマ)をインポートすることができます.flatpickrテーマを読むhere

ヘルパー関数
ここではいくつかのヘルパーが表示されます.
// cities is an array of strings such as ["New York", "Alabama", ...]
import { cities } from "./dummy-data/cities"

// This is mocking a call to API that would return location search results
// whenever user types into the location input field.
const searchPlace = async (query) =>
  new Promise((resolve, _reject) => {
    setTimeout(() => resolve(filterAndMapCiies(query)), 600)
  })

// This is what might happen on the backend in real-life application: it would search for the city and return the results in correct format `{value: string, label: string}`.
const filterAndMapCiies = (query) =>
  cities
    .filter((city) => city.toLowerCase().includes(query.toLowerCase()))
    .map((city) => ({ value: city.toLowerCase(), label: city }))

// This is intended to be loaded into the location input field by default
const defaultLocationOptions = [
  { value: "new-york", label: "New York" },
  { value: "barcelona", label: "Barcelona" },
  { value: "los-angeles", label: "Los Angeles" },
]

4 .定義フォームスキーマ
このパッケージでは、できるだけ多くのフィールドを構築することができます柔軟なフォームのスキーマを使用します.フィールドの3種類があります(あなたは、同様に真ん中に自分の完全に別のフィールドを作成することができます恐れてはいけない)があります🤓): location , date ( datetimeを許可する)peopleCount セレクタ.
はい
const formSchema: FormSchema = {
  location: {
    type: "location",
    focusOnNext: "checkIn",
    options: { defaultLocationOptions, searchPlace },
  },
  checkIn: {
    type: "date",
    focusOnNext: "checkOut",
    options: {
    // These are entirely flatpickr options
      altInput: true,
      altFormat: "M j, Y",
      dateFormat: "Y-m-d",
      minDate: "today",
      wrap: true,
    },
  },
  checkOut: {
    type: "date",
    focusOnNext: "guests",
    options: {
      minDateFrom: "checkIn",
      // These are entirely flatpickr options
      altInput: true,
      altFormat: "M j, Y",
      dateFormat: "Y-m-d",
      wrap: true,
    },
  },
  guests: {
    type: "peopleCount",
    defaultValue: [
      {
        name: "adults",
        label: "Adults",
        description: "Ages 13+",
        value: 1,
        min: 0,
        max: 10,
      },
      {
        name: "children",
        label: "Children",
        description: "Ages 4-12",
        value: 0,
        min: 0,
        max: 10,
      },
      {
        name: "infants",
        label: "Infants",
        description: "Under 4 years old",
        value: 0,
        min: 0,
        max: 10,
      },
    ],
  },
}
フォーマットは自己記述的です.キー名は我々が望むものであるかもしれません、しかし、オブジェクトの各々の値は特定のタイプに従わなければなりません.詳細についてはrepoのドキュメントを参照してください.
ここでは、4つのフィールドが欲しいと言います.
  • 受け入れられる場所検索フィールドsearchPlace (上記のヘルパーから)ユーザがフィールドで何かをタイプするたびに、「デッドド」方式で実行されます.選択の後、それはcheckIn …という分野
  • チェックイン日の日付フィールド.これは、軽量で強力なライブラリをflatpickr . あなたはそれを調べることができますoptions このフィールドの選択については、options キー.そして、それはに集中するでしょう.
  • チェックアウトのための日付フィールド.これには、minminefromと呼ばれる余分なオプションがありますcheckIn これにより、ユーザーは、checkIn 値.そして、それが変わるとき、それは焦点を当てます...
  • 客/乗客セレクタ.これは、どのように多くの人々のクラスは、サービス/場所を予約していることを示すことができるスマートセレクタです.

  • JSX予約フォーム
    もう少しで終わりだ.JSXパターンはこちらBookingForm コンポーネント
    export const BookingForm = () => {
      const form = useReactBookingForm({ formSchema })
    
      return (
        <Container>
          <InputContainer>
            <Label>{"Location"}</Label>
            <LocationSelect
              form={form}
              menuContainer={MenuContainer}
              optionContainer={OptionContainer}
              inputComponent={InputComponent}
              name="location"
              inputProps={{ placeholder: "Where are you going?" }}
            />
          </InputContainer>
          <InputContainer>
            <Label>{"Check in"}</Label>
            <DatePicker placeholder="Add date" form={form} name={"checkIn"} />
          </InputContainer>
          <InputContainer>
            <Label>{"Check out"}</Label>
            <DatePicker placeholder="Add date" form={form} name={"checkOut"} />
          </InputContainer>
          <InputContainer>
            <Label>{"Guests"}</Label>
            <GuestsSelect
              form={form}
              menuContainer={MenuContainer}
              optionComponent={OptionComponent}
              controlComponent={ControlComponent}
              controlProps={{ placeholder: "Add guests" }}
              name={"guests"}
            />
          </InputContainer>
          <InputContainer>
            <MainButton>
              <FaSearch/>
              <ButtonText>{"Search"}</ButtonText>
            </MainButton>
          </InputContainer>
        </Container>
      )
    }
    
    簡単、右?今、私たちはTarwindCSSで動作して、速度のために(そして、読みやすさのためにコードのいくつかの線を節約するために)我々は少しそれを変えるでしょう
    export const BookingForm = () => {
      const form = useReactBookingForm({ formSchema })
    
      return (
        <div
          className="w-full mx-auto rounded-full bg-black bg-opacity-30 backdrop-filter backdrop-blur p-6 flex justify-between flex-col md:flex-row md:space-x-2 md:space-y-0 space-y-2 border border-purple-500"
          style={{ boxShadow: "0px 0px 50px #a025da44 inset" }}
        >
          <div className="relative w-full md:w-1/3 border-l-0 flex flex-col justify-center items-center pl-2">
            <Label>{"Location"}</Label>
            <LocationSelect
              form={form}
              menuContainer={MenuContainer}
              optionContainer={OptionContainer}
              inputComponent={InputComponent}
              name="location"
              inputProps={{ placeholder: "Where are you going?" }}
            />
          </div>
          <div className="relative w-full md:w-1/3 border-l-0 flex flex-col justify-center items-center pl-2">
            <Label>{"Check in"}</Label>
            <DatePicker placeholder="Add date" form={form} name={"checkIn"} />
          </div>
          <div className="relative w-full md:w-1/3 border-l-0 flex flex-col justify-center items-center pl-2">
            <Label>{"Guests"}</Label>
            <GuestsSelect
              form={form}
              menuContainer={MenuContainer}
              optionComponent={OptionComponent}
              controlComponent={ControlComponent}
              controlProps={{ placeholder: "Add guests" }}
              name={"guests"}
            />
          </div>
          <div className="relative w-full md:w-1/3 border-l-0 flex flex-col justify-center items-center pl-2">
            <button className="appearance-none mt-5 border w-full h-10 bg-purple-900 hover:bg-purple-500 transition border-purple-500 rounded-full flex justify-center items-center bg-transparent text-white font-bold px-3 font-title-2 uppercase">
              {"Book"}
            </button>
          </div>
        </div>
      )
    }
    

    6 .スタイル!🎩
    そして今、我々は追加/スタイル我々の補完的なコンポーネントを任意の方法で我々が欲しい.
    この例では、TailWindCSSを使用していますが、スタイルのコンポーネントを使用できます.twin.macro , モジュールのscssまたは他の方法でパターンを理解します.
    const DatePickerInput = ({ placeholder, inputRef }) => (
      <div className="relative flex group h-10 w-full" ref={inputRef}>
        <InputCore type="input" data-input placeholder={placeholder} />
      </div>
    )
    
    const DatePicker = (props) => (
      <DateInput className="w-full" inputComponent={DatePickerInput} {...props} />
    )
    
    const MenuContainer = React.forwardRef(
      ({ isOpen, children, style, ...props }: any, ref) => (
        <div
          className={`w-full w-64 border border-purple-500 z-10 mt-12 transform transition ease-in-out bg-black bg-opacity-60 backdrop-filter backdrop-blur rounded-3xl overflow-y-auto overflow-x-hidden
            ${
              isOpen
                ? "opacity-100"
                : "opacity-0 -translate-y-4 pointer-events-none"
            }
          `}
          style={{ ...style, maxWidth: "240px" }}
          ref={ref}
          {...props}
        >
          {children}
        </div>
      ),
    )
    
    const inputClassName =
      "appearance-none border rounded-full w-full outline-none transition pl-4 pr-6 bg-transparent border-purple-500 cursor-pointer flex items-center text-white"
    
    const InputCore = React.forwardRef((props, ref) => (
      <input className={inputClassName} ref={ref} {...props} />
    ))
    
    const RoundButton = ({ children, ...props }) => (
      <button
        {...props}
        className="appearance-none rounded-full p-2 flex items-center justify-center h-full overflow-hidden border border-gray-500 text-gray-500 hover:text-white hover:bg-purple-500 hover:border-transparent transition ease-in-out disabled:opacity-50"
      >
        {children}
      </button>
    )
    
    const OptionComponent = ({
      form,
      name,
      option,
    }: {
      form: BookingFormType
      name: string
      option: any
    }) => {
      const onPlusClick = () => {
        form.setGuestOptionValue(name, option, option.value + 1)
      }
    
      const onMinusClick = () => {
        form.setGuestOptionValue(name, option, option.value - 1)
      }
    
      return (
        <div className="transition ease-in-out relative py-2 px-4 flex justify-between items-center">
          <div>
            <p className="font-title font-bold text-sm text-white">
              {option.label}
            </p>
            <p className="text-white text-sm">{option.description}</p>
          </div>
          <div className="flex justify-center items-center gap-x-2">
            <RoundButton
              onClick={onPlusClick}
              disabled={option.value >= (option.max || 100)}
            >
              <FaPlus />
            </RoundButton>
            <p className="font-title font-bold text-sm text-white">
              {option.value}
            </p>
            <RoundButton onClick={onMinusClick} disabled={option.value === 0}>
              <FaMinus />
            </RoundButton>
          </div>
        </div>
      )
    }
    
    const InputComponent = ({ form, name, isLoading, ...props }) => (
      <div className="relative flex group h-10 w-full">
        <InputCore ref={form.refs[name]} {...props} />
      </div>
    )
    
    const OptionContainer = ({ children, ...props }) => (
      <div
        className="transition ease-in-out relative py-2 px-4 hover:bg-gray-800 cursor-pointer text-white"
        {...props}
      >
        {children}
      </div>
    )
    
    const ControlComponent = ({
      form,
      name,
      placeholder,
      ...props
    }: {
      form: BookingFormType
      name: string
      placeholder?: string
    }) => {
      const count = form.state[name].totalCount
    
      return (
        <div className="relative flex group h-10 w-full">
          <div
            className={inputClassName}
            ref={form.refs[name]}
            tabIndex={-1}
            {...props}
          >
            <p>{count ? `${count} guest${count > 1 ? "s" : ""}` : ""} </p>
            <div>{count ? "" : placeholder}</div>
          </div>
        </div>
      )
    }
    
    const Label = ({ children }) => (
      <div className="text-sm w-full font-bold mb-1 text-white">{children}</div>
    )
    

    結果
    ここでは、./pages/index.tsx レンダリングします.
    import { BookingForm } from "./BookingForm.tsx"
    
    ...
    const Home = () => (
      ...
        <BookingForm />
      ...
    )
    
    そして今、あなたはブラウザで何かを見ることができるはずです🎩
    あなたが遊ぶならば、あなたはこのように何かをつくることができます:

    はい、どうぞlink to the repository Githubであなたと遊ぶことができます.ピース🚀