{-# 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 (BoxType -> Value
(BoxType -> Value) -> Val BoxType
forall a. (a -> Value) -> Val a
value :: BoxType -> Value
$cvalue :: BoxType -> Value
Val, BoxType
BoxType -> Inherit BoxType
forall a. a -> Inherit a
inherit :: BoxType
$cinherit :: BoxType
Inherit)

paddingBox, borderBox, contentBox :: BoxType

paddingBox :: BoxType
paddingBox = Value -> BoxType
BoxType Value
"padding-box"
borderBox :: BoxType
borderBox  = Value -> BoxType
BoxType Value
"border-box"
contentBox :: BoxType
contentBox = Value -> BoxType
BoxType Value
"content-box"

-------------------------------------------------------------------------------

boxSizing :: BoxType -> Css
boxSizing :: BoxType -> Css
boxSizing = Prefixed -> BoxType -> Css
forall a. Val a => Prefixed -> a -> Css
prefixed (Prefixed
browsers Prefixed -> Prefixed -> Prefixed
forall a. Semigroup a => a -> a -> a
<> Prefixed
"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 (BoxShadow -> Value
(BoxShadow -> Value) -> Val BoxShadow
forall a. (a -> Value) -> Val a
value :: BoxShadow -> Value
$cvalue :: BoxShadow -> Value
Val, BoxShadow
BoxShadow -> Inherit BoxShadow
forall a. a -> Inherit a
inherit :: BoxShadow
$cinherit :: BoxShadow
Inherit, BoxShadow
BoxShadow -> Initial BoxShadow
forall a. a -> Initial a
initial :: BoxShadow
$cinitial :: BoxShadow
Initial, BoxShadow
BoxShadow -> Unset BoxShadow
forall a. a -> Unset a
unset :: BoxShadow
$cunset :: BoxShadow
Unset, BoxShadow
BoxShadow -> None BoxShadow
forall a. a -> None a
none :: BoxShadow
$cnone :: BoxShadow
None, Value -> BoxShadow
(Value -> BoxShadow) -> Other BoxShadow
forall a. (Value -> a) -> Other a
other :: Value -> BoxShadow
$cother :: Value -> BoxShadow
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 :: NonEmpty BoxShadow -> Css
boxShadow = Prefixed -> Value -> Css
forall a. Val a => Prefixed -> a -> Css
prefixed (Prefixed
browsers Prefixed -> Prefixed -> Prefixed
forall a. Semigroup a => a -> a -> a
<> Prefixed
"box-shadow") (Value -> Css)
-> (NonEmpty BoxShadow -> Value) -> NonEmpty BoxShadow -> Css
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty BoxShadow -> Value
forall a. Val a => a -> Value
value

shadow
  :: Size a -- ^ Horizontal offset
  -> Size a -- ^ Vertical offset
  -> BoxShadow
shadow :: Size a -> Size a -> BoxShadow
shadow Size a
x Size a
y = Value -> BoxShadow
BoxShadow (Value -> BoxShadow)
-> ((Size a, Size a) -> Value) -> (Size a, Size a) -> BoxShadow
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Size a, Size a) -> Value
forall a. Val a => a -> Value
value ((Size a, Size a) -> BoxShadow) -> (Size a, Size a) -> BoxShadow
forall a b. (a -> b) -> a -> b
$ (Size a
x Size a -> Size a -> (Size a, Size a)
forall a b. a -> b -> (a, b)
! Size a
y)

shadowWithBlur
  :: Size a -- ^ Horizontal offset
  -> Size a -- ^ Vertical offset
  -> Size a -- ^ Blur radius
  -> BoxShadow
shadowWithBlur :: Size a -> Size a -> Size a -> BoxShadow
shadowWithBlur Size a
x Size a
y Size a
w = Value -> BoxShadow
BoxShadow (Value -> BoxShadow)
-> ((Size a, (Size a, Size a)) -> Value)
-> (Size a, (Size a, Size a))
-> BoxShadow
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Size a, (Size a, Size a)) -> Value
forall a. Val a => a -> Value
value ((Size a, (Size a, Size a)) -> BoxShadow)
-> (Size a, (Size a, Size a)) -> BoxShadow
forall a b. (a -> b) -> a -> b
$ (Size a
x Size a -> (Size a, Size a) -> (Size a, (Size a, Size a))
forall a b. a -> b -> (a, b)
! Size a
y Size a -> Size a -> (Size a, Size a)
forall a b. a -> b -> (a, b)
! Size a
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 :: Size a -> Size a -> Size a -> Size a -> BoxShadow
shadowWithSpread Size a
x Size a
y Size a
blurRadius Size a
spreadRadius =
    Value -> BoxShadow
BoxShadow (Value -> BoxShadow)
-> ((Size a, (Size a, (Size a, Size a))) -> Value)
-> (Size a, (Size a, (Size a, Size a)))
-> BoxShadow
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Size a, (Size a, (Size a, Size a))) -> Value
forall a. Val a => a -> Value
value ((Size a, (Size a, (Size a, Size a))) -> BoxShadow)
-> (Size a, (Size a, (Size a, Size a))) -> BoxShadow
forall a b. (a -> b) -> a -> b
$ (Size a
x Size a
-> (Size a, (Size a, Size a))
-> (Size a, (Size a, (Size a, Size a)))
forall a b. a -> b -> (a, b)
! Size a
y Size a -> (Size a, Size a) -> (Size a, (Size a, Size a))
forall a b. a -> b -> (a, b)
! Size a
blurRadius Size a -> Size a -> (Size a, Size a)
forall a b. a -> b -> (a, b)
! Size a
spreadRadius)

-- | Adapt the provided @box-shadow@ with the @inset@ prefix.
-- 
-- > boxShadow . pure . bsInset
bsInset :: BoxShadow -> BoxShadow
bsInset :: BoxShadow -> BoxShadow
bsInset (BoxShadow Value
v) = Value -> BoxShadow
BoxShadow (Value -> BoxShadow)
-> ((Value, Value) -> Value) -> (Value, Value) -> BoxShadow
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value, Value) -> Value
forall a. Val a => a -> Value
value ((Value, Value) -> BoxShadow) -> (Value, Value) -> BoxShadow
forall a b. (a -> b) -> a -> b
$ (Value
"inset" :: Value, Value
v)

-- | Supply a color to the provided @box-shadow@.
bsColor :: Color -> BoxShadow -> BoxShadow
bsColor :: Color -> BoxShadow -> BoxShadow
bsColor Color
c (BoxShadow Value
v) = Value -> BoxShadow
BoxShadow (Value -> BoxShadow)
-> ((Value, Color) -> Value) -> (Value, Color) -> BoxShadow
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value, Color) -> Value
forall a. Val a => a -> Value
value ((Value, Color) -> BoxShadow) -> (Value, Color) -> BoxShadow
forall a b. (a -> b) -> a -> b
$ (Value
v, Color
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' :: Size a -> Size a -> Size a -> Color -> Css
boxShadow' Size a
x Size a
y Size a
w Color
c = Prefixed -> (Size a, (Size a, (Size a, Color))) -> Css
forall a. Val a => Prefixed -> a -> Css
prefixed (Prefixed
browsers Prefixed -> Prefixed -> Prefixed
forall a. Semigroup a => a -> a -> a
<> Prefixed
"box-shadow") (Size a
x Size a
-> (Size a, (Size a, Color)) -> (Size a, (Size a, (Size a, Color)))
forall a b. a -> b -> (a, b)
! Size a
y Size a -> (Size a, Color) -> (Size a, (Size a, Color))
forall a b. a -> b -> (a, b)
! Size a
w Size a -> Color -> (Size a, Color)
forall a b. a -> b -> (a, b)
! Color
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 :: Size a -> Size a -> Size a -> Size a -> Color -> Css
boxShadowWithSpread Size a
x Size a
y Size a
blurRadius Size a
spreadRadius Color
color =
    Prefixed -> (Size a, (Size a, (Size a, (Size a, Color)))) -> Css
forall a. Val a => Prefixed -> a -> Css
prefixed (Prefixed
browsers Prefixed -> Prefixed -> Prefixed
forall a. Semigroup a => a -> a -> a
<> Prefixed
"box-shadow") (Size a
x Size a
-> (Size a, (Size a, (Size a, Color)))
-> (Size a, (Size a, (Size a, (Size a, Color))))
forall a b. a -> b -> (a, b)
! Size a
y Size a
-> (Size a, (Size a, Color)) -> (Size a, (Size a, (Size a, Color)))
forall a b. a -> b -> (a, b)
! Size a
blurRadius Size a -> (Size a, Color) -> (Size a, (Size a, Color))
forall a b. a -> b -> (a, b)
! Size a
spreadRadius Size a -> Color -> (Size a, Color)
forall a b. a -> b -> (a, b)
! Color
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 :: [(Size a, Size a, Size a, Color)] -> Css
boxShadows = Prefixed -> [(Size a, (Size a, (Size a, Color)))] -> Css
forall a. Val a => Prefixed -> a -> Css
prefixed (Prefixed
browsers Prefixed -> Prefixed -> Prefixed
forall a. Semigroup a => a -> a -> a
<> Prefixed
"box-shadow") ([(Size a, (Size a, (Size a, Color)))] -> Css)
-> ([(Size a, Size a, Size a, Color)]
    -> [(Size a, (Size a, (Size a, Color)))])
-> [(Size a, Size a, Size a, Color)]
-> Css
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Size a, Size a, Size a, Color)
 -> (Size a, (Size a, (Size a, Color))))
-> [(Size a, Size a, Size a, Color)]
-> [(Size a, (Size a, (Size a, Color)))]
forall a b. (a -> b) -> [a] -> [b]
map (\(Size a
a, Size a
b, Size a
c, Color
d) -> Size a
a Size a
-> (Size a, (Size a, Color)) -> (Size a, (Size a, (Size a, Color)))
forall a b. a -> b -> (a, b)
! Size a
b Size a -> (Size a, Color) -> (Size a, (Size a, Color))
forall a b. a -> b -> (a, b)
! Size a
c Size a -> Color -> (Size a, Color)
forall a b. a -> b -> (a, b)
! Color
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 :: Stroke -> Size a -> Size a -> Size a -> Color -> Css
insetBoxShadow Stroke
x Size a
y Size a
w Size a
c Color
z = Prefixed -> (Stroke, (Size a, (Size a, (Size a, Color)))) -> Css
forall a. Val a => Prefixed -> a -> Css
prefixed (Prefixed
browsers Prefixed -> Prefixed -> Prefixed
forall a. Semigroup a => a -> a -> a
<> Prefixed
"box-shadow") (Stroke
x Stroke
-> (Size a, (Size a, (Size a, Color)))
-> (Stroke, (Size a, (Size a, (Size a, Color))))
forall a b. a -> b -> (a, b)
! Size a
y Size a
-> (Size a, (Size a, Color)) -> (Size a, (Size a, (Size a, Color)))
forall a b. a -> b -> (a, b)
! Size a
w Size a -> (Size a, Color) -> (Size a, (Size a, Color))
forall a b. a -> b -> (a, b)
! Size a
c Size a -> Color -> (Size a, Color)
forall a b. a -> b -> (a, b)
! Color
z)
{-# DEPRECATED insetBoxShadow "This function has been replaced with shadowWithSpread, bsInset and bsColor and will be removed." #-}