hyperbole-0.7.0: src/Web/Hyperbole/HyperView/Input.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE UndecidableInstances #-}
module Web.Hyperbole.HyperView.Input where
import Data.Aeson (FromJSON, ToJSON)
import Data.String.Conversions (cs)
import Data.Text (Text)
import GHC.Generics (Generic)
import Web.Atomic.Types
import Web.Hyperbole.Data.Argument (decodeArgument, encodeArgument)
import Web.Hyperbole.HyperView.Event (DelayMs, onChange, onClick, onInput)
import Web.Hyperbole.HyperView.Types (HyperView (..))
import Web.Hyperbole.Route (Route (..), routeUri)
import Web.Hyperbole.View
{- | \<button\> HTML tag which sends the action when pressed
@
#EMBED Example.Simple messageView
@
-}
button :: (ViewAction (Action id)) => Action id -> View id () -> View id ()
button action cnt = do
tag "button" cnt @ onClick action
{- | Type-safe dropdown. Sends (opt -> Action id) when selected. The default will be selected.
@
#EMBED Example.DataLists.Filter familyDropdown
@
-}
dropdown
:: forall opt id
. (ViewAction (Action id), FromJSON opt)
=> Action id
-> opt -- default option
-> View (Option id opt) ()
-> View id ()
dropdown act defOpt options = do
st :: ViewState id <- viewState
i :: id <- viewId
tag "select" @ onChange act $ do
runViewContext (Option i defOpt) st options
-- | An option for a 'dropdown' or 'select'
option
:: forall opt id
. (ViewAction (Action id), Eq opt, ToJSON opt)
=> opt
-> Text
-> View (Option id opt) ()
option opt cnt = do
os :: Option id opt <- viewId
tag "option" @ att "value" (encodeOption opt) @ selected (os.defaultOption == opt) $ text cnt
encodeOption :: (ToJSON opt) => opt -> Text
encodeOption opt =
case encodeArgument opt of
-- For options, an empty string makes much more sense than null for empty values
"null" -> ""
other -> other
-- | sets selected = true if the 'dropdown' predicate returns True
selected :: (Attributable h) => Bool -> Attributes h -> Attributes h
selected b = if b then att "selected" "true" else id
-- | The view context for an 'option'
data Option id opt = Option
{ id :: id
, defaultOption :: opt
}
deriving (Generic)
instance (ToJSON id, ToJSON opt, FromJSON id, FromJSON opt) => ViewId (Option id opt) where
type ViewState (Option id opt) = ViewState id
{- | A live search field. Set a DelayMs to avoid hitting the server on every keystroke
@
#EMBED Example.Errors viewSearchUsers
@
-}
search :: (ViewAction (Action id)) => Action id -> DelayMs -> View id ()
search go delay = do
tag "input" none @ onInput go delay
-- | Set checkbox = checked via the client (VDOM doesn't work)
checked :: (Attributable a) => Bool -> Attributes a -> Attributes a
checked c =
att "data-checked" (cs $ show c)
. if c then att "checked" "" else id
{- | A hyperlink to another route
>>> route (User 100) id "View User"
<a href="/user/100">View User</a>
-}
route :: (Route a) => a -> View c () -> View c ()
route r = link (routeUri r)
-- instance {-# OVERLAPPABLE #-} (FromJSON a) => UserInput (Maybe a) where
-- parseInput "" = pure Nothing
-- parseInput t = pure $ A.decode (cs t)
--
--
-- instance {-# OVERLAPS #-} UserInput (Maybe Text) where
-- parseInput = pure . Just
class InputValue a where
parseInputValue :: Text -> Either String a
default parseInputValue :: (FromJSON a) => Text -> Either String a
parseInputValue = decodeArgument
instance InputValue Text where
parseInputValue = pure
instance InputValue Int where
parseInputValue "" = Right 0
parseInputValue t = decodeArgument t
instance InputValue Float where
parseInputValue "" = Right 0
parseInputValue t = decodeArgument t
instance InputValue Double where
parseInputValue "" = Right 0
parseInputValue t = decodeArgument t
instance InputValue Integer where
parseInputValue "" = Right 0
parseInputValue t = decodeArgument t
instance {-# OVERLAPPABLE #-} (InputValue a) => InputValue (Maybe a) where
parseInputValue "null" = pure Nothing
parseInputValue "" = pure Nothing
parseInputValue t = Just <$> parseInputValue t
instance {-# OVERLAPS #-} InputValue (Maybe Text) where
parseInputValue t = pure $ Just t
instance {-# OVERLAPS #-} InputValue (Maybe String) where
parseInputValue t = pure $ Just (cs t)