diff options
author | Alexander Foremny <aforemny@posteo.de> | 2024-06-04 09:28:10 +0200 |
---|---|---|
committer | Alexander Foremny <aforemny@posteo.de> | 2024-06-04 09:37:28 +0200 |
commit | 342ebdf61b3b9021b9e58cfce607e96a6e7ae54e (patch) | |
tree | f8a97170fc688c8177db22df524c3775f137bffd /frontend/app/Form | |
parent | a19623cc781c62e50ce7e5c71635e664c9338846 (diff) |
refactor `Form` module
Diffstat (limited to 'frontend/app/Form')
-rw-r--r-- | frontend/app/Form/Input.hs | 26 | ||||
-rw-r--r-- | frontend/app/Form/Internal.hs | 60 |
2 files changed, 86 insertions, 0 deletions
diff --git a/frontend/app/Form/Input.hs b/frontend/app/Form/Input.hs new file mode 100644 index 0000000..a9648c4 --- /dev/null +++ b/frontend/app/Form/Input.hs @@ -0,0 +1,26 @@ +module Form.Input + ( string, + ) +where + +import Data.Text qualified as T +import Form.Internal +import Miso +import Miso.String (toMisoString) + +string :: String -> Form T.Text T.Text +string label = + Form + { view = \i -> + [ div_ [] $ + [ label_ [] $ + [ text (toMisoString label), + input_ + [ type_ "text", + value_ (toMisoString i) + ] + ] + ] + ], + fill = \i -> Right i + } diff --git a/frontend/app/Form/Internal.hs b/frontend/app/Form/Internal.hs new file mode 100644 index 0000000..7782368 --- /dev/null +++ b/frontend/app/Form/Internal.hs @@ -0,0 +1,60 @@ +module Form.Internal + ( Form (..), + mapValues, + runForm, + ) +where + +import Miso + +data Form i o = Form + { view :: i -> [View i], + fill :: i -> Either String o + } + +instance Functor (Form i) where + fmap f (Form {view, fill}) = + Form + { fill = fmap f . fill, + .. + } + +instance Applicative (Form i) where + pure x = + Form + { view = const [], + fill = const (Right x) + } + + f <*> x = + Form + { view = liftA2 (<>) f.view x.view, + fill = \i -> ($) <$> f.fill i <*> x.fill i + } + +instance Monad (Form i) where + form >>= mkForm = + Form + { view = \i -> + form.view i + <> case form.fill i of + Right x -> (mkForm x).view i + Left _ -> [], + fill = \i -> case form.fill i of + Right x -> (mkForm x).fill i + Left e -> Left e + } + +mapValues :: (i' -> i) -> (i -> i' -> i') -> Form i o -> Form i' o +mapValues get set (Form {view, fill}) = + Form + { view = \i -> fmap (flip set i) <$> view (get i), + fill = fill . get + } + +runForm :: Form i o -> i -> View (Either i o) +runForm (Form {view}) i = + div_ [] $ + (fmap Left <$> view i) + <> [ button_ [type_ "submit"] [text "submit"] + ] |