{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module Shpadoinkle.Html.Property where
import Control.Monad (msum)
import qualified Data.Set as Set
import Data.String hiding (unwords)
import Data.Text
import Prelude hiding (unwords)
import Shpadoinkle
import Shpadoinkle.Html.TH
class ToPropText a where toPropText :: a -> Text
instance ToPropText Text where toPropText = id
instance ToPropText Int where toPropText = pack . show
instance ToPropText Float where toPropText = pack . show
instance ToPropText Bool where toPropText = \case True -> "true"; False -> "false"
textProperty :: ToPropText a => Text -> a -> (Text, Prop m b)
textProperty k = textProperty' k . toPropText
textProperty' :: Text -> Text -> (Text, Prop m b)
textProperty' k = (,) k . textProp
{-# INLINE textProperty' #-}
newtype ClassList = ClassList { unClassList :: Set.Set Text } deriving (Eq, Ord, Show, Semigroup, Monoid)
instance IsString ClassList where fromString = ClassList . Set.fromList . split (== ' ') . pack
class ClassListRep a where asClass :: a -> ClassList
instance ClassListRep Text where asClass = ClassList . Set.fromList . split (== ' ')
instance ClassListRep ClassList where asClass = id
instance ClassListRep (Text, Bool) where asClass (a, b) = if b then asClass a else mempty
instance ClassListRep (ClassList, Bool) where asClass = \case (cl, True) -> cl; _ -> mempty
instance ClassListRep cl => ClassListRep [cl] where asClass = foldMap asClass
flagProperty :: Text -> Bool -> (Text, Prop m a)
flagProperty t = (,) t . flagProp
class' :: ClassListRep cl => cl -> (Text, Prop m a)
class' = className . unwords . Set.toList . unClassList . asClass
className :: Text -> (Text, Prop m a)
className = textProperty "className"
for' :: Text -> (Text, Prop m a)
for' = textProperty "htmlFor"
styleProp :: [(Text, Text)] -> (Text, Prop m a)
styleProp = textProperty "style" . intercalate ";" . fmap subStyle
where subStyle (k,v) = k <> ":" <> v
px, toEm, rem :: (Num a, Show a) => a -> Text
px = (<> "px") . pack . show
toEm = (<> "em") . pack . show
rem = (<> "rem") . pack . show
$(msum <$> mapM mkBoolProp
[ "checked", "selected", "hidden", "autocomplete", "autofocus", "disabled", "autoplay", "controls", "loop"
, "multiple", "novalidate", "readonly", "required", "ismap", "usemap", "default'", "reversed"
])
$(msum <$> mapM mkTextProp
[ "id'", "type'", "rel", "href", "placeholder", "value", "src", "title"
, "accept", "action", "acceptCharset", "enctype", "method", "pattern"
, "max", "min", "step", "wrap", "target", "download", "hreflang", "media", "ping", "shape", "coords"
, "alt", "preload", "poster", "name'", "kind'", "srclang", "sandbox", "srcdoc", "align"
, "headers", "scope", "datetime", "pubdate", "manifest", "contextmenu", "draggable"
, "dropzone", "itemprop", "charset", "content", "property", "innerHTML", "lang"
])
$(msum <$> mapM mkIntProp
[ "tabIndex", "width", "height", "maxLength", "minLength" ])
newTab :: (Text, Prop m a)
newTab = target "_blank"
tabbable :: (Text, Prop m a)
tabbable = tabIndex 0