Lightweight frontend library for GHCJS
Go to file
2021-10-24 05:38:01 +04:00
benchmarks Add benchmarks 2021-10-24 05:38:01 +04:00
examples Distinguish DOMNode and DOMElement 2021-10-23 05:24:56 +04:00
src Add benchmarks 2021-10-24 05:38:01 +04:00
.gitignore Add benchmarks 2021-10-24 05:38:01 +04:00
8.6.0.nix Add benchmarks 2021-10-24 05:38:01 +04:00
8.10.7.nix Add benchmarks 2021-10-24 05:38:01 +04:00
htmlt.cabal Add benchmarks 2021-10-24 05:38:01 +04:00
README.md Bug fixes for firefox 2021-10-22 06:09:23 +04:00
Setup.hs First commit 2019-09-19 22:30:50 +04:00
shell.nix Add benchmarks 2021-10-24 05:38:01 +04:00

🔥API is unstable and incomplete, do not use in production🔥

Small experimental GUI library in haskell

Quick API summary

Constructing DOM

el :: Text -> Html x -> Html x
el' :: Text -> Html x -> Html (x, Node)
elns :: Text -> Text -> Html x -> Html x
text :: Text -> Html ()
dynText :: Dynamic Text -> Html ()

el, el' and elns create a new HTML element and attach it to the root, which is given by Reader-like enviroment inside HtmlEnv. There are shortcut versions (div_, h1_, span_ etc) for the most common HTML5 tags declared in Html.Element

Applying attributes and properties

prop :: Text -> v -> Html ()
dynProp :: Text -> Dynamic v -> Html ()

attr :: Text -> Text -> Html ()
dynAttr :: Text -> Text -> Html ()

prop assignes a property (like value to HTMLInputElement) to a parent element dynProp assignes a dynamic property (Dynamic a), attr and dynAttr do the same but for html attributes instead of properties (there is a suble difference).

-- Applying properties to elements
menuWidget :: Html () 
menuWidget = 
  ul_ [class_ "menu"] do
    li_ $
      a_ [href_ "#one"] $ "One" -- Html has IsString instance 
    li_ $
      a_ [href_ "#two"] $ "Two"
    li_ $
      a_ [href_ "#three"] $ "Three"

Reacting to DOM events

on :: Text -> (DOMEvent -> Html ()) -> Html ()
on_ :: Text -> Html () -> Html ()

Essentially on and on_ call addEventListener on the current root and run the given action when DOM event fires

counterWidget :: Html ()
counterWidget = do
  counterRef <- newRef @Int 0
  div_ do
    span_ $
      dynText $ T.pack . show <$> fromRef counterRef
    button_ do
      on_ "click" $ modifyRef counterRef pred
      text "Decrease"
    button_ do
      on_ "click" $ modifyRef counterRef succ
      text "Increase"

Minimal complete app

import Data.Text
import HtmlT

main :: IO ()
main = attachToBody do
  colorRef <- newRef 0
  div_ [class_ "root"] do
    h1_ do
      dynStyle "color" $ getColor <$> fromRef colorRef
      on_ "mouseenter" do modifyRef colorRef (+ 1)
      text "Hello, World!"
    el "style" do text styles
  where
    getColor n =
      colors !! (n `mod` Prelude.length colors)

colors :: [Text]
colors =
  [ "rgb(173,192,84)", "rgb(22,153,190)", "rgb(22,93,24)", "rgb(199,232,42)"
  , "rgb(235,206,57)", "rgb(225,57,149)", "rgb(255,134,157)", "rgb(231,251,35)"
  , "rgb(148,122,45)", "rgb(227,10,30)", "rgb(97,22,125)", "rgb(239,243,10)"
  , "rgb(155,247,3)", "rgb(199,31,74)", "rgb(109,198,34)", "rgb(170,52,228)"
  , "rgb(61,44,247)", "rgb(118,45,39)", "rgb(248,116,17)", "rgb(27,184,238)"
  , "rgb(117,23,222)" ]

Other examples

Hello World source | demo
TodoMVC source | demo
Simple Routing source | demo

Todos

  • API to display sum types
  • Reduce compile time by getting rid of ghcjs-dom and jsaddle-dom from dependency list
  • Faster updates for large lists, using similar technique to diffarray
  • Bindings to non-web GUIs (e.g. GTK or ReactNative)
  • Add benchmarks