{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}

module Web.View.Types where

import Data.Map (Map)
import Data.String (IsString (..))
import Data.Text (Text, pack, unpack)
import Data.Text qualified as T
import GHC.Generics (Generic)
import Numeric (showFFloat)
import Text.Casing (kebab)


data Content
  = Node Element
  | Text Text
  | -- | Raw embedded HTML or SVG. See 'Web.View.Element.raw'
    Raw Text
  deriving (Int -> Content -> ShowS
[Content] -> ShowS
Content -> String
(Int -> Content -> ShowS)
-> (Content -> String) -> ([Content] -> ShowS) -> Show Content
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Content -> ShowS
showsPrec :: Int -> Content -> ShowS
$cshow :: Content -> String
show :: Content -> String
$cshowList :: [Content] -> ShowS
showList :: [Content] -> ShowS
Show)


-- | A single HTML tag. Note that the class attribute is stored separately from the rest of the attributes to make adding styles easier
data Element = Element
  { Element -> Bool
inline :: Bool
  , Element -> Text
name :: Name
  , Element -> Attributes
attributes :: Attributes
  , Element -> [Content]
children :: [Content]
  }
  deriving (Int -> Element -> ShowS
[Element] -> ShowS
Element -> String
(Int -> Element -> ShowS)
-> (Element -> String) -> ([Element] -> ShowS) -> Show Element
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Element -> ShowS
showsPrec :: Int -> Element -> ShowS
$cshow :: Element -> String
show :: Element -> String
$cshowList :: [Element] -> ShowS
showList :: [Element] -> ShowS
Show)


-- | Construct an Element
element :: Name -> Attributes -> [Content] -> Element
element :: Text -> Attributes -> [Content] -> Element
element = Bool -> Text -> Attributes -> [Content] -> Element
Element Bool
False


data Attributes = Attributes
  { Attributes -> [Class]
classes :: [Class]
  , Attributes -> Map Text Text
other :: Map Name AttValue
  }
  deriving (Int -> Attributes -> ShowS
[Attributes] -> ShowS
Attributes -> String
(Int -> Attributes -> ShowS)
-> (Attributes -> String)
-> ([Attributes] -> ShowS)
-> Show Attributes
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Attributes -> ShowS
showsPrec :: Int -> Attributes -> ShowS
$cshow :: Attributes -> String
show :: Attributes -> String
$cshowList :: [Attributes] -> ShowS
showList :: [Attributes] -> ShowS
Show)
instance Semigroup Attributes where
  Attributes
a1 <> :: Attributes -> Attributes -> Attributes
<> Attributes
a2 = [Class] -> Map Text Text -> Attributes
Attributes (Attributes
a1.classes [Class] -> [Class] -> [Class]
forall a. Semigroup a => a -> a -> a
<> Attributes
a2.classes) (Attributes
a1.other Map Text Text -> Map Text Text -> Map Text Text
forall a. Semigroup a => a -> a -> a
<> Attributes
a2.other)
instance Monoid Attributes where
  mempty :: Attributes
mempty = [Class] -> Map Text Text -> Attributes
Attributes [] Map Text Text
forall a. Monoid a => a
mempty
type Attribute = (Name, AttValue)
type Name = Text
type AttValue = Text


-- * Attribute Modifiers


{- | Element functions expect a Mod function as their first argument that adds attributes and classes.

> userEmail :: User -> View c ()
> userEmail user = input (fontSize 16 . active) (text user.email)
>   where
>     active = isActive user then bold else id
-}
type Mod = Attributes -> Attributes


-- * Atomic CSS


-- TODO: document atomic CSS here?

-- | All the atomic classes used in a 'Web.View.View'
type CSS = Map Selector Class


-- | Atomic classes include a selector and the corresponding styles
data Class = Class
  { Class -> Selector
selector :: Selector
  , Class -> Styles
properties :: Styles
  }
  deriving (Int -> Class -> ShowS
[Class] -> ShowS
Class -> String
(Int -> Class -> ShowS)
-> (Class -> String) -> ([Class] -> ShowS) -> Show Class
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Class -> ShowS
showsPrec :: Int -> Class -> ShowS
$cshow :: Class -> String
show :: Class -> String
$cshowList :: [Class] -> ShowS
showList :: [Class] -> ShowS
Show)


-- | The styles to apply for a given atomic 'Class'
type Styles = Map Name StyleValue


-- | The selector to use for the given atomic 'Class'
data Selector = Selector
  { Selector -> Maybe Text
parent :: Maybe Text
  , Selector -> Maybe Pseudo
pseudo :: Maybe Pseudo
  , Selector -> Maybe Media
media :: Maybe Media
  , Selector -> ClassName
className :: ClassName
  }
  deriving (Selector -> Selector -> Bool
(Selector -> Selector -> Bool)
-> (Selector -> Selector -> Bool) -> Eq Selector
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Selector -> Selector -> Bool
== :: Selector -> Selector -> Bool
$c/= :: Selector -> Selector -> Bool
/= :: Selector -> Selector -> Bool
Eq, Eq Selector
Eq Selector =>
(Selector -> Selector -> Ordering)
-> (Selector -> Selector -> Bool)
-> (Selector -> Selector -> Bool)
-> (Selector -> Selector -> Bool)
-> (Selector -> Selector -> Bool)
-> (Selector -> Selector -> Selector)
-> (Selector -> Selector -> Selector)
-> Ord Selector
Selector -> Selector -> Bool
Selector -> Selector -> Ordering
Selector -> Selector -> Selector
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Selector -> Selector -> Ordering
compare :: Selector -> Selector -> Ordering
$c< :: Selector -> Selector -> Bool
< :: Selector -> Selector -> Bool
$c<= :: Selector -> Selector -> Bool
<= :: Selector -> Selector -> Bool
$c> :: Selector -> Selector -> Bool
> :: Selector -> Selector -> Bool
$c>= :: Selector -> Selector -> Bool
>= :: Selector -> Selector -> Bool
$cmax :: Selector -> Selector -> Selector
max :: Selector -> Selector -> Selector
$cmin :: Selector -> Selector -> Selector
min :: Selector -> Selector -> Selector
Ord, Int -> Selector -> ShowS
[Selector] -> ShowS
Selector -> String
(Int -> Selector -> ShowS)
-> (Selector -> String) -> ([Selector] -> ShowS) -> Show Selector
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Selector -> ShowS
showsPrec :: Int -> Selector -> ShowS
$cshow :: Selector -> String
show :: Selector -> String
$cshowList :: [Selector] -> ShowS
showList :: [Selector] -> ShowS
Show)


instance IsString Selector where
  fromString :: String -> Selector
fromString String
s = Maybe Text -> Maybe Pseudo -> Maybe Media -> ClassName -> Selector
Selector Maybe Text
forall a. Maybe a
Nothing Maybe Pseudo
forall a. Maybe a
Nothing Maybe Media
forall a. Maybe a
Nothing (String -> ClassName
forall a. IsString a => String -> a
fromString String
s)


-- | Create a 'Selector' given only a 'ClassName'
selector :: ClassName -> Selector
selector :: ClassName -> Selector
selector = Maybe Text -> Maybe Pseudo -> Maybe Media -> ClassName -> Selector
Selector Maybe Text
forall a. Maybe a
Nothing Maybe Pseudo
forall a. Maybe a
Nothing Maybe Media
forall a. Maybe a
Nothing


-- | A class name
newtype ClassName = ClassName
  { ClassName -> Text
text :: Text
  }
  deriving newtype (ClassName -> ClassName -> Bool
(ClassName -> ClassName -> Bool)
-> (ClassName -> ClassName -> Bool) -> Eq ClassName
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ClassName -> ClassName -> Bool
== :: ClassName -> ClassName -> Bool
$c/= :: ClassName -> ClassName -> Bool
/= :: ClassName -> ClassName -> Bool
Eq, Eq ClassName
Eq ClassName =>
(ClassName -> ClassName -> Ordering)
-> (ClassName -> ClassName -> Bool)
-> (ClassName -> ClassName -> Bool)
-> (ClassName -> ClassName -> Bool)
-> (ClassName -> ClassName -> Bool)
-> (ClassName -> ClassName -> ClassName)
-> (ClassName -> ClassName -> ClassName)
-> Ord ClassName
ClassName -> ClassName -> Bool
ClassName -> ClassName -> Ordering
ClassName -> ClassName -> ClassName
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ClassName -> ClassName -> Ordering
compare :: ClassName -> ClassName -> Ordering
$c< :: ClassName -> ClassName -> Bool
< :: ClassName -> ClassName -> Bool
$c<= :: ClassName -> ClassName -> Bool
<= :: ClassName -> ClassName -> Bool
$c> :: ClassName -> ClassName -> Bool
> :: ClassName -> ClassName -> Bool
$c>= :: ClassName -> ClassName -> Bool
>= :: ClassName -> ClassName -> Bool
$cmax :: ClassName -> ClassName -> ClassName
max :: ClassName -> ClassName -> ClassName
$cmin :: ClassName -> ClassName -> ClassName
min :: ClassName -> ClassName -> ClassName
Ord, String -> ClassName
(String -> ClassName) -> IsString ClassName
forall a. (String -> a) -> IsString a
$cfromString :: String -> ClassName
fromString :: String -> ClassName
IsString, Int -> ClassName -> ShowS
[ClassName] -> ShowS
ClassName -> String
(Int -> ClassName -> ShowS)
-> (ClassName -> String)
-> ([ClassName] -> ShowS)
-> Show ClassName
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ClassName -> ShowS
showsPrec :: Int -> ClassName -> ShowS
$cshow :: ClassName -> String
show :: ClassName -> String
$cshowList :: [ClassName] -> ShowS
showList :: [ClassName] -> ShowS
Show)


-- | Convert a type into a className segment to generate unique compound style names based on the value
class ToClassName a where
  toClassName :: a -> Text
  default toClassName :: (Show a) => a -> Text
  toClassName = Text -> Text
T.toLower (Text -> Text) -> (a -> Text) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show


instance ToClassName Int
instance ToClassName Text where
  toClassName :: Text -> Text
toClassName = Text -> Text
forall a. a -> a
id
instance ToClassName Float where
  toClassName :: Float -> Text
toClassName Float
f = String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
noDot ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
3) Float
f String
""
   where
    noDot :: Char -> Char
noDot Char
'.' = Char
'-'
    noDot Char
c = Char
c


{- | Psuedos allow for specifying styles that only apply in certain conditions. See `Web.View.Style.hover` etc

> el (color Primary . hover (color White)) "hello"
-}
data Pseudo
  = Hover
  | Active
  | Even
  | Odd
  deriving (Int -> Pseudo -> ShowS
[Pseudo] -> ShowS
Pseudo -> String
(Int -> Pseudo -> ShowS)
-> (Pseudo -> String) -> ([Pseudo] -> ShowS) -> Show Pseudo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Pseudo -> ShowS
showsPrec :: Int -> Pseudo -> ShowS
$cshow :: Pseudo -> String
show :: Pseudo -> String
$cshowList :: [Pseudo] -> ShowS
showList :: [Pseudo] -> ShowS
Show, Pseudo -> Pseudo -> Bool
(Pseudo -> Pseudo -> Bool)
-> (Pseudo -> Pseudo -> Bool) -> Eq Pseudo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Pseudo -> Pseudo -> Bool
== :: Pseudo -> Pseudo -> Bool
$c/= :: Pseudo -> Pseudo -> Bool
/= :: Pseudo -> Pseudo -> Bool
Eq, Eq Pseudo
Eq Pseudo =>
(Pseudo -> Pseudo -> Ordering)
-> (Pseudo -> Pseudo -> Bool)
-> (Pseudo -> Pseudo -> Bool)
-> (Pseudo -> Pseudo -> Bool)
-> (Pseudo -> Pseudo -> Bool)
-> (Pseudo -> Pseudo -> Pseudo)
-> (Pseudo -> Pseudo -> Pseudo)
-> Ord Pseudo
Pseudo -> Pseudo -> Bool
Pseudo -> Pseudo -> Ordering
Pseudo -> Pseudo -> Pseudo
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Pseudo -> Pseudo -> Ordering
compare :: Pseudo -> Pseudo -> Ordering
$c< :: Pseudo -> Pseudo -> Bool
< :: Pseudo -> Pseudo -> Bool
$c<= :: Pseudo -> Pseudo -> Bool
<= :: Pseudo -> Pseudo -> Bool
$c> :: Pseudo -> Pseudo -> Bool
> :: Pseudo -> Pseudo -> Bool
$c>= :: Pseudo -> Pseudo -> Bool
>= :: Pseudo -> Pseudo -> Bool
$cmax :: Pseudo -> Pseudo -> Pseudo
max :: Pseudo -> Pseudo -> Pseudo
$cmin :: Pseudo -> Pseudo -> Pseudo
min :: Pseudo -> Pseudo -> Pseudo
Ord)


-- | The value of a css style property
newtype StyleValue = StyleValue String
  deriving newtype (String -> StyleValue
(String -> StyleValue) -> IsString StyleValue
forall a. (String -> a) -> IsString a
$cfromString :: String -> StyleValue
fromString :: String -> StyleValue
IsString, Int -> StyleValue -> ShowS
[StyleValue] -> ShowS
StyleValue -> String
(Int -> StyleValue -> ShowS)
-> (StyleValue -> String)
-> ([StyleValue] -> ShowS)
-> Show StyleValue
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StyleValue -> ShowS
showsPrec :: Int -> StyleValue -> ShowS
$cshow :: StyleValue -> String
show :: StyleValue -> String
$cshowList :: [StyleValue] -> ShowS
showList :: [StyleValue] -> ShowS
Show)


-- | Use a type as a css style property value
class ToStyleValue a where
  toStyleValue :: a -> StyleValue
  default toStyleValue :: (Show a) => a -> StyleValue
  toStyleValue = String -> StyleValue
StyleValue (String -> StyleValue) -> (a -> String) -> a -> StyleValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
kebab ShowS -> (a -> String) -> a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show


instance ToStyleValue String where
  toStyleValue :: String -> StyleValue
toStyleValue = String -> StyleValue
StyleValue


instance ToStyleValue Text where
  toStyleValue :: Text -> StyleValue
toStyleValue = String -> StyleValue
StyleValue (String -> StyleValue) -> (Text -> String) -> Text -> StyleValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack


instance ToStyleValue Int


instance ToStyleValue Float where
  -- this does not convert to a percent, just a ratio
  toStyleValue :: Float -> StyleValue
toStyleValue Float
n = String -> StyleValue
StyleValue (String -> StyleValue) -> String -> StyleValue
forall a b. (a -> b) -> a -> b
$ Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
2) Float
n String
""


data Length
  = -- | Px, converted to Rem. Allows for the user to change the document font size and have the app scale accordingly. But allows the programmer to code in pixels to match a design
    PxRem PxRem
  | Pct Float
  deriving (Int -> Length -> ShowS
[Length] -> ShowS
Length -> String
(Int -> Length -> ShowS)
-> (Length -> String) -> ([Length] -> ShowS) -> Show Length
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Length -> ShowS
showsPrec :: Int -> Length -> ShowS
$cshow :: Length -> String
show :: Length -> String
$cshowList :: [Length] -> ShowS
showList :: [Length] -> ShowS
Show)


instance ToClassName Length where
  toClassName :: Length -> Text
toClassName (PxRem PxRem
p) = PxRem -> Text
forall a. ToClassName a => a -> Text
toClassName PxRem
p
  toClassName (Pct Float
p) = Float -> Text
forall a. ToClassName a => a -> Text
toClassName Float
p


newtype PxRem = PxRem' Int
  deriving newtype (Int -> PxRem -> ShowS
[PxRem] -> ShowS
PxRem -> String
(Int -> PxRem -> ShowS)
-> (PxRem -> String) -> ([PxRem] -> ShowS) -> Show PxRem
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PxRem -> ShowS
showsPrec :: Int -> PxRem -> ShowS
$cshow :: PxRem -> String
show :: PxRem -> String
$cshowList :: [PxRem] -> ShowS
showList :: [PxRem] -> ShowS
Show, PxRem -> Text
(PxRem -> Text) -> ToClassName PxRem
forall a. (a -> Text) -> ToClassName a
$ctoClassName :: PxRem -> Text
toClassName :: PxRem -> Text
ToClassName, Integer -> PxRem
PxRem -> PxRem
PxRem -> PxRem -> PxRem
(PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem)
-> (PxRem -> PxRem)
-> (PxRem -> PxRem)
-> (Integer -> PxRem)
-> Num PxRem
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
$c+ :: PxRem -> PxRem -> PxRem
+ :: PxRem -> PxRem -> PxRem
$c- :: PxRem -> PxRem -> PxRem
- :: PxRem -> PxRem -> PxRem
$c* :: PxRem -> PxRem -> PxRem
* :: PxRem -> PxRem -> PxRem
$cnegate :: PxRem -> PxRem
negate :: PxRem -> PxRem
$cabs :: PxRem -> PxRem
abs :: PxRem -> PxRem
$csignum :: PxRem -> PxRem
signum :: PxRem -> PxRem
$cfromInteger :: Integer -> PxRem
fromInteger :: Integer -> PxRem
Num, PxRem -> PxRem -> Bool
(PxRem -> PxRem -> Bool) -> (PxRem -> PxRem -> Bool) -> Eq PxRem
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PxRem -> PxRem -> Bool
== :: PxRem -> PxRem -> Bool
$c/= :: PxRem -> PxRem -> Bool
/= :: PxRem -> PxRem -> Bool
Eq, Enum PxRem
Real PxRem
(Real PxRem, Enum PxRem) =>
(PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> (PxRem, PxRem))
-> (PxRem -> PxRem -> (PxRem, PxRem))
-> (PxRem -> Integer)
-> Integral PxRem
PxRem -> Integer
PxRem -> PxRem -> (PxRem, PxRem)
PxRem -> PxRem -> PxRem
forall a.
(Real a, Enum a) =>
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
$cquot :: PxRem -> PxRem -> PxRem
quot :: PxRem -> PxRem -> PxRem
$crem :: PxRem -> PxRem -> PxRem
rem :: PxRem -> PxRem -> PxRem
$cdiv :: PxRem -> PxRem -> PxRem
div :: PxRem -> PxRem -> PxRem
$cmod :: PxRem -> PxRem -> PxRem
mod :: PxRem -> PxRem -> PxRem
$cquotRem :: PxRem -> PxRem -> (PxRem, PxRem)
quotRem :: PxRem -> PxRem -> (PxRem, PxRem)
$cdivMod :: PxRem -> PxRem -> (PxRem, PxRem)
divMod :: PxRem -> PxRem -> (PxRem, PxRem)
$ctoInteger :: PxRem -> Integer
toInteger :: PxRem -> Integer
Integral, Num PxRem
Ord PxRem
(Num PxRem, Ord PxRem) => (PxRem -> Rational) -> Real PxRem
PxRem -> Rational
forall a. (Num a, Ord a) => (a -> Rational) -> Real a
$ctoRational :: PxRem -> Rational
toRational :: PxRem -> Rational
Real, Eq PxRem
Eq PxRem =>
(PxRem -> PxRem -> Ordering)
-> (PxRem -> PxRem -> Bool)
-> (PxRem -> PxRem -> Bool)
-> (PxRem -> PxRem -> Bool)
-> (PxRem -> PxRem -> Bool)
-> (PxRem -> PxRem -> PxRem)
-> (PxRem -> PxRem -> PxRem)
-> Ord PxRem
PxRem -> PxRem -> Bool
PxRem -> PxRem -> Ordering
PxRem -> PxRem -> PxRem
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: PxRem -> PxRem -> Ordering
compare :: PxRem -> PxRem -> Ordering
$c< :: PxRem -> PxRem -> Bool
< :: PxRem -> PxRem -> Bool
$c<= :: PxRem -> PxRem -> Bool
<= :: PxRem -> PxRem -> Bool
$c> :: PxRem -> PxRem -> Bool
> :: PxRem -> PxRem -> Bool
$c>= :: PxRem -> PxRem -> Bool
>= :: PxRem -> PxRem -> Bool
$cmax :: PxRem -> PxRem -> PxRem
max :: PxRem -> PxRem -> PxRem
$cmin :: PxRem -> PxRem -> PxRem
min :: PxRem -> PxRem -> PxRem
Ord, Int -> PxRem
PxRem -> Int
PxRem -> [PxRem]
PxRem -> PxRem
PxRem -> PxRem -> [PxRem]
PxRem -> PxRem -> PxRem -> [PxRem]
(PxRem -> PxRem)
-> (PxRem -> PxRem)
-> (Int -> PxRem)
-> (PxRem -> Int)
-> (PxRem -> [PxRem])
-> (PxRem -> PxRem -> [PxRem])
-> (PxRem -> PxRem -> [PxRem])
-> (PxRem -> PxRem -> PxRem -> [PxRem])
-> Enum PxRem
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: PxRem -> PxRem
succ :: PxRem -> PxRem
$cpred :: PxRem -> PxRem
pred :: PxRem -> PxRem
$ctoEnum :: Int -> PxRem
toEnum :: Int -> PxRem
$cfromEnum :: PxRem -> Int
fromEnum :: PxRem -> Int
$cenumFrom :: PxRem -> [PxRem]
enumFrom :: PxRem -> [PxRem]
$cenumFromThen :: PxRem -> PxRem -> [PxRem]
enumFromThen :: PxRem -> PxRem -> [PxRem]
$cenumFromTo :: PxRem -> PxRem -> [PxRem]
enumFromTo :: PxRem -> PxRem -> [PxRem]
$cenumFromThenTo :: PxRem -> PxRem -> PxRem -> [PxRem]
enumFromThenTo :: PxRem -> PxRem -> PxRem -> [PxRem]
Enum)


instance Num Length where
  -- only support numeric literals
  Length
a + :: Length -> Length -> Length
+ Length
_ = Length
a
  Length
a * :: Length -> Length -> Length
* Length
_ = Length
a
  abs :: Length -> Length
abs (PxRem PxRem
a) = PxRem -> Length
PxRem (PxRem -> PxRem
forall a. Num a => a -> a
abs PxRem
a)
  abs (Pct Float
a) = Float -> Length
Pct (Float -> Float
forall a. Num a => a -> a
abs Float
a)
  signum :: Length -> Length
signum (PxRem PxRem
a) = PxRem -> Length
PxRem (PxRem -> PxRem
forall a. Num a => a -> a
signum PxRem
a)
  signum (Pct Float
a) = Float -> Length
Pct (Float -> Float
forall a. Num a => a -> a
signum Float
a)
  negate :: Length -> Length
negate (PxRem PxRem
a) = PxRem -> Length
PxRem (PxRem -> PxRem
forall a. Num a => a -> a
negate PxRem
a)
  negate (Pct Float
a) = Float -> Length
Pct (Float -> Float
forall a. Num a => a -> a
negate Float
a)
  fromInteger :: Integer -> Length
fromInteger Integer
n = PxRem -> Length
PxRem (Integer -> PxRem
forall a. Num a => Integer -> a
fromInteger Integer
n)


instance ToStyleValue PxRem where
  toStyleValue :: PxRem -> StyleValue
toStyleValue (PxRem' Int
0) = StyleValue
"0px"
  toStyleValue (PxRem' Int
1) = StyleValue
"1px"
  toStyleValue (PxRem' Int
n) = String -> StyleValue
StyleValue (String -> StyleValue) -> String -> StyleValue
forall a b. (a -> b) -> a -> b
$ Float -> String
forall a. Show a => a -> String
show ((Int -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n :: Float) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
16.0) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"rem"


instance ToStyleValue Length where
  toStyleValue :: Length -> StyleValue
toStyleValue (PxRem PxRem
p) = PxRem -> StyleValue
forall a. ToStyleValue a => a -> StyleValue
toStyleValue PxRem
p
  toStyleValue (Pct Float
n) = String -> StyleValue
StyleValue (String -> StyleValue) -> String -> StyleValue
forall a b. (a -> b) -> a -> b
$ Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) (Float
n Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
100) String
"" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"%"


-- | Milliseconds, used for transitions
newtype Ms = Ms Int
  deriving (Int -> Ms -> ShowS
[Ms] -> ShowS
Ms -> String
(Int -> Ms -> ShowS)
-> (Ms -> String) -> ([Ms] -> ShowS) -> Show Ms
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Ms -> ShowS
showsPrec :: Int -> Ms -> ShowS
$cshow :: Ms -> String
show :: Ms -> String
$cshowList :: [Ms] -> ShowS
showList :: [Ms] -> ShowS
Show)
  deriving newtype (Integer -> Ms
Ms -> Ms
Ms -> Ms -> Ms
(Ms -> Ms -> Ms)
-> (Ms -> Ms -> Ms)
-> (Ms -> Ms -> Ms)
-> (Ms -> Ms)
-> (Ms -> Ms)
-> (Ms -> Ms)
-> (Integer -> Ms)
-> Num Ms
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
$c+ :: Ms -> Ms -> Ms
+ :: Ms -> Ms -> Ms
$c- :: Ms -> Ms -> Ms
- :: Ms -> Ms -> Ms
$c* :: Ms -> Ms -> Ms
* :: Ms -> Ms -> Ms
$cnegate :: Ms -> Ms
negate :: Ms -> Ms
$cabs :: Ms -> Ms
abs :: Ms -> Ms
$csignum :: Ms -> Ms
signum :: Ms -> Ms
$cfromInteger :: Integer -> Ms
fromInteger :: Integer -> Ms
Num, Ms -> Text
(Ms -> Text) -> ToClassName Ms
forall a. (a -> Text) -> ToClassName a
$ctoClassName :: Ms -> Text
toClassName :: Ms -> Text
ToClassName)


instance ToStyleValue Ms where
  toStyleValue :: Ms -> StyleValue
toStyleValue (Ms Int
n) = String -> StyleValue
StyleValue (String -> StyleValue) -> String -> StyleValue
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show Int
n String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"ms"


-- | Media allows for responsive designs that change based on characteristics of the window. See [Layout Example](https://github.com/seanhess/web-view/blob/master/example/Example/Layout.hs)
data Media
  = MinWidth Int
  | MaxWidth Int
  deriving (Media -> Media -> Bool
(Media -> Media -> Bool) -> (Media -> Media -> Bool) -> Eq Media
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Media -> Media -> Bool
== :: Media -> Media -> Bool
$c/= :: Media -> Media -> Bool
/= :: Media -> Media -> Bool
Eq, Eq Media
Eq Media =>
(Media -> Media -> Ordering)
-> (Media -> Media -> Bool)
-> (Media -> Media -> Bool)
-> (Media -> Media -> Bool)
-> (Media -> Media -> Bool)
-> (Media -> Media -> Media)
-> (Media -> Media -> Media)
-> Ord Media
Media -> Media -> Bool
Media -> Media -> Ordering
Media -> Media -> Media
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Media -> Media -> Ordering
compare :: Media -> Media -> Ordering
$c< :: Media -> Media -> Bool
< :: Media -> Media -> Bool
$c<= :: Media -> Media -> Bool
<= :: Media -> Media -> Bool
$c> :: Media -> Media -> Bool
> :: Media -> Media -> Bool
$c>= :: Media -> Media -> Bool
>= :: Media -> Media -> Bool
$cmax :: Media -> Media -> Media
max :: Media -> Media -> Media
$cmin :: Media -> Media -> Media
min :: Media -> Media -> Media
Ord, Int -> Media -> ShowS
[Media] -> ShowS
Media -> String
(Int -> Media -> ShowS)
-> (Media -> String) -> ([Media] -> ShowS) -> Show Media
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Media -> ShowS
showsPrec :: Int -> Media -> ShowS
$cshow :: Media -> String
show :: Media -> String
$cshowList :: [Media] -> ShowS
showList :: [Media] -> ShowS
Show)


{- | Options for styles that support specifying various sides. This has a "fake" Num instance to support literals

> border 5
> border (X 2)
> border (TRBL 0 5 0 0)
-}
data Sides a
  = All a
  | TRBL a a a a
  | X a
  | Y a
  | XY a a


-- Num instance is just to support literals
instance (Num a) => Num (Sides a) where
  Sides a
a + :: Sides a -> Sides a -> Sides a
+ Sides a
_ = Sides a
a
  Sides a
a * :: Sides a -> Sides a -> Sides a
* Sides a
_ = Sides a
a
  abs :: Sides a -> Sides a
abs Sides a
a = Sides a
a
  negate :: Sides a -> Sides a
negate Sides a
a = Sides a
a
  signum :: Sides a -> Sides a
signum Sides a
a = Sides a
a
  fromInteger :: Integer -> Sides a
fromInteger Integer
n = a -> Sides a
forall a. a -> Sides a
All (Integer -> a
forall a. Num a => Integer -> a
fromInteger Integer
n)


-- | Element's attributes do not include class, which is separated. FlatAttributes generate the class attribute and include it
newtype FlatAttributes = FlatAttributes {FlatAttributes -> Map Text Text
attributes :: Map Name AttValue}
  deriving ((forall x. FlatAttributes -> Rep FlatAttributes x)
-> (forall x. Rep FlatAttributes x -> FlatAttributes)
-> Generic FlatAttributes
forall x. Rep FlatAttributes x -> FlatAttributes
forall x. FlatAttributes -> Rep FlatAttributes x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FlatAttributes -> Rep FlatAttributes x
from :: forall x. FlatAttributes -> Rep FlatAttributes x
$cto :: forall x. Rep FlatAttributes x -> FlatAttributes
to :: forall x. Rep FlatAttributes x -> FlatAttributes
Generic)


-- ** Colors


{- | ToColor allows you to create a type containing your application's colors:

> data AppColor
>   = White
>   | Primary
>   | Dark
>
> instance ToColor AppColor where
>   colorValue White = "#FFF"
>   colorValue Dark = "#333"
>   colorValue Primary = "#00F"
>
> hello :: View c ()
> hello = el (bg Primary . color White) "Hello"
-}
class ToColor a where
  colorValue :: a -> HexColor
  colorName :: a -> Text
  default colorName :: (Show a) => a -> Text
  colorName = Text -> Text
T.toLower (Text -> Text) -> (a -> Text) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show


instance ToColor HexColor where
  colorValue :: HexColor -> HexColor
colorValue HexColor
c = HexColor
c
  colorName :: HexColor -> Text
colorName (HexColor Text
a) = (Char -> Bool) -> Text -> Text
T.dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'#') Text
a


-- | Hexidecimal Color. Can be specified with or without the leading '#'. Recommended to use an AppColor type instead of manually using hex colors. See 'Web.View.Types.ToColor'
newtype HexColor = HexColor Text


instance ToStyleValue HexColor where
  toStyleValue :: HexColor -> StyleValue
toStyleValue (HexColor Text
s) = String -> StyleValue
StyleValue (String -> StyleValue) -> String -> StyleValue
forall a b. (a -> b) -> a -> b
$ String
"#" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
unpack ((Char -> Bool) -> Text -> Text
T.dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'#') Text
s)


instance IsString HexColor where
  fromString :: String -> HexColor
fromString = Text -> HexColor
HexColor (Text -> HexColor) -> (String -> Text) -> String -> HexColor
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> Text
T.dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'#') (Text -> Text) -> (String -> Text) -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack


data Align
  = Center
  deriving (Int -> Align -> ShowS
[Align] -> ShowS
Align -> String
(Int -> Align -> ShowS)
-> (Align -> String) -> ([Align] -> ShowS) -> Show Align
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Align -> ShowS
showsPrec :: Int -> Align -> ShowS
$cshow :: Align -> String
show :: Align -> String
$cshowList :: [Align] -> ShowS
showList :: [Align] -> ShowS
Show, Align -> Text
(Align -> Text) -> ToClassName Align
forall a. (a -> Text) -> ToClassName a
$ctoClassName :: Align -> Text
toClassName :: Align -> Text
ToClassName, Align -> StyleValue
(Align -> StyleValue) -> ToStyleValue Align
forall a. (a -> StyleValue) -> ToStyleValue a
$ctoStyleValue :: Align -> StyleValue
toStyleValue :: Align -> StyleValue
ToStyleValue)