aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/app/Form
diff options
context:
space:
mode:
authorLibravatar Alexander Foremny <aforemny@posteo.de>2024-06-04 09:28:10 +0200
committerLibravatar Alexander Foremny <aforemny@posteo.de>2024-06-04 09:37:28 +0200
commit342ebdf61b3b9021b9e58cfce607e96a6e7ae54e (patch)
treef8a97170fc688c8177db22df524c3775f137bffd /frontend/app/Form
parenta19623cc781c62e50ce7e5c71635e664c9338846 (diff)
refactor `Form` module
Diffstat (limited to 'frontend/app/Form')
-rw-r--r--frontend/app/Form/Input.hs26
-rw-r--r--frontend/app/Form/Internal.hs60
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"]
+ ]