-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Interactive HTML apps using type-safe serverside Haskell -- -- Interactive HTML applications using type-safe serverside Haskell. -- Inspired by HTMX, Elm, and Phoenix LiveView @package hyperbole @version 0.3.6 module Web.Hyperbole.Embed -- | Default CSS to remove unintuitive default styles. This or -- cssResetLink is required. -- --
--   import Data.String.Interpolate (i)
--   
--   toDocument :: ByteString -> ByteString
--   toDocument cnt =
--     [i|<html>
--       <head>
--         <style type="text/css">#{cssResetEmbed}</style>
--       </head>
--       <body>#{cnt}</body>
--     </html>|]
--   
cssResetEmbed :: ByteString -- | Alternatively, the reset is available on a CDN -- --
--   import Data.String.Interpolate (i)
--   
--   toDocument :: ByteString -> ByteString
--   toDocument cnt =
--     [i|<html>
--       <head>
--         <link rel="stylesheet" href="#{cssResetLink}">
--       </head>
--       <body>#{cnt}</body>
--     </html>|]
--   
cssResetLink :: Text scriptEmbed :: ByteString module Web.Hyperbole.Route -- | Derive this class to use a sum type as a route. Constructors and -- Selectors map intuitively to url patterns -- --
--   data AppRoute
--    = HomePage
--    | Users
--    | User Int
--    deriving (Generic, Route)
--   
--   /         -> HomePage
--   /users/   -> Users
--   /user/100 -> User 100
--   
class Route a -- | The default route to use if attempting to match on empty segments defRoute :: Route a => a -- | Map a route to segments routePath :: Route a => a -> [Segment] -- | Try to match segments to a route matchRoute :: Route a => [Segment] -> Maybe a -- | Try to match segments to a route matchRoute :: (Route a, Generic a, GenRoute (Rep a)) => [Segment] -> Maybe a -- | Map a route to segments routePath :: (Route a, Generic a, Eq a, GenRoute (Rep a)) => a -> [Segment] -- | The default route to use if attempting to match on empty segments defRoute :: (Route a, Generic a, GenRoute (Rep a)) => a -- | Try to match a route, use defRoute if it's empty findRoute :: Route a => [Segment] -> Maybe a pathUrl :: [Segment] -> Url -- | Convert a Route to a Url -- --
--   >>> routeUrl (User 100)
--   /user/100
--   
routeUrl :: Route a => a -> Url -- | Automatically derive Route class GenRoute f genRoute :: GenRoute f => [Text] -> Maybe (f p) genPaths :: GenRoute f => f p -> [Text] genFirst :: GenRoute f => f p genRouteRead :: Read x => [Text] -> Maybe (K1 R x a) data () => Url instance Web.Hyperbole.Route.Route sub => Web.Hyperbole.Route.GenRoute (GHC.Generics.K1 GHC.Generics.R sub) instance Web.Hyperbole.Route.Route Data.Text.Internal.Text instance Web.Hyperbole.Route.Route GHC.Base.String instance Web.Hyperbole.Route.Route GHC.Num.Integer.Integer instance Web.Hyperbole.Route.Route GHC.Types.Int instance Web.Hyperbole.Route.Route a => Web.Hyperbole.Route.Route (GHC.Maybe.Maybe a) instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.D c f) instance forall k (c :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Constructor c, Web.Hyperbole.Route.GenRoute f) => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.C c f) instance Web.Hyperbole.Route.GenRoute GHC.Generics.U1 instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.S c f) instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Generics.:+: b) instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Generics.:*: b) module Web.Hyperbole.HyperView -- | HyperViews are interactive subsections of a Page -- -- Create an instance with a unique view id type and a sum type -- describing the actions the HyperView supports. The View Id can contain -- context (a database id, for example) -- --
--   data Message = Message Int
--     deriving (Generic, Param)
--   
--   data MessageAction
--     = Louder Text
--     | ClearMessage
--     deriving (Generic, Param)
--   
--   instance HyperView Message where
--     type Action Message = MessageAction
--   
class (Param id, Param (Action id)) => HyperView id where { type Action id :: Type; } -- | Embed HyperViews into the page, or nest them into other views -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     handle messages
--     load $ do
--       pure $ do
--         el_ "My Page"
--         hyper (Message 1) $ messageView "Hello World"
--         hyper (Message 2) $ do
--           messageView "Another Message"
--           hyper OtherView otherView
--   
-- -- Views can only trigger actions that match their HyperView -- --
--   messageView :: Text -> View Message ()
--   messageView m = do
--     el_ (text m)
--     button (Louder m) Louder
--   
--   otherView :: View OtherView ()
--   otherView = do
--     -- Type Error!
--     button (Louder "Hi") id Louder
--   
hyper :: forall id ctx. HyperView id => id -> View id () -> View ctx () -- | <button> HTML tag which sends the action when pressed -- --
--   button SomeAction (border 1) "Click Me"
--   
button :: HyperView id => Action id -> Mod -> View id () -> View id () -- | Send the action after N milliseconds. Can be used to implement lazy -- loading or polling -- --
--   pollMessageView :: Text -> View Message ()
--   pollMessageView m = do
--     onLoad LoadMessage 1000 $ do
--       el bold "Current Message. Reloading in 1s"
--       el_ (text m)
--   
onLoad :: HyperView id => Action id -> DelayMs -> View id () -> View id () type DelayMs = Int -- | Give visual feedback when an action is in-flight. -- --
--   myView = do
--     onRequest loadingIndicator $ do
--       el_ "Loaded"
--     where
--       loadingIndicator = el_ "Loading..."
--   
onRequest :: View id () -> View id () -> View id () -- | Internal dataTarget :: Param a => a -> Mod -- | Trigger actions for another view. They will update the view specified -- --
--   otherView :: View OtherView ()
--   otherView = do
--     el_ "This is not a message view"
--     button OtherAction id "Do Something"
--   
--     target (Message 2) $ do
--       el_ "Now we can trigger a MessageAction which will update our Message HyperView, not this one"
--       button ClearMessage id "Clear Message #2"
--   
target :: HyperView id => id -> View id () -> View a () -- | Type-safe dropdown. Sends (opt -> Action id) when selected. The -- selection predicate (opt -> Bool) controls which option is -- selected. See Example.Contacts -- --
--   data ContactsAction
--     = Reload (Maybe Filter)
--     | Delete Int
--     deriving (Generic, Param)
--   
--   allContactsView :: Maybe Filter -> View Contacts ()
--   allContactsView fil = do
--     row (gap 10) $ do
--       el (pad 10) "Filter: "
--       dropdown Reload (== fil) id $ do
--         option Nothing ""
--         option (Just Active) "Active!"
--         option (Just Inactive) Inactive
--     ...
--   
dropdown :: HyperView id => (opt -> Action id) -> (opt -> Bool) -> Mod -> View (Option opt id (Action id)) () -> View id () -- | An option for a dropdown. First argument is passed to (opt -- -> Action id) in the dropdown, and to the selected predicate option :: (HyperView id, Eq opt) => opt -> View (Option opt id (Action id)) () -> View (Option opt id (Action id)) () -- | sets selected = true if the dropdown predicate returns True selected :: Bool -> Mod -- | The view context for an option data Option opt id action Option :: (opt -> action) -> (opt -> Bool) -> Option opt id action [$sel:toAction:Option] :: Option opt id action -> opt -> action [$sel:selected:Option] :: Option opt id action -> opt -> Bool -- | Types that can be serialized. HyperView requires this for both -- its view id and action -- --
--   data Message = Message Int
--     deriving (Generic, Param)
--   
class Param a toParam :: Param a => a -> Text toParam :: (Param a, Generic a, GParam (Rep a)) => a -> Text parseParam :: Param a => Text -> Maybe a parseParam :: (Param a, Generic a, GParam (Rep a)) => Text -> Maybe a class GParam f gToParam :: GParam f => f p -> Text gParseParam :: GParam f => Text -> Maybe (f p) breakSegment :: Text -> (Text, Text) toSegment :: String -> Text -- | A hyperlink to another route -- --
--   >>> route (User 100) id "View User"
--   <a href="/user/100">View User</a>
--   
route :: Route a => a -> Mod -> View c () -> View c () instance Web.Hyperbole.HyperView.Param a => Web.Hyperbole.HyperView.GParam (GHC.Generics.K1 GHC.Generics.R a) instance Web.Hyperbole.HyperView.Param a => Web.Hyperbole.HyperView.Param (GHC.Maybe.Maybe a) instance Web.Hyperbole.HyperView.Param GHC.Num.Integer.Integer instance Web.Hyperbole.HyperView.Param GHC.Types.Float instance Web.Hyperbole.HyperView.Param GHC.Types.Int instance Web.Hyperbole.HyperView.Param () instance Web.Hyperbole.HyperView.Param Data.Text.Internal.Text instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.HyperView.GParam f, Web.Hyperbole.HyperView.GParam g) => Web.Hyperbole.HyperView.GParam (f GHC.Generics.:*: g) instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.HyperView.GParam f, Web.Hyperbole.HyperView.GParam g) => Web.Hyperbole.HyperView.GParam (f GHC.Generics.:+: g) instance forall k (d :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Datatype d, Web.Hyperbole.HyperView.GParam f) => Web.Hyperbole.HyperView.GParam (GHC.Generics.M1 GHC.Generics.D d f) instance forall k (c :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Constructor c, Web.Hyperbole.HyperView.GParam f) => Web.Hyperbole.HyperView.GParam (GHC.Generics.M1 GHC.Generics.C c f) instance Web.Hyperbole.HyperView.GParam GHC.Generics.U1 instance forall k (f :: k -> *) (s :: GHC.Generics.Meta). Web.Hyperbole.HyperView.GParam f => Web.Hyperbole.HyperView.GParam (GHC.Generics.M1 GHC.Generics.S s f) instance Web.Hyperbole.HyperView.GParam (GHC.Generics.K1 GHC.Generics.R Data.Text.Internal.Text) instance Web.Hyperbole.HyperView.GParam (GHC.Generics.K1 GHC.Generics.R GHC.Base.String) module Web.Hyperbole.Session newtype Session Session :: Map Text Text -> Session -- | Set the session key to value sessionSet :: ToHttpApiData a => Text -> a -> Session -> Session sessionDel :: Text -> Session -> Session sessionLookup :: FromHttpApiData a => Text -> Session -> Maybe a sessionEmpty :: Session -- | Render a session as a url-encoded query string sessionRender :: Session -> ByteString -- | Parse a session as a url-encoded query string sessionParse :: ByteString -> Session sessionFromCookies :: [(ByteString, ByteString)] -> Session sessionSetCookie :: Session -> ByteString instance GHC.Show.Show Web.Hyperbole.Session.Session module Web.Hyperbole.Effect newtype Host Host :: ByteString -> Host [$sel:text:Host] :: Host -> ByteString data Request Request :: Host -> [Segment] -> Query -> ByteString -> Method -> [(ByteString, ByteString)] -> Request [$sel:host:Request] :: Request -> Host [$sel:path:Request] :: Request -> [Segment] [$sel:query:Request] :: Request -> Query [$sel:body:Request] :: Request -> ByteString [$sel:method:Request] :: Request -> Method [$sel:cookies:Request] :: Request -> [(ByteString, ByteString)] -- | Valid responses for a Hyperbole effect. Use notFound, -- etc instead. Reminds you to use load in your Page -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     -- compiler error: () does not equal Response
--     pure ()
--   
data Response Response :: View () () -> Response NotFound :: Response Redirect :: Url -> Response Err :: ResponseError -> Response Empty :: Response data ResponseError ErrParse :: Text -> ResponseError ErrParam :: Text -> ResponseError ErrOther :: Text -> ResponseError ErrNotHandled :: Event Text Text -> ResponseError ErrAuth :: ResponseError -- | Hyperbole applications are divided into Pages. Each Page must -- load the whole page , and handle each type of -- HyperView -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     handle messages
--     load pageView
--   
--   pageView = do
--     el_ "My Page"
--     hyper (Message 1) $ messageView "Starting Message"
--   
newtype Page es a Page :: Eff es a -> Page es a -- | An action, with its corresponding id data Event id act Event :: id -> act -> Event id act [$sel:viewId:Event] :: Event id act -> id [$sel:action:Event] :: Event id act -> act -- | Low level effect mapping request/response to either HTTP or WebSockets data Server :: Effect [LoadRequest] :: Server m Request [SendResponse] :: Session -> Response -> Server m () -- | In any load or handle, you can use this Effect to get -- extra request information or control the response manually. -- -- For most Pages, you won't need to use this effect directly. Use -- custom Routes for request info, and return Views to -- respond data Hyperbole :: Effect [GetRequest] :: Hyperbole m Request [RespondEarly] :: Response -> Hyperbole m a [SetSession] :: ToHttpApiData a => Text -> a -> Hyperbole m () [DelSession] :: Text -> Hyperbole m () [GetSession] :: FromHttpApiData a => Text -> Hyperbole m (Maybe a) data HyperState HyperState :: Request -> Session -> HyperState [$sel:request:HyperState] :: HyperState -> Request [$sel:session:HyperState] :: HyperState -> Session -- | Run the Hyperbole effect to Server runHyperbole :: Server :> es => Eff (Hyperbole : es) Response -> Eff es Response -- | Return all information about the Request request :: Hyperbole :> es => Eff es Request -- | Return the request path -- --
--   >>> reqPath
--   ["users", "100"]
--   
reqPath :: Hyperbole :> es => Eff es [Segment] -- | Return the request body as a Web.FormUrlEncoded.Form -- -- Prefer using Type-Safe Forms when possible formData :: Hyperbole :> es => Eff es Form getEvent :: (HyperView id, Hyperbole :> es) => Eff es (Maybe (Event id (Action id))) parseEvent :: HyperView id => Query -> Maybe (Event id (Action id)) lookupEvent :: Query -> Maybe (Event Text Text) -- | Lookup a session variable by keyword -- --
--   load $ do
--     tok <- session "token"
--     ...
--   
session :: (Hyperbole :> es, FromHttpApiData a) => Text -> Eff es (Maybe a) -- | Set a session variable by keyword -- --
--   load $ do
--     t <- reqParam "token"
--     setSession "token" t
--     ...
--   
setSession :: (Hyperbole :> es, ToHttpApiData a) => Text -> a -> Eff es () -- | Clear the user's session clearSession :: Hyperbole :> es => Text -> Eff es () -- | Return the entire Query -- --
--   myPage :: Page es Response
--   myPage = do
--     load $ do
--       q <- reqParams
--       case lookupParam "token" q of
--         Nothing -> pure $ errorView "Missing Token in Query String"
--         Just t -> do
--           sideEffectUsingToken token
--           pure myPageView
--   
reqParams :: Hyperbole :> es => Eff es Query -- | Lookup the query param in the Query lookupParam :: ByteString -> Query -> Maybe Text -- | Require a given parameter from the Query arguments -- --
--   myPage :: Page es Response
--   myPage = do
--     load $ do
--       token <- reqParam "token"
--       sideEffectUsingToken token
--       pure myPageView
--   
reqParam :: (Hyperbole :> es, FromHttpApiData a) => Text -> Eff es a -- | Respond immediately with 404 Not Found -- --
--   userLoad :: (Hyperbole :> es, Users :> es) => UserId -> Eff es User
--   userLoad uid = do
--     mu <- send (LoadUser uid)
--     maybe notFound pure mu
--   
--   myPage :: (Hyperbole :> es, Users :> es) => Eff es View
--   myPage = do
--     load $ do
--       u <- userLoad 100
--       -- skipped if user = Nothing
--       pure $ userView u
--   
notFound :: Hyperbole :> es => Eff es a -- | Respond immediately with a parse error parseError :: Hyperbole :> es => Text -> Eff es a -- | Redirect immediately to the Url redirect :: Hyperbole :> es => Url -> Eff es a -- | Respond with the given view, and stop execution respondEarly :: (Hyperbole :> es, HyperView id) => id -> View id () -> Eff es () -- | Manually set the response to the given view. Normally you return a -- View from load or handle instead of using this view :: Hyperbole :> es => View () () -> Eff es Response -- | The load handler is run when the page is first loaded. Run any side -- effects needed, then return a view of the full page -- --
--   myPage :: (Hyperbole :> es) => UserId -> Page es Response
--   myPage userId = do
--     load $ do
--       user <- loadUserFromDatabase userId
--       pure $ userPageView user
--   
load :: Hyperbole :> es => Eff es (View () ()) -> Page es Response -- | A handler is run when an action for that HyperView is -- triggered. Run any side effects needed, then return a view of the -- corresponding type -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     handle messages
--     load pageView
--   
--   messages :: (Hyperbole :> es, MessageDatabase) => Message -> MessageAction -> Eff es (View Message ())
--   messages (Message mid) ClearMessage = do
--     deleteMessageSideEffect mid
--     pure $ messageView ""
--   
--   messages (Message mid) (Louder m) = do
--     let new = m <> "!"
--     saveMessageSideEffect mid new
--     pure $ messageView new
--   
handle :: forall id es. (Hyperbole :> es, HyperView id) => (id -> Action id -> Eff es (View id ())) -> Page es () -- | Run a Page in Hyperbole page :: Hyperbole :> es => Page es Response -> Eff es Response instance GHC.Show.Show Web.Hyperbole.Effect.Host instance GHC.Show.Show Web.Hyperbole.Effect.Request instance GHC.Base.Functor (Web.Hyperbole.Effect.Page es) instance GHC.Base.Monad (Web.Hyperbole.Effect.Page es) instance GHC.Base.Applicative (Web.Hyperbole.Effect.Page es) instance GHC.Show.Show Web.Hyperbole.Effect.ResponseError instance (GHC.Show.Show act, GHC.Show.Show id) => GHC.Show.Show (Web.Hyperbole.Effect.Event id act) module Web.Hyperbole.Forms -- | The only time we can use Fields is inside a form data FormFields id FormFields :: id -> Validation -> FormFields id -- | Choose one for inputs to give the browser autocomplete hints data InputType NewPassword :: InputType CurrentPassword :: InputType Username :: InputType Email :: InputType Number :: InputType TextInput :: InputType Name :: InputType OneTimeCode :: InputType Organization :: InputType StreetAddress :: InputType Country :: InputType CountryName :: InputType PostalCode :: InputType Search :: InputType data Label a data Invalid a data Input id a Input :: Text -> Validation -> Input id a -- | Display a FormField -- --
--   data Age = Age Int deriving (Generic, FormField)
--   
--   myForm = do
--     form SignUp mempty id $ do
--       field @Age id id $ do
--        label Age
--        input Number (value "0")
--   
field :: forall a id. FormField a => Mod -> Mod -> View (Input id a) () -> View (FormFields id) () -- | label for a field label :: Text -> View (Input id a) () -- | input for a field input :: InputType -> Mod -> View (Input id a) () -- | Type-safe <form>. Calls (Action id) on submit -- --
--   userForm :: Validation -> View FormView ()
--   userForm v = do
--     form Signup v id $ do
--       el Style.h1 "Sign Up"
--   
--       field @User id Style.invalid $ do
--         label "Username"
--         input Username (placeholder "username")
--         el_ invalidText
--   
--       field @Age id Style.invalid $ do
--         label "Age"
--         input Number (placeholder "age" . value "0")
--         el_ invalidText
--   
--       submit (border 1) "Submit"
--   
form :: forall id. HyperView id => Action id -> Validation -> Mod -> View (FormFields id) () -> View id () placeholder :: Text -> Mod -- | Button that submits the form. Use button to specify -- actions other than submit submit :: Mod -> View (FormFields id) () -> View (FormFields id) () parseForm :: forall form es. (Form form, Hyperbole :> es) => Eff es (form Identity) -- | Parse a FormField from the request -- --
--   formAction :: (Hyperbole :> es, UserDB :> es) => FormView -> FormAction -> Eff es (View FormView ())
--   formAction _ SignUp = do
--     a <- formField @Age
--     u <- formField @User
--     saveUserToDB u a
--     pure $ el_ "Saved!"
--   
formField :: forall a es. (FormField a, Hyperbole :> es) => Eff es a class Form (form :: (Type -> Type) -> Type) formLabels :: Form form => form Label formLabels :: (Form form, Generic (form Label), GForm (Rep (form Label))) => form Label formInvalid :: Form form => form Invalid formInvalid :: (Form form, Generic (form Invalid), GForm (Rep (form Invalid))) => form Invalid fromForm :: Form form => Form -> Either Text (form Identity) fromForm :: (Form form, Generic (form Identity), GFromForm (form Identity) (Rep (form Identity))) => Form -> Either Text (form Identity) -- | Default encoding FormOptions. -- --
--   FormOptions
--   { fieldLabelModifier = id
--   }
--   
defaultFormOptions :: FormOptions -- | Generic-based deriving options for ToForm and -- FromForm. -- -- A common use case for non-default FormOptions is to strip a -- prefix off of field labels: -- --
--   data Project = Project
--     { projectName :: String
--     , projectSize :: Int
--     } deriving (Generic, Show)
--   
--   myOptions :: FormOptions
--   myOptions = FormOptions
--    { fieldLabelModifier = map toLower . drop (length "project") }
--   
--   instance ToForm Project where
--     toForm = genericToForm myOptions
--   
--   instance FromForm Project where
--     fromForm = genericFromForm myOptions
--   
-- --
--   >>> urlEncodeAsFormStable Project { projectName = "http-api-data", projectSize = 172 }
--   "name=http-api-data&size=172"
--   
--   >>> urlDecodeAsForm "name=http-api-data&size=172" :: Either Text Project
--   Right (Project {projectName = "http-api-data", projectSize = 172})
--   
data () => FormOptions FormOptions :: (String -> String) -> FormOptions -- | Function applied to field labels. Handy for removing common record -- prefixes for example. [fieldLabelModifier] :: FormOptions -> String -> String -- | A Generic-based implementation of fromForm. This is used -- as a default implementation in FromForm. -- -- Note that this only works for records (i.e. product data types with -- named fields): -- --
--   data Person = Person
--     { name :: String
--     , age  :: Int
--     } deriving (Generic)
--   
-- -- In this implementation each field's value gets decoded using -- parseQueryParam. Two field types are exceptions: -- -- -- -- Here's an example: -- --
--   data Post = Post
--     { title    :: String
--     , subtitle :: Maybe String
--     , comments :: [String]
--     } deriving (Generic, Show)
--   
--   instance FromForm Post
--   
-- --
--   >>> urlDecodeAsForm "comments=Nice%20post%21&comments=%2B1&title=Test" :: Either Text Post
--   Right (Post {title = "Test", subtitle = Nothing, comments = ["Nice post!","+1"]})
--   
genericFromForm :: (Generic a, GFromForm a (Rep a)) => FormOptions -> Form -> Either Text a -- | Validation results for a form -- --
--   validateUser :: User -> Age -> Validation
--   validateUser (User u) (Age a) =
--     validation
--       [ validate @Age (a < 20) "User must be at least 20 years old"
--       , validate @User (T.elem ' ' u) "Username must not contain spaces"
--       , validate @User (T.length u < 4) "Username must be at least 4 chars"
--       ]
--   
--   formAction :: (Hyperbole :> es, UserDB :> es) => FormView -> FormAction -> Eff es (View FormView ())
--   formAction _ SignUp = do
--     a <- formField @Age
--     u <- formField @User
--   
--     case validateUser u a of
--       Validation [] -> successView
--       errs -> userForm v
--   
-- -- @ newtype Validation Validation :: [(Text, Text)] -> Validation -- | Form Fields are identified by a type -- --
--   data User = User Text deriving (Generic, FormField)
--   data Age = Age Int deriving (Generic, FormField)
--   
class FormField a inputName :: FormField a => Text inputName :: (FormField a, Generic a, GDataName (Rep a)) => Text fieldParse :: FormField a => Text -> Form -> Either Text a fieldParse :: (FormField a, Generic a, GFieldParse (Rep a)) => Text -> Form -> Either Text a lookupInvalid :: forall a. FormField a => Validation -> Maybe Text invalidStyle :: forall a. FormField a => Mod -> Validation -> Mod -- | Display any validation error for the FormField from the -- Validation passed to form -- --
--   field @User id Style.invalid $ do
--     label "Username"
--     input Username (placeholder "username")
--     el_ invalidText
--   
invalidText :: forall a id. FormField a => View (Input id a) () -- | specify a check for a Validation validate :: forall a. FormField a => Bool -> Text -> Maybe (Text, Text) -- | Create a Validation from list of validators validation :: [Maybe (Text, Text)] -> Validation -- | Parse value from HTTP API data. -- -- WARNING: Do not derive this using DeriveAnyClass as -- the generated instance will loop indefinitely. class () => FromHttpApiData a -- | Representable types of kind *. This class is derivable in GHC -- with the DeriveGeneric flag on. -- -- A Generic instance must satisfy the following laws: -- --
--   from . toid
--   to . fromid
--   
class () => Generic a instance GHC.Show.Show Web.Hyperbole.Forms.InputType instance GHC.Base.Monoid Web.Hyperbole.Forms.Validation instance GHC.Base.Semigroup Web.Hyperbole.Forms.Validation instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Forms.GFieldParse f => Web.Hyperbole.Forms.GFieldParse (GHC.Generics.M1 GHC.Generics.D d f) instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Forms.GFieldParse f => Web.Hyperbole.Forms.GFieldParse (GHC.Generics.M1 GHC.Generics.C c f) instance forall k (f :: k -> *) (s :: GHC.Generics.Meta). Web.Hyperbole.Forms.GFieldParse f => Web.Hyperbole.Forms.GFieldParse (GHC.Generics.M1 GHC.Generics.S s f) instance Web.Internal.HttpApiData.FromHttpApiData a => Web.Hyperbole.Forms.GFieldParse (GHC.Generics.K1 GHC.Generics.R a) instance forall k (d :: GHC.Generics.Meta) (c :: GHC.Generics.Meta) (f :: k -> *). GHC.Generics.Datatype d => Web.Hyperbole.Forms.GDataName (GHC.Generics.M1 GHC.Generics.D d (GHC.Generics.M1 GHC.Generics.C c f)) instance Web.Hyperbole.Forms.GForm GHC.Generics.U1 instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Forms.GForm f, Web.Hyperbole.Forms.GForm g) => Web.Hyperbole.Forms.GForm (f GHC.Generics.:*: g) instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Forms.GForm f => Web.Hyperbole.Forms.GForm (GHC.Generics.M1 GHC.Generics.D d f) instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Forms.GForm f => Web.Hyperbole.Forms.GForm (GHC.Generics.M1 GHC.Generics.C c f) instance GHC.Generics.Selector s => Web.Hyperbole.Forms.GForm (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R Data.Text.Internal.Text)) instance Web.Hyperbole.Forms.GForm (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R (GHC.Maybe.Maybe Data.Text.Internal.Text))) instance Web.Hyperbole.HyperView.Param id => Web.Hyperbole.HyperView.Param (Web.Hyperbole.Forms.FormFields id) instance (Web.Hyperbole.HyperView.HyperView id, Web.Hyperbole.HyperView.Param id) => Web.Hyperbole.HyperView.HyperView (Web.Hyperbole.Forms.FormFields id) module Web.Hyperbole.Application waiApp :: (ByteString -> ByteString) -> Eff '[Hyperbole, Server, IOE] Response -> Application -- | Upgrade a websockets ServerApp to a wai -- Application. Uses the given backup Application to handle -- Requests that are not WebSocket requests. -- --
--   websocketsOr opts ws_app backup_app = \req respond ->
--       case websocketsApp opts ws_app req of
--           Nothing  -> backup_app req send_response
--           Just res -> respond res
--   
-- -- For example, below is an Application that sends "Hello, -- client!" to each connected client. -- --
--   app :: Application
--   app = websocketsOr defaultConnectionOptions wsApp backupApp
--     where
--       wsApp :: ServerApp
--       wsApp pending_conn = do
--           conn <- acceptRequest pending_conn
--           sendTextData conn ("Hello, client!" :: Text)
--   
--       backupApp :: Application
--       backupApp _ respond = respond $ responseLBS status400 [] "Not a WebSocket request"
--   
websocketsOr :: ConnectionOptions -> ServerApp -> Application -> Application -- | The default connection options: -- -- defaultConnectionOptions :: ConnectionOptions -- | Turn one or more Pages into a Wai Application. Respond using -- both HTTP and WebSockets -- --
--   main = do
--     run 3000 $ do
--     liveApp (basicDocument "Example") $ do
--        page mainPage
--   
liveApp :: (ByteString -> ByteString) -> Eff '[Hyperbole, Server, IOE] Response -> Application socketApp :: IOE :> es => Eff (Hyperbole : (Server : es)) Response -> PendingConnection -> Eff es () runServerSockets :: IOE :> es => Connection -> Eff (Server : es) Response -> Eff es Response runServerWai :: IOE :> es => (ByteString -> ByteString) -> Request -> (Response -> IO ResponseReceived) -> Eff (Server : es) a -> Eff es (Maybe ResponseReceived) -- | wrap HTML fragments in a simple document with a custom title and -- include required embeds -- --
--   liveApp (basicDocument "App Title") (routeRequest router)
--   
-- -- You may want to specify a custom document function instead: -- --
--   myDocument :: ByteString -> ByteString
--   myDocument content =
--     [i|<html>
--       <head>
--         <title>#{title}</title>
--         <script type="text/javascript">#{scriptEmbed}</script>
--         <style type type="text/css">#{cssResetEmbed}</style>
--       </head>
--       <body>#{content}</body>
--     </html>|]
--   
basicDocument :: Text -> ByteString -> ByteString -- | Route URL patterns to different pages -- --
--   import Page.Messages qualified as Messages
--   import Page.Users qualified as Users
--   
--   data AppRoute
--     = Main
--     | Messages
--     | Users UserId
--     deriving (Eq, Generic, Route)
--   
--   router :: (Hyperbole :> es) => AppRoute -> Eff es Response
--   router Messages = page Messages.page
--   router (Users uid) = page $ Users.page uid
--   router Main = do
--     view $ do
--       el_ "click a link below to visit a page"
--       route Messages id "Messages"
--   
--   main = do
--     run 3000 $ do
--       liveApp (basicDocument "Example") (routeRequest router)
--   
routeRequest :: (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response instance GHC.Classes.Eq Web.Hyperbole.Application.SocketError instance GHC.Show.Show Web.Hyperbole.Application.SocketError module Web.Hyperbole.View -- | Element functions expect a Mod function as their first argument that -- adds attributes and classes. -- --
--   userEmail :: User -> View c ()
--   userEmail user = input (fontSize 16 . active) (text user.email)
--     where
--       active = isActive user then bold else id
--   
type Mod = Attributes -> Attributes -- | Views are HTML fragments that carry all CSS used by any child -- element. -- --
--   view :: View c ()
--   view = col (pad 10 . gap 10) $ do
--     el bold "Hello"
--     el_ "World"
--   
-- -- They can also have a context which can be used to create type-safe or -- context-aware elements. See table for an example data () => View context a data () => Align Center :: Align -- | Hexidecimal Color. Can be specified with or without the leading -- #. Recommended to use an AppColor type instead of manually -- using hex colors. See ToColor newtype () => HexColor HexColor :: Text -> HexColor -- | ToColor allows you to create a type containing your application's -- colors: -- --
--   data AppColor
--     = White
--     | Primary
--     | Dark
--   
--   instance ToColor AppColor where
--     colorValue White = "#FFF"
--     colorValue Dark = "#333"
--     colorValue Primary = "#00F"
--   
--   hello :: View c ()
--   hello = el (bg Primary . color White) "Hello"
--   
class () => ToColor a colorValue :: ToColor a => a -> HexColor colorName :: ToColor a => a -> Text -- | Options for styles that support specifying various sides. This has a -- "fake" Num instance to support literals -- --
--   border 5
--   border (X 2)
--   border (TRBL 0 5 0 0)
--   
data () => Sides a All :: a -> Sides a TRBL :: a -> a -> a -> a -> Sides a X :: a -> Sides a Y :: a -> Sides a XY :: a -> a -> Sides a -- | Media allows for responsive designs that change based on -- characteristics of the window. See Layout Example data () => Media MinWidth :: Int -> Media MaxWidth :: Int -> Media -- | Milliseconds, used for transitions data () => Ms data () => PxRem data () => Length -- | Px, converted to Rem. Allows for the user to change the document font -- size and have the app scale accordingly. But allows the programmer to -- code in pixels to match a design PxRem :: PxRem -> Length Pct :: Float -> Length data () => TransitionProperty Width :: PxRem -> TransitionProperty Height :: PxRem -> TransitionProperty data () => Url Url :: Text -> Text -> [Segment] -> Query -> Url [$sel:scheme:Url] :: Url -> Text [$sel:domain:Url] :: Url -> Text [$sel:path:Url] :: Url -> [Segment] [$sel:query:Url] :: Url -> Query data () => TableColumn c dt data () => TableHead a -- | Add text to a view. Not required for string literals -- --
--   el_ $ do
--     "Hello: "
--     text user.name
--   
text :: Text -> View c () -- | Apply to even-numbered children even :: Mod -> Mod -- | Cut off the contents of the element truncate :: Mod -- | Apply to odd-numbered children odd :: Mod -> Mod -- | A hyperlink to the given url link :: Url -> Mod -> View c () -> View c () value :: Text -> Mod -- | Space surrounding the children of the element -- -- To create even spacing around and between all elements: -- --
--   col (pad 10 . gap 10) $ do
--     el_ "one"
--     el_ "two"
--     el_ "three"
--   
pad :: Sides Length -> Mod style :: Text -> View c () -- | We can intuitively create layouts with combindations of row, -- col, grow, and space -- -- Wrap main content in layout to allow the view to consume -- vertical screen space -- --
--   holygrail :: View c ()
--   holygrail = layout id $ do
--     row section "Top Bar"
--     row grow $ do
--       col section "Left Sidebar"
--       col (section . grow) "Main Content"
--       col section "Right Sidebar"
--     row section "Bottom Bar"
--     where section = border 1
--   
layout :: Mod -> View c () -> View c () name :: Text -> Mod -- | Space that fills the available space in the parent row or -- col. -- --
--   row id $ do
--    space
--    el_ "Right"
--   
-- -- This is equivalent to an empty element with grow -- --
--   space = el grow none
--   
space :: View c () -- | Apply when hovering over an element -- --
--   el (bg Primary . hover (bg PrimaryLight)) "Hover"
--   
hover :: Mod -> Mod -- | Embed static, unescaped HTML or SVG. Take care not to use raw -- with user-generated content. -- --
--   spinner = raw "<svg>...</svg>"
--   
raw :: Text -> View c () -- | Lay out children in a row -- --
--   row id $ do
--      el_ "Left"
--      space
--      el_ "Right"
--   
row :: Mod -> View c () -> View c () -- | Lay out children in a column. -- --
--   col grow $ do
--      el_ "Top"
--      space
--      el_ "Bottom"
--   
col :: Mod -> View c () -> View c () -- | Create a type safe data table by specifying columns -- --
--   usersTable :: [User] -> View c ()
--   usersTable us = do
--     table id us $ do
--       tcol (th hd "Name") $ \u -> td cell $ text u.name
--       tcol (th hd "Email") $ \u -> td cell $ text u.email
--    where
--     hd = cell . bold
--     cell = pad 4 . border 1
--   
table :: Mod -> [dt] -> Eff '[Writer [TableColumn c dt]] () -> View c () -- | Alternatively, the reset is available on a CDN -- --
--   import Data.String.Interpolate (i)
--   
--   toDocument :: ByteString -> ByteString
--   toDocument cnt =
--     [i|<html>
--       <head>
--         <link rel="stylesheet" href="#{cssResetLink}">
--       </head>
--       <body>#{cnt}</body>
--     </html>|]
--   
cssResetLink :: Text -- | Set to a specific width width :: Length -> Mod -- | Set to a specific height height :: Length -> Mod -- | Allow width to grow to contents but not shrink any smaller than value minWidth :: Length -> Mod -- | Allow height to grow to contents but not shrink any smaller than value minHeight :: Length -> Mod -- | The space between child elements. See pad gap :: Length -> Mod fontSize :: Length -> Mod -- | Set container to be a row. Favor row when possible flexRow :: Mod -- | Set container to be a column. Favor col when possible flexCol :: Mod -- | Adds a basic drop shadow to an element shadow :: Mod -- | Round the corners of the element rounded :: Length -> Mod -- | Set the background color. See ToColor bg :: ToColor c => c -> Mod -- | Set the text color. See ToColor color :: ToColor c => c -> Mod bold :: Mod -- | Hide an element. See parent and media hide :: Mod opacity :: Float -> Mod -- | Set a border around the element -- --
--   el (border 1) "all sides"
--   el (border (X 1)) "only left and right"
--   
border :: Sides PxRem -> Mod -- | Set a border color. See ToColor borderColor :: ToColor c => c -> Mod -- | Use a button-like cursor when hovering over the element -- -- Button-like elements: -- --
--   btn = pointer . bg Primary . hover (bg PrimaryLight)
--   
--   options = row id $ do
--     el btn "Login"
--     el btn "Sign Up"
--   
pointer :: Mod -- | Animate changes to the given property -- --
--   el (transition 100 (Height 400)) "Tall"
--   el (transition 100 (Height 100)) "Small"
--   
transition :: Ms -> TransitionProperty -> Mod textAlign :: Align -> Mod -- | Apply when the mouse is pressed down on an element active :: Mod -> Mod -- | Apply when the Media matches the current window. This allows for -- responsive designs -- --
--   el (width 100 . media (MinWidth 800) (width 400))
--     "Big if window > 800"
--   
media :: Media -> Mod -> Mod -- | Apply when the element is somewhere inside an anscestor. -- -- For example, the HTMX library applies an "htmx-request" class to the -- body when a request is pending. We can use this to create a loading -- indicator -- --
--   el (pad 10) $ do
--     el (parent "htmx-request" flexRow . hide) "Loading..."
--     el (parent "htmx-request" hide . flexRow) "Normal Content"
--   
parent :: Text -> Mod -> Mod pathUrl :: [Segment] -> Url cleanSegment :: Segment -> Segment pathSegments :: Text -> [Segment] url :: Text -> Url renderUrl :: Url -> Text -- | Get the current context context :: View context context -- | Run a view with a specific context in a parent View with -- a different context. This can be used to create type safe view -- functions, like table addContext :: context -> View context () -> View c () -- | Create a new element constructor -- --
--   aside :: Mod -> View c () -> View c ()
--   aside = tag "aside"
--   
tag :: Text -> Mod -> View c () -> View c () -- | Set an attribute, replacing existing value -- --
--   hlink :: Text -> View c () -> View c ()
--   hlink url content = tag "a" (att "href" url) content
--   
att :: Name -> AttValue -> Mod -- | Renders a View as HTML with embedded CSS class definitions -- --
--   >>> renderText $ el bold "Hello"
--   <style type='text/css'>.bold { font-weight:bold }</style>
--   <div class='bold'>Hello</div>
--   
renderText :: View () () -> Text renderLazyText :: View () () -> Text renderLazyByteString :: View () () -> ByteString -- | A basic element -- --
--   el (bold . pad 10) "Hello"
--   
el :: Mod -> View c () -> View c () -- | A basic element, with no modifiers -- --
--   el_ "Hello"
--   
el_ :: View c () -> View c () -- | Do not show any content -- --
--   if isVisible
--    then content
--    else none
--   
none :: View c () pre :: Mod -> Text -> View c () script :: Text -> View c () stylesheet :: Text -> View c () tcol :: forall dt c. View (TableHead c) () -> (dt -> View dt ()) -> Eff '[Writer [TableColumn c dt]] () th :: Mod -> View c () -> View (TableHead c) () td :: Mod -> View () () -> View dt () -- | As layout but as a Mod -- --
--   holygrail = col root $ do
--     ...
--   
root :: Mod -- | Grow to fill the available space in the parent row or -- col -- --
--   row id $ do
--    el grow none
--    el_ "Right"
--   
grow :: Mod -- | Allow items to become smaller than their contents. This is not the -- opposite of grow! collapse :: Mod -- | Make a fixed layout by putting scroll on a child-element -- --
--   document = row root $ do
--     nav (width 300) "Sidebar"
--     col (grow . scroll) "Main Content"
--   
scroll :: Mod -- | A Nav element nav :: Mod -> View c () -> View c () -- | Create fully interactive HTML applications with type-safe serverside -- Haskell. Inspired by HTMX, Elm, and Phoenix -- LiveView module Web.Hyperbole -- | Turn one or more Pages into a Wai Application. Respond using -- both HTTP and WebSockets -- --
--   main = do
--     run 3000 $ do
--     liveApp (basicDocument "Example") $ do
--        page mainPage
--   
liveApp :: (ByteString -> ByteString) -> Eff '[Hyperbole, Server, IOE] Response -> Application -- | Run an Application on the given port. This calls -- runSettings with defaultSettings. run :: Port -> Application -> IO () -- | Run a Page in Hyperbole page :: Hyperbole :> es => Page es Response -> Eff es Response -- | wrap HTML fragments in a simple document with a custom title and -- include required embeds -- --
--   liveApp (basicDocument "App Title") (routeRequest router)
--   
-- -- You may want to specify a custom document function instead: -- --
--   myDocument :: ByteString -> ByteString
--   myDocument content =
--     [i|<html>
--       <head>
--         <title>#{title}</title>
--         <script type="text/javascript">#{scriptEmbed}</script>
--         <style type type="text/css">#{cssResetEmbed}</style>
--       </head>
--       <body>#{content}</body>
--     </html>|]
--   
basicDocument :: Text -> ByteString -> ByteString -- | Route URL patterns to different pages -- --
--   import Page.Messages qualified as Messages
--   import Page.Users qualified as Users
--   
--   data AppRoute
--     = Main
--     | Messages
--     | Users UserId
--     deriving (Eq, Generic, Route)
--   
--   router :: (Hyperbole :> es) => AppRoute -> Eff es Response
--   router Messages = page Messages.page
--   router (Users uid) = page $ Users.page uid
--   router Main = do
--     view $ do
--       el_ "click a link below to visit a page"
--       route Messages id "Messages"
--   
--   main = do
--     run 3000 $ do
--       liveApp (basicDocument "Example") (routeRequest router)
--   
routeRequest :: (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response -- | Derive this class to use a sum type as a route. Constructors and -- Selectors map intuitively to url patterns -- --
--   data AppRoute
--    = HomePage
--    | Users
--    | User Int
--    deriving (Generic, Route)
--   
--   /         -> HomePage
--   /users/   -> Users
--   /user/100 -> User 100
--   
class Route a -- | Convert a Route to a Url -- --
--   >>> routeUrl (User 100)
--   /user/100
--   
routeUrl :: Route a => a -> Url -- | A hyperlink to another route -- --
--   >>> route (User 100) id "View User"
--   <a href="/user/100">View User</a>
--   
route :: Route a => a -> Mod -> View c () -> View c () -- | Hyperbole applications are divided into Pages. Each Page must -- load the whole page , and handle each type of -- HyperView -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     handle messages
--     load pageView
--   
--   pageView = do
--     el_ "My Page"
--     hyper (Message 1) $ messageView "Starting Message"
--   
data Page es a -- | The load handler is run when the page is first loaded. Run any side -- effects needed, then return a view of the full page -- --
--   myPage :: (Hyperbole :> es) => UserId -> Page es Response
--   myPage userId = do
--     load $ do
--       user <- loadUserFromDatabase userId
--       pure $ userPageView user
--   
load :: Hyperbole :> es => Eff es (View () ()) -> Page es Response -- | A handler is run when an action for that HyperView is -- triggered. Run any side effects needed, then return a view of the -- corresponding type -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     handle messages
--     load pageView
--   
--   messages :: (Hyperbole :> es, MessageDatabase) => Message -> MessageAction -> Eff es (View Message ())
--   messages (Message mid) ClearMessage = do
--     deleteMessageSideEffect mid
--     pure $ messageView ""
--   
--   messages (Message mid) (Louder m) = do
--     let new = m <> "!"
--     saveMessageSideEffect mid new
--     pure $ messageView new
--   
handle :: forall id es. (Hyperbole :> es, HyperView id) => (id -> Action id -> Eff es (View id ())) -> Page es () -- | HyperViews are interactive subsections of a Page -- -- Create an instance with a unique view id type and a sum type -- describing the actions the HyperView supports. The View Id can contain -- context (a database id, for example) -- --
--   data Message = Message Int
--     deriving (Generic, Param)
--   
--   data MessageAction
--     = Louder Text
--     | ClearMessage
--     deriving (Generic, Param)
--   
--   instance HyperView Message where
--     type Action Message = MessageAction
--   
class (Param id, Param (Action id)) => HyperView id where { type Action id :: Type; } -- | Embed HyperViews into the page, or nest them into other views -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     handle messages
--     load $ do
--       pure $ do
--         el_ "My Page"
--         hyper (Message 1) $ messageView "Hello World"
--         hyper (Message 2) $ do
--           messageView "Another Message"
--           hyper OtherView otherView
--   
-- -- Views can only trigger actions that match their HyperView -- --
--   messageView :: Text -> View Message ()
--   messageView m = do
--     el_ (text m)
--     button (Louder m) Louder
--   
--   otherView :: View OtherView ()
--   otherView = do
--     -- Type Error!
--     button (Louder "Hi") id Louder
--   
hyper :: forall id ctx. HyperView id => id -> View id () -> View ctx () -- | <button> HTML tag which sends the action when pressed -- --
--   button SomeAction (border 1) "Click Me"
--   
button :: HyperView id => Action id -> Mod -> View id () -> View id () -- | Type-safe dropdown. Sends (opt -> Action id) when selected. The -- selection predicate (opt -> Bool) controls which option is -- selected. See Example.Contacts -- --
--   data ContactsAction
--     = Reload (Maybe Filter)
--     | Delete Int
--     deriving (Generic, Param)
--   
--   allContactsView :: Maybe Filter -> View Contacts ()
--   allContactsView fil = do
--     row (gap 10) $ do
--       el (pad 10) "Filter: "
--       dropdown Reload (== fil) id $ do
--         option Nothing ""
--         option (Just Active) "Active!"
--         option (Just Inactive) Inactive
--     ...
--   
dropdown :: HyperView id => (opt -> Action id) -> (opt -> Bool) -> Mod -> View (Option opt id (Action id)) () -> View id () -- | An option for a dropdown. First argument is passed to (opt -- -> Action id) in the dropdown, and to the selected predicate option :: (HyperView id, Eq opt) => opt -> View (Option opt id (Action id)) () -> View (Option opt id (Action id)) () -- | The view context for an option data Option opt id action -- | Give visual feedback when an action is in-flight. -- --
--   myView = do
--     onRequest loadingIndicator $ do
--       el_ "Loaded"
--     where
--       loadingIndicator = el_ "Loading..."
--   
onRequest :: View id () -> View id () -> View id () -- | Send the action after N milliseconds. Can be used to implement lazy -- loading or polling -- --
--   pollMessageView :: Text -> View Message ()
--   pollMessageView m = do
--     onLoad LoadMessage 1000 $ do
--       el bold "Current Message. Reloading in 1s"
--       el_ (text m)
--   
onLoad :: HyperView id => Action id -> DelayMs -> View id () -> View id () type DelayMs = Int -- | Form Fields are identified by a type -- --
--   data User = User Text deriving (Generic, FormField)
--   data Age = Age Int deriving (Generic, FormField)
--   
class FormField a -- | Type-safe <form>. Calls (Action id) on submit -- --
--   userForm :: Validation -> View FormView ()
--   userForm v = do
--     form Signup v id $ do
--       el Style.h1 "Sign Up"
--   
--       field @User id Style.invalid $ do
--         label "Username"
--         input Username (placeholder "username")
--         el_ invalidText
--   
--       field @Age id Style.invalid $ do
--         label "Age"
--         input Number (placeholder "age" . value "0")
--         el_ invalidText
--   
--       submit (border 1) "Submit"
--   
form :: forall id. HyperView id => Action id -> Validation -> Mod -> View (FormFields id) () -> View id () -- | Display a FormField -- --
--   data Age = Age Int deriving (Generic, FormField)
--   
--   myForm = do
--     form SignUp mempty id $ do
--       field @Age id id $ do
--        label Age
--        input Number (value "0")
--   
field :: forall a id. FormField a => Mod -> Mod -> View (Input id a) () -> View (FormFields id) () -- | label for a field label :: Text -> View (Input id a) () -- | input for a field input :: InputType -> Mod -> View (Input id a) () -- | Button that submits the form. Use button to specify -- actions other than submit submit :: Mod -> View (FormFields id) () -> View (FormFields id) () placeholder :: Text -> Mod -- | Choose one for inputs to give the browser autocomplete hints data InputType NewPassword :: InputType CurrentPassword :: InputType Username :: InputType Email :: InputType Number :: InputType TextInput :: InputType Name :: InputType OneTimeCode :: InputType Organization :: InputType StreetAddress :: InputType Country :: InputType CountryName :: InputType PostalCode :: InputType Search :: InputType -- | Parse a FormField from the request -- --
--   formAction :: (Hyperbole :> es, UserDB :> es) => FormView -> FormAction -> Eff es (View FormView ())
--   formAction _ SignUp = do
--     a <- formField @Age
--     u <- formField @User
--     saveUserToDB u a
--     pure $ el_ "Saved!"
--   
formField :: forall a es. (FormField a, Hyperbole :> es) => Eff es a -- | Validation results for a form -- --
--   validateUser :: User -> Age -> Validation
--   validateUser (User u) (Age a) =
--     validation
--       [ validate @Age (a < 20) "User must be at least 20 years old"
--       , validate @User (T.elem ' ' u) "Username must not contain spaces"
--       , validate @User (T.length u < 4) "Username must be at least 4 chars"
--       ]
--   
--   formAction :: (Hyperbole :> es, UserDB :> es) => FormView -> FormAction -> Eff es (View FormView ())
--   formAction _ SignUp = do
--     a <- formField @Age
--     u <- formField @User
--   
--     case validateUser u a of
--       Validation [] -> successView
--       errs -> userForm v
--   
-- -- @ newtype Validation Validation :: [(Text, Text)] -> Validation -- | specify a check for a Validation validate :: forall a. FormField a => Bool -> Text -> Maybe (Text, Text) -- | Create a Validation from list of validators validation :: [Maybe (Text, Text)] -> Validation -- | Display any validation error for the FormField from the -- Validation passed to form -- --
--   field @User id Style.invalid $ do
--     label "Username"
--     input Username (placeholder "username")
--     el_ invalidText
--   
invalidText :: forall a id. FormField a => View (Input id a) () -- | In any load or handle, you can use this Effect to get -- extra request information or control the response manually. -- -- For most Pages, you won't need to use this effect directly. Use -- custom Routes for request info, and return Views to -- respond data Hyperbole :: Effect -- | Require a given parameter from the Query arguments -- --
--   myPage :: Page es Response
--   myPage = do
--     load $ do
--       token <- reqParam "token"
--       sideEffectUsingToken token
--       pure myPageView
--   
reqParam :: (Hyperbole :> es, FromHttpApiData a) => Text -> Eff es a -- | Return the entire Query -- --
--   myPage :: Page es Response
--   myPage = do
--     load $ do
--       q <- reqParams
--       case lookupParam "token" q of
--         Nothing -> pure $ errorView "Missing Token in Query String"
--         Just t -> do
--           sideEffectUsingToken token
--           pure myPageView
--   
reqParams :: Hyperbole :> es => Eff es Query -- | Return all information about the Request request :: Hyperbole :> es => Eff es Request -- | Lookup the query param in the Query lookupParam :: ByteString -> Query -> Maybe Text -- | Return the request body as a Web.FormUrlEncoded.Form -- -- Prefer using Type-Safe Forms when possible formData :: Hyperbole :> es => Eff es Form -- | Respond immediately with 404 Not Found -- --
--   userLoad :: (Hyperbole :> es, Users :> es) => UserId -> Eff es User
--   userLoad uid = do
--     mu <- send (LoadUser uid)
--     maybe notFound pure mu
--   
--   myPage :: (Hyperbole :> es, Users :> es) => Eff es View
--   myPage = do
--     load $ do
--       u <- userLoad 100
--       -- skipped if user = Nothing
--       pure $ userView u
--   
notFound :: Hyperbole :> es => Eff es a -- | Redirect immediately to the Url redirect :: Hyperbole :> es => Url -> Eff es a -- | Respond with the given view, and stop execution respondEarly :: (Hyperbole :> es, HyperView id) => id -> View id () -> Eff es () -- | Lookup a session variable by keyword -- --
--   load $ do
--     tok <- session "token"
--     ...
--   
session :: (Hyperbole :> es, FromHttpApiData a) => Text -> Eff es (Maybe a) -- | Set a session variable by keyword -- --
--   load $ do
--     t <- reqParam "token"
--     setSession "token" t
--     ...
--   
setSession :: (Hyperbole :> es, ToHttpApiData a) => Text -> a -> Eff es () -- | Clear the user's session clearSession :: Hyperbole :> es => Text -> Eff es () -- | Trigger actions for another view. They will update the view specified -- --
--   otherView :: View OtherView ()
--   otherView = do
--     el_ "This is not a message view"
--     button OtherAction id "Do Something"
--   
--     target (Message 2) $ do
--       el_ "Now we can trigger a MessageAction which will update our Message HyperView, not this one"
--       button ClearMessage id "Clear Message #2"
--   
target :: HyperView id => id -> View id () -> View a () -- | Manually set the response to the given view. Normally you return a -- View from load or handle instead of using this view :: Hyperbole :> es => View () () -> Eff es Response -- | Types that can be serialized. HyperView requires this for both -- its view id and action -- --
--   data Message = Message Int
--     deriving (Generic, Param)
--   
class Param a toParam :: Param a => a -> Text toParam :: (Param a, Generic a, GParam (Rep a)) => a -> Text parseParam :: Param a => Text -> Maybe a parseParam :: (Param a, Generic a, GParam (Rep a)) => Text -> Maybe a -- | Valid responses for a Hyperbole effect. Use notFound, -- etc instead. Reminds you to use load in your Page -- --
--   myPage :: (Hyperbole :> es) => Page es Response
--   myPage = do
--     -- compiler error: () does not equal Response
--     pure ()
--   
data Response -- | A constraint that requires that a particular effect e is a -- member of the type-level list es. This is used to -- parameterize an Eff computation over an arbitrary list of -- effects, so long as e is somewhere in the list. -- -- For example, a computation that only needs access to a mutable value -- of type Integer would have the following type: -- --
--   State Integer :> es => Eff es ()
--   
class () => (e :: Effect) :> (es :: [Effect]) -- | The Eff monad provides the implementation of a computation that -- performs an arbitrary set of effects. In Eff es a, -- es is a type-level list that contains all the effects that -- the computation may perform. For example, a computation that produces -- an Integer by consuming a String from the global -- environment and acting upon a single mutable value of type Bool -- would have the following type: -- --
--   (Reader String :> es, State Bool :> es) => Eff es Integer
--   
-- -- Abstracting over the list of effects with (:>): -- -- data () => Eff (es :: [Effect]) a -- | The WAI application. -- -- Note that, since WAI 3.0, this type is structured in continuation -- passing style to allow for proper safe resource handling. This was -- handled in the past via other means (e.g., ResourceT). As a -- demonstration: -- --
--   app :: Application
--   app req respond = bracket_
--       (putStrLn "Allocating scarce resource")
--       (putStrLn "Cleaning up")
--       (respond $ responseLBS status200 [] "Hello World")
--   
type Application = Request -> Response -> IO ResponseReceived -> IO ResponseReceived -- | Representable types of kind *. This class is derivable in GHC -- with the DeriveGeneric flag on. -- -- A Generic instance must satisfy the following laws: -- --
--   from . toid
--   to . fromid
--   
class () => Generic a