2024-06-04 09:28:10 +02:00
|
|
|
module Form.Internal
|
|
|
|
|
( Form (..),
|
|
|
|
|
mapValues,
|
|
|
|
|
runForm,
|
2024-06-06 22:42:44 +02:00
|
|
|
optional,
|
2024-06-04 09:28:10 +02:00
|
|
|
)
|
|
|
|
|
where
|
|
|
|
|
|
2024-06-06 22:42:44 +02:00
|
|
|
import Data.Text qualified as T
|
2024-06-04 09:28:10 +02:00
|
|
|
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)
|
2024-06-04 09:59:10 +02:00
|
|
|
runForm form i =
|
|
|
|
|
form_ [onSubmit (either (\_ -> Left i) (Right) (form.fill i))] $
|
|
|
|
|
(fmap Left <$> form.view i)
|
|
|
|
|
<> [button_ [type_ "submit"] [text "submit"]]
|
2024-06-06 22:42:44 +02:00
|
|
|
|
|
|
|
|
class IsEmpty i where
|
|
|
|
|
isEmpty :: i -> Bool
|
|
|
|
|
|
|
|
|
|
instance IsEmpty T.Text where
|
|
|
|
|
isEmpty = T.null . T.strip
|
|
|
|
|
|
|
|
|
|
optional :: (IsEmpty i) => Form i o -> Form i (Maybe o)
|
|
|
|
|
optional form =
|
|
|
|
|
Form
|
|
|
|
|
{ view = \i -> form.view i,
|
|
|
|
|
fill = \i -> if isEmpty i then Right Nothing else Just <$> form.fill i
|
|
|
|
|
}
|