content: {-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-}
  module Clay.Text
  (
  -- * Letter and word-spacing.
  
    letterSpacing
  , wordSpacing
  
  -- * Text-rendering.
  
  , TextRendering
  , textRendering
  , optimizeSpeed, optimizeLegibility, geometricPrecision
  
  -- * Text-shadow.
  
  , textShadow
  
  -- * Text-indent.
  -- $text-indent
  
  , TextIndent
  , textIndent
  , eachLine, hanging
  , indent
  
  -- * Text-direction.
  
  , TextDirection
  , direction
  , ltr
  , rtl
  
  -- * Text-align.
  
  , TextAlign
  , textAlign
  , textAlignLast
  , justify, matchParent, start, end
  , alignSide
  , alignString
  
  -- * White-space.
  
  , WhiteSpace
  , whiteSpace
  , pre, nowrap, preWrap, preLine
  
  -- * Text-decoration.
  
  , TextDecoration
  , textDecoration
  , textDecorationStyle
  , textDecorationLine
  , textDecorationColor
  , underline, overline, lineThrough, blink
  
  -- * Text-transform.
  
  , TextTransform
  , textTransform
  , capitalize, uppercase, lowercase, fullWidth
  
  -- * Text-overflow.
  
  , TextOverflow
  , textOverflow
  , overflowClip, overflowEllipsis
  
  -- * Word-break.
  
  , WordBreak
  , wordBreak
  , breakAll
  , keepAll
  
  -- * Overflow-wrap (and Word-wrap).
  
  , OverflowWrap
  , overflowWrap
  , wordWrap
  , breakWord
  
  -- * Hyphenation.
  
  , hyphens
  , hyphenateCharacter
  , hyphenateLimitChars
  , manual
  , Hyphens
  , HyphenateCharacter
  , HyphenateLimit
  
  -- * Content.
  
  , Content
  , content
  , contents
  , attrContent
  , stringContent
  , uriContent
  , urlContent
  , openQuote, closeQuote, noOpenQuote, noCloseQuote
  
  )
  where
  
  import Data.String
  import Data.Text (Text, pack)
  
  import Clay.Background
  import Clay.Border
  import Clay.Color
  import Clay.Common
  import Clay.Property
  import Clay.Stylesheet
  import Clay.Size
  
  -------------------------------------------------------------------------------
  
  letterSpacing :: Size a -> Css
  letterSpacing = key "letter-spacing"
  
  wordSpacing :: Size a -> Css
  wordSpacing = key "word-spacing"
  
  -------------------------------------------------------------------------------
  
  newtype TextRendering = TextRendering Value
    deriving (Val, Auto, Inherit, Other)
  
  optimizeSpeed, optimizeLegibility, geometricPrecision :: TextRendering
  
  optimizeSpeed      = TextRendering "optimizeSpeed"
  optimizeLegibility = TextRendering "optimizeLegibility"
  geometricPrecision = TextRendering "geometricPrecision"
  
  textRendering :: TextRendering -> Css
  textRendering = key "text-rendering"
  
  -------------------------------------------------------------------------------
  
  textShadow :: Size a -> Size a -> Size a -> Color -> Css
  textShadow x y w c = key "text-shadow" (x ! y ! w ! c)
  
  -------------------------------------------------------------------------------
  
  -- $text-indent
  --
  -- Supply a length — optionally annotated with @each-line@ or @hanging@ or
  -- both, or a global value. It is possible to apply the same annotation
  -- multiple times, but it has no defined effect.
  --
  -- Note browser support is currently (March 2018) non-existent, but the
  -- Prince typesetting system supports the syntax.
  --
  -- === Formal argument syntax
  --
  -- > <length-percentage> && hanging? && each-line?
  -- > where
  -- > <length-percentage> = <length> | <percentage>
  
  newtype TextIndent = TextIndent Value
    deriving (Val, Inherit, Initial, Unset, Other)
  
  -- | An internal function that ensures each-line and hanging are processed
  -- correctly.
  tagTextIndent :: Value -> TextIndent -> TextIndent
  tagTextIndent v (TextIndent v0) = TextIndent . value $ (v0, v)
  
  -- | Annotate the supplied 'TextIndent' with @each-line@ or @hanging@ or
  -- both.
  --
  -- > eachLine . hanging . indent $ px 3 :: TextIndent
  eachLine, hanging :: TextIndent -> TextIndent
  
  eachLine = tagTextIndent "each-line"
  hanging  = tagTextIndent "hanging"
  
  indent :: Size a -> TextIndent
  indent = TextIndent . value
  
  textIndent :: TextIndent -> Css
  textIndent = key "text-indent"
  
  -------------------------------------------------------------------------------
  
  newtype TextDirection = TextDirection Value
    deriving (Val, Normal, Inherit, Other)
  
  ltr :: TextDirection
  ltr = TextDirection "ltr"
  
  rtl :: TextDirection
  rtl = TextDirection "rtl"
  
  direction :: TextDirection -> Css
  direction = key "direction"
  
  -------------------------------------------------------------------------------
  
  newtype TextAlign = TextAlign Value
    deriving (Val, Normal, Inherit, Other, Center)
  
  justify, matchParent, start, end :: TextAlign
  
  justify     = TextAlign "justify"
  matchParent = TextAlign "match-parent"
  start       = TextAlign "start"
  end         = TextAlign "end"
  
  alignSide :: Side -> TextAlign
  alignSide = TextAlign . value
  
  alignString :: Char -> TextAlign
  alignString = TextAlign . value . Literal . fromString . return
  
  textAlign :: TextAlign -> Css
  textAlign = key "text-align"
  
  textAlignLast :: TextAlign -> Css
  textAlignLast = key "text-align-last"
  
  -------------------------------------------------------------------------------
  
  newtype WhiteSpace = WhiteSpace Value
    deriving (Val, Normal, Inherit, Other)
  
  whiteSpace :: WhiteSpace -> Css
  whiteSpace = key "white-space"
  
  pre, nowrap, preWrap, preLine :: WhiteSpace
  
  pre     = WhiteSpace "pre"
  nowrap  = WhiteSpace "nowrap"
  preWrap = WhiteSpace "pre-wrap"
  preLine = WhiteSpace "pre-line"
  
  -------------------------------------------------------------------------------
  
  newtype TextDecoration = TextDecoration Value
    deriving (Val, None, Inherit, Other)
  
  underline, overline, lineThrough, blink :: TextDecoration
  
  underline   = TextDecoration "underline"
  overline    = TextDecoration "overline"
  lineThrough = TextDecoration "line-through"
  blink       = TextDecoration "blink"
  
  textDecorationLine :: TextDecoration -> Css
  textDecorationLine = key "text-decoration-line"
  
  textDecorationColor :: Color -> Css
  textDecorationColor = key "text-decoration-color"
  
  textDecoration :: TextDecoration -> Css
  textDecoration = key "text-decoration"
  
  textDecorationStyle :: Stroke -> Css
  textDecorationStyle = key "text-decoration-style"
  
  -------------------------------------------------------------------------------
  
  newtype TextTransform = TextTransform Value
    deriving (Val, None, Inherit)
  
  capitalize, uppercase, lowercase, fullWidth :: TextTransform
  
  capitalize = TextTransform "capitalize"
  uppercase  = TextTransform "uppercase"
  lowercase  = TextTransform "lowercase"
  fullWidth  = TextTransform "full-width"
  
  textTransform :: TextTransform -> Css
  textTransform = key "text-transform"
  
  -------------------------------------------------------------------------------
  
  newtype WordBreak = WordBreak Value
    deriving (Val, Inherit, Initial, Unset, Normal)
  
  breakAll, keepAll :: WordBreak
  
  breakAll = WordBreak "break-all"
  keepAll  = WordBreak "keep-all"
  
  wordBreak :: WordBreak -> Css
  
  wordBreak = key "word-break"
  
  -------------------------------------------------------------------------------
  
  newtype OverflowWrap = OverflowWrap Value
    deriving (Val, Inherit, Initial, Unset, Normal)
  
  breakWord :: OverflowWrap
  
  breakWord = OverflowWrap "break-word"
  
  overflowWrap, wordWrap :: OverflowWrap -> Css
  
  wordWrap     = key "word-wrap"
  overflowWrap = key "overflow-wrap"
  
  -------------------------------------------------------------------------------
  
  newtype TextOverflow = TextOverflow Value
    deriving (Val, None, Inherit, Initial)
  
  overflowClip, overflowEllipsis :: TextOverflow
  
  overflowClip = TextOverflow "clip"
  overflowEllipsis = TextOverflow "ellipsis"
  
  textOverflow :: TextOverflow -> Css
  textOverflow = key "text-overflow"
  
  -------------------------------------------------------------------------------
  
  -- | Type for values which can be provided to 'hyphens'.
  newtype Hyphens = Hyphens Value
    deriving (Val, None, Auto, Initial, Inherit, Unset, Other)
  
  -- | Specifies how words should be hyphenated.
  --
  -- Possible values are:
  --
  --  ['none']: No hyphenation.
  --  Words will not be hyphenated even if it is explicitly suggested for a word.
  --
  --  ['manual']: Manual hyphenation.
  --  Specific characters such as @&shy;@ in a word will suggest break points.
  --  This is the default.
  --
  --  ['auto']: Automatic hyphenation.
  --  The browser is free to hyphenate words as it sees fit.
  --  However, explicitly suggested break points will take precedence.
  --
  -- For example,
  --
  -- >>> hyphens auto
  --
  -- The hyphenation rules depend on the language,
  -- which must be specified by the @lang@ attribute.
  --
  -- For reference, see
  -- [@hyphens@](https://developer.mozilla.org/en-US/docs/Web/CSS/hyphens).
  hyphens :: Hyphens -> Css
  hyphens = key "hyphens"
  
  -- | Value for 'hyphens' specifying that hyphenation be manual.
  manual :: Hyphens
  manual = Hyphens "manual"
  -- 'manual' feels like it should be a function and type class in Clay.Common,
  -- but @hyphens@ is the only CSS property which uses it as a specified value.
  
  -- | Type for values which can be provided to 'hyphenateCharacter'.
  newtype HyphenateCharacter = HyphenateCharacter Value
    deriving (Val, Auto, Initial, Inherit, Unset, Other)
  
  -- Allow a 'HyphenateCharacter' value to be specified directly with a string.
  instance IsString HyphenateCharacter where
    fromString = HyphenateCharacter . Value . Plain . quote . pack
  
  -- | Customizes the character used for hyphenation.
  --
  -- For example,
  --
  -- >>> hyphenateCharacter "~"
  --
  -- For reference, see
  -- [@hyphenate-character@](https://developer.mozilla.org/en-US/docs/Web/CSS/hyphenate-character).
  hyphenateCharacter :: HyphenateCharacter -> Css
  hyphenateCharacter = key "hyphenate-character"
  
  -- | Type for values which can be provded to 'hyphenateLimitChars'.
  newtype HyphenateLimit = HyphenateLimit Value
    deriving (Val, Auto, Initial, Inherit, Unset, Other)
  
  -- Allow a 'HyphenateLimit' value to be specified directly with a number.
  instance Num HyphenateLimit where
    fromInteger = HyphenateLimit . value
    (+) = error "plus not implemented for HyphenateLimit"
    (*) = error "times not implemented for HyphenateLimit"
    abs = error "abs not implemented for HyphenateLimit"
    signum = error "signum not implemented for HyphenateLimit"
    negate = error "negate not implemented for HyphenateLimit"
  
  -- | Adjusts the minumum number of characters involved in hyphenation.
  --
  -- I.e., specifies the minumum number of characters allowed in a breakable word,
  -- before a break point, and after a break point when hyphenating a word.
  --
  -- For example,
  --
  -- >>> hyphenateLimitChars 14 auto auto
  --
  -- For reference, see
  -- [@hyphenate-limit-chars@](https://developer.mozilla.org/en-US/docs/Web/CSS/hyphenate-limit-chars).
  hyphenateLimitChars
    :: HyphenateLimit -- ^ Minimum length of a word which can be hyphenated.
    -> HyphenateLimit -- ^ Minimum number of characters allowed before a break point.
    -> HyphenateLimit -- ^ Minimum number of characters allowed after a break point.
    -> Css
  hyphenateLimitChars word before after =
    key "hyphenate-limit-chars" (word ! before ! after)
  
  -------------------------------------------------------------------------------
  
  newtype Content = Content Value
    deriving (Val, None, Normal, Inherit, Initial)
  
  attrContent :: Text -> Content
  attrContent a = Content ("attr(" <> value a <> ")")
  
  stringContent :: Text -> Content
  stringContent = Content . value . Literal
  
  uriContent :: Text -> Content
  uriContent u = Content ("uri(" <> value (Literal u) <> ")")
  
  urlContent :: Text -> Content
  urlContent u = Content ("url(" <> value (Literal u) <> ")")
  
  openQuote, closeQuote, noOpenQuote, noCloseQuote :: Content
  
  openQuote    = Content "open-quote"
  closeQuote   = Content "close-quote"
  noOpenQuote  = Content "no-open-quote"
  noCloseQuote = Content "no-close-quote"
  
  content :: Content -> Css
  content = key "content"
  
  contents :: [Content] -> Css
  contents cs = key "content" (noCommas cs)
  
  -- TODO: counters
  