packages feed

react-flux-1.1.0: example/todo/TodoComponents.hs

{-# LANGUAGE OverloadedStrings, BangPatterns #-}

-- | The division between a view and a component is arbitrary, but for me components are pieces that
-- are re-used many times for different purposes.  In the TODO app, there is one component for the
-- text box.
module TodoComponents where

import Data.Typeable (Typeable)
import React.Flux
import Data.JSString (JSString)
import qualified Data.Text as T

-- | The properties for the text input component.  Note how we can pass anything, including
-- functions, as the properties; the only requirement is an instance of Typeable.
data TextInputArgs = TextInputArgs {
      tiaId :: Maybe JSString
    , tiaClass :: JSString
    , tiaPlaceholder :: JSString
    , tiaOnSave :: T.Text -> [SomeStoreAction]
    , tiaValue :: Maybe T.Text
} deriving (Typeable)

-- | The text input stateful view.  The state is the text that has been typed into the textbox
-- but not yet saved.  The save is triggered either on enter or blur, which resets the state/content
-- of the text box to the empty string.
todoTextInput :: ReactView TextInputArgs
todoTextInput = defineStatefulView "todo text input" "" $ \curText args ->
    input_ $
        maybe [] (\i -> ["id" &= i]) (tiaId args)
        ++
        [ "className" &= tiaClass args
        , "placeholder" &= tiaPlaceholder args
        , "value" &= curText -- using value here creates a controlled component: https://facebook.github.io/react/docs/forms.html
        , "autoFocus" &= True

        -- Update the current state with the current text in the textbox, sending no actions
        , onChange $ \evt _ -> ([], Just $ target evt "value")

        -- Produce the save action and reset the current state to the empty string
        , onBlur $ \_ _ curState ->
            if not (T.null curState)
                then (tiaOnSave args curState, Just "")
                else ([], Nothing)
        , onKeyDown $ \_ evt curState ->
             if keyCode evt == 13 && not (T.null curState) -- 13 is enter
                 then (tiaOnSave args curState, Just "")
                 else ([], Nothing)
        ]

-- | A combinator suitible for use inside rendering functions.
todoTextInput_ :: TextInputArgs -> ReactElementM eventHandler ()
todoTextInput_ !args = view todoTextInput args mempty