Strongly-typed front-end: experiment 2, simple application, in PureScript
In PureScript world there are quite a few libraries for React. And all of them have terrible (or rather non-existent) documentation, so I had to use as much intuition as outdated and barely working code samples.
Initial application structure:
module Main where
import Prelude
import Control.Monad.Eff
import Data.Maybe
import Data.Maybe.Unsafe (fromJust)
import Data.Nullable (toMaybe)
import Effect (Effect)
import Effect.Console (log)
import DOM (DOM())
import DOM.HTML (window)
import DOM.HTML.Document (body)
import DOM.HTML.Types (htmlElementToElement)
import DOM.HTML.Window (document)
import DOM.Node.Types (Element())
import React
import React.DOM as DOM
import React.DOM.Props as Props
type Shape = Circle | Square
calculateArea :: Maybe Shape -> Float -> Float
calculateArea Nothing _ = 0
calculateArea (Just Circle) value = pi * value * value
calculateArea (Just Square) value = value * value
getShape :: String -> Maybe Shape
getShape "circle" = Just Circle
getShape "square" = Just Square
getShape _ = Nothing
onShapeChanged ctx evt = do
writeState ctx { shape: getShape ((unsafeCoerce evt).target.value) }
onCalculateAreaClicked ctx evt = do
{ shape, value } <- readState ctx
writeState ctx { area: calculateArea shape value }
areaCalculator = createClass $ spec { shape: Nothing, value: 0, area: 0 } \ctx -> do
{ shape, value, area } <- readState ctx
return $ DOM.div [] [
DOM.div [] [
DOM.select [ Props.onChange (onShapeChanged ctx) ] [
DOM.option [ Props.value "" ] [ DOM.text "Select shape" ],
DOM.option [ Props.value "circle" ] [ DOM.text "Circle" ],
DOM.option [ Props.value "square" ] [ DOM.text "Square" ]
],
DOM.input [ Props.value (show value) ] [],
DOM.button [ Props.onClick (onCalculateAreaClicked ctx) ] [ DOM.text "Calculate area" ]
],
DOM.div [] [
DOM.text ("Area: " ++ (show area))
]
]
main = container >>= render ui
where
ui :: ReactElement
ui = createFactory areaCalculator {}
container :: forall eff. Eff (dom :: DOM | eff) Element
container = do
win <- window
doc <- document win
elt <- fromJust <$> toMaybe <$> body doc
return $ htmlElementToElement elt