content: {-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-}
  module Clay.Box
  ( BoxType
  , paddingBox, borderBox, contentBox
  , boxSizing
  -- * @box-shadow@
  -- $box-shadow
  , boxShadow
  , shadow
  , shadowWithBlur
  , shadowWithSpread
  , bsInset
  , bsColor
  -- ** Deprecated
  -- $box-shadow-deprecated
  , boxShadow'
  , boxShadowWithSpread
  , boxShadows
  , insetBoxShadow
  )
  where
  
  import Data.List.NonEmpty (NonEmpty)
  
  import Clay.Color
  import Clay.Common
  import Clay.Property
  import Clay.Stylesheet
  import Clay.Size
  import Clay.Border
  
  -------------------------------------------------------------------------------
  
  newtype BoxType = BoxType Value
    deriving (Val, Inherit)
  
  paddingBox, borderBox, contentBox :: BoxType
  
  paddingBox = BoxType "padding-box"
  borderBox  = BoxType "border-box"
  contentBox = BoxType "content-box"
  
  -------------------------------------------------------------------------------
  
  boxSizing :: BoxType -> Css
  boxSizing = prefixed (browsers <> "box-sizing")
  
  -------------------------------------------------------------------------------
  
  -- $box-shadow
  --
  -- === Formal argument syntax
  --
  -- > none | <shadow>#
  -- > where 
  -- > <shadow> = inset? && <length>{2,4} && <color>?
  -- > 
  -- > where 
  -- > <color> = <rgb()> | <rgba()> | <hsl()> | <hsla()> | <hex-color> | <named-color> | currentcolor | <deprecated-system-color>
  -- > 
  -- > where 
  -- > <rgb()> = rgb( [ [ <percentage>{3} | <number>{3} ] [ / <alpha-value> ]? ] | [ [ <percentage>#{3} | <number>#{3} ] , <alpha-value>? ] )
  -- > <rgba()> = rgba( [ [ <percentage>{3} | <number>{3} ] [ / <alpha-value> ]? ] | [ [ <percentage>#{3} | <number>#{3} ] , <alpha-value>? ] )
  -- > <hsl()> = hsl( [ <hue> <percentage> <percentage> [ / <alpha-value> ]? ] | [ <hue>, <percentage>, <percentage>, <alpha-value>? ] )
  -- > <hsla()> = hsla( [ <hue> <percentage> <percentage> [ / <alpha-value> ]? ] | [ <hue>, <percentage>, <percentage>, <alpha-value>? ] )
  -- > 
  -- > where 
  -- > <alpha-value> = <number> | <percentage>
  -- > <hue> = <number> | <angle>
  
  newtype BoxShadow = BoxShadow Value
    deriving (Val, Inherit, Initial, Unset, None, Other)
  
  -- | This function will usually take a singleton list, but requiring a (non-empty)
  -- list prevents accidentally applying the modifiers ('bsInset', 'bsColor')
  -- incorrectly.
  --
  -- 'pure' (from "Control.Applicative") creates a singleton list.
  --
  -- > boxShadow . pure $ none
  -- > boxShadow . pure $ shadow (px 1) (px 1)
  --
  -- Use with @{-# LANGUAGE OverloadedLists #-}@ for the simplest list syntax.
  -- Note that sometimes when @{-# LANGUAGE OverloadedLists #-}@ is active, GHC
  -- has troubles identifying what type the list should be converted to. Examples:
  -- 1) "forM_ [0..10] $ \x -> ..."
  -- 2) "[left, top, right, bottom] `forM_` ($ pct 4)"
  --
  -- > boxShadow [none]
  -- > boxShadow [shadow (px 1) (px 1)]
  --
  -- This is recommended for supplying multiple 'BoxShadow' values.
  --
  -- > boxShadow [shadowWithBlur (em 2) (em 1), bsInset . bsColor red $ shadow (px 1) (px 2)]
  boxShadow :: NonEmpty BoxShadow -> Css
  boxShadow = prefixed (browsers <> "box-shadow") . value
  
  shadow
    :: Size a -- ^ Horizontal offset
    -> Size a -- ^ Vertical offset
    -> BoxShadow
  shadow x y = BoxShadow . value $ (x ! y)
  
  shadowWithBlur
    :: Size a -- ^ Horizontal offset
    -> Size a -- ^ Vertical offset
    -> Size a -- ^ Blur radius
    -> BoxShadow
  shadowWithBlur x y w = BoxShadow . value $ (x ! y ! w)
  
  -- | While this function is the correct type to work with the 'sym', 'sym2'
  -- or 'sym3' functions, such applications are unlikely to be meaningful.
  shadowWithSpread
    :: Size a -- ^ Horizontal offset
    -> Size a -- ^ Vertical offset
    -> Size a -- ^ Blur radius
    -> Size a -- ^ Spread radius
    -> BoxShadow
  shadowWithSpread x y blurRadius spreadRadius =
      BoxShadow . value $ (x ! y ! blurRadius ! spreadRadius)
  
  -- | Adapt the provided @box-shadow@ with the @inset@ prefix.
  -- 
  -- > boxShadow . pure . bsInset
  bsInset :: BoxShadow -> BoxShadow
  bsInset (BoxShadow v) = BoxShadow . value $ ("inset" :: Value, v)
  
  -- | Supply a color to the provided @box-shadow@.
  bsColor :: Color -> BoxShadow -> BoxShadow
  bsColor c (BoxShadow v) = BoxShadow . value $ (v, c)
  infixr 9 `bsColor`
  
  -------------------------------------------------------------------------------
  
  -- $box-shadow-deprecated
  --
  -- The old implementation was both restrictive and slightly off-spec. It
  -- shall be discontinued in a future release. The 'boxShadow' name has already
  -- been taken, so the functionality that used to provide is now provided by
  -- 'boxShadow\''.
  
  -- | This is the drop-in replacement for the old 'boxShadow' function (< 0.13).
  -- It is possible to continue for now
  boxShadow' :: Size a -> Size a -> Size a -> Color -> Css
  boxShadow' x y w c = prefixed (browsers <> "box-shadow") (x ! y ! w ! c)
  {-# DEPRECATED boxShadow' "This function is only present for compatibility purposes and will be removed." #-}
  
  -- | Replace calls to this function as follows (using -XOverloadedLists)
  --
  -- > boxShadowWithSpread x y rb rs c
  --
  -- > boxShadow [c `bsColor` shadowWithSpread x y rb rs]
  boxShadowWithSpread :: Size a -> Size a -> Size a -> Size a -> Color -> Css
  boxShadowWithSpread x y blurRadius spreadRadius color =
      prefixed (browsers <> "box-shadow") (x ! y ! blurRadius ! spreadRadius ! color)
  {-# DEPRECATED boxShadowWithSpread "This function has been replaced with shadowWithSpread and bsColor and will be removed." #-}
  
  -- | Replace calls to this function as follows (using -XOverloadedLists)
  --
  -- > boxShadows [(x1, y1, rb1, c1), (x2, y2, rb2, c2)]
  --
  -- > boxShadow
  -- >   [ c1 `bsColor` shadowWithBlur x1 y1 rb1
  -- >   , c2 `bsColor` shadowWithBlur x2 y2 rb2
  -- >   ]
  boxShadows :: [(Size a, Size a, Size a, Color)] -> Css
  boxShadows = prefixed (browsers <> "box-shadow") . map (\(a, b, c, d) -> a ! b ! c ! d)
  {-# DEPRECATED boxShadows "This function is replaced with boxShadow and will be removed." #-}
  
  -- | Replace calls to this function as follows (using -XOverloadedLists)
  --
  -- > insetBoxShadow s x y rb c
  --
  -- > boxShadow [bsInset $ c `bsColor` shadowWithBlur x y rb]
  insetBoxShadow :: Stroke -> Size a -> Size a -> Size a -> Color -> Css
  insetBoxShadow x y w c z = prefixed (browsers <> "box-shadow") (x ! y ! w ! c ! z)
  {-# DEPRECATED insetBoxShadow "This function has been replaced with shadowWithSpread, bsInset and bsColor and will be removed." #-}
  