clay 0.12.2 → 0.12.3
raw patch · 11 files changed
+338/−59 lines, 11 filesdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base
API changes (from Hackage documentation)
- Clay.Property: intersperse :: Monoid a => a -> [a] -> a
- Clay.Selector: filterFromText :: Text -> Refinement
- Clay.Selector: text :: Text -> Selector
+ Clay: commenting :: CommentText -> Css -> Css
+ Clay: important :: Css -> Css
+ Clay: infixl 3 `commenting`
+ Clay.Box: boxShadow' :: Size a -> Size a -> Size a -> Color -> Css
+ Clay.Box: bsColor :: Color -> BoxShadow -> BoxShadow
+ Clay.Box: bsInset :: BoxShadow -> BoxShadow
+ Clay.Box: infixr 9 `bsColor`
+ Clay.Box: instance Clay.Common.Inherit Clay.Box.BoxShadow
+ Clay.Box: instance Clay.Common.Initial Clay.Box.BoxShadow
+ Clay.Box: instance Clay.Common.None Clay.Box.BoxShadow
+ Clay.Box: instance Clay.Common.Other Clay.Box.BoxShadow
+ Clay.Box: instance Clay.Common.Unset Clay.Box.BoxShadow
+ Clay.Box: instance Clay.Property.Val Clay.Box.BoxShadow
+ Clay.Box: shadow :: Size a -> Size a -> BoxShadow
+ Clay.Box: shadowWithBlur :: Size a -> Size a -> Size a -> BoxShadow
+ Clay.Box: shadowWithSpread :: Size a -> Size a -> Size a -> Size a -> BoxShadow
+ Clay.Comments: addComment :: CommentText -> Rule -> Rule
+ Clay.Comments: commenting :: CommentText -> Css -> Css
+ Clay.Comments: infixl 3 `commenting`
+ Clay.FontFace: WOFF2 :: FontFaceFormat
+ Clay.Property: instance Clay.Property.Val a => Clay.Property.Val (Data.List.NonEmpty.NonEmpty a)
+ Clay.Property: intercalate :: Monoid a => a -> [a] -> a
+ Clay.Render: [comments] :: Config -> Bool
+ Clay.Render: instance GHC.Show.Show Clay.Render.Representation
+ Clay.Render: withBanner :: Text -> Text
+ Clay.Selector: instance GHC.Base.Monoid Clay.Selector.Refinement
+ Clay.Selector: refinementFromText :: Text -> Refinement
+ Clay.Selector: selectorFromText :: Text -> Selector
+ Clay.Stylesheet: Comment :: CommentText -> Modifier
+ Clay.Stylesheet: CommentText :: Text -> CommentText
+ Clay.Stylesheet: Important :: Modifier
+ Clay.Stylesheet: [unCommentText] :: CommentText -> Text
+ Clay.Stylesheet: _Comment :: Modifier -> Maybe CommentText
+ Clay.Stylesheet: _Important :: Modifier -> Maybe Text
+ Clay.Stylesheet: addImportant :: Rule -> Rule
+ Clay.Stylesheet: data Modifier
+ Clay.Stylesheet: important :: Css -> Css
+ Clay.Stylesheet: instance Data.Semigroup.Semigroup Clay.Stylesheet.CommentText
+ Clay.Stylesheet: instance Data.String.IsString Clay.Stylesheet.CommentText
+ Clay.Stylesheet: instance GHC.Base.Monoid Clay.Stylesheet.CommentText
+ Clay.Stylesheet: instance GHC.Show.Show Clay.Stylesheet.CommentText
+ Clay.Stylesheet: instance GHC.Show.Show Clay.Stylesheet.Modifier
+ Clay.Stylesheet: newtype CommentText
+ Clay.Text: instance Clay.Common.Initial Clay.Text.TextIndent
+ Clay.Text: instance Clay.Common.Unset Clay.Text.TextIndent
- Clay.Background: class Val a => Background a where background = key "background"
+ Clay.Background: class Val a => Background a
- Clay.Background: class Val a => Loc a where location = Location . value
+ Clay.Background: class Val a => Loc a
- Clay.Box: boxShadow :: Size a -> Size a -> Size a -> Color -> Css
+ Clay.Box: boxShadow :: NonEmpty BoxShadow -> Css
- Clay.Display: class (Val a) => Cursor a where cursor = key "cursor"
+ Clay.Display: class (Val a) => Cursor a
- Clay.Display: class (Val a) => VerticalAlign a where verticalAlign = key "vertical-align"
+ Clay.Display: class (Val a) => VerticalAlign a
- Clay.Font: class Val a => Font a where font = key "font"
+ Clay.Font: class Val a => Font a
- Clay.Mask: class Val a => Mask a where mask = pkey "mask"
+ Clay.Mask: class Val a => Mask a
- Clay.Pseudo: not :: Text -> Refinement
+ Clay.Pseudo: not :: Selector -> Refinement
- Clay.Render: Config :: Builder -> Builder -> Builder -> Builder -> Builder -> Bool -> Bool -> Bool -> Bool -> Config
+ Clay.Render: Config :: Builder -> Builder -> Builder -> Builder -> Builder -> Bool -> Bool -> Bool -> Bool -> Bool -> Config
- Clay.Stylesheet: Property :: (Key ()) -> Value -> Rule
+ Clay.Stylesheet: Property :: [Modifier] -> (Key ()) -> Value -> Rule
- Clay.Text: eachLine :: TextIndent
+ Clay.Text: eachLine :: TextIndent -> TextIndent
- Clay.Text: hanging :: TextIndent
+ Clay.Text: hanging :: TextIndent -> TextIndent
Files
- clay.cabal +2/−1
- src/Clay.hs +26/−1
- src/Clay/Box.hs +125/−4
- src/Clay/Comments.hs +30/−0
- src/Clay/FontFace.hs +8/−1
- src/Clay/Property.hs +9/−5
- src/Clay/Pseudo.hs +7/−2
- src/Clay/Render.hs +51/−29
- src/Clay/Selector.hs +10/−10
- src/Clay/Stylesheet.hs +41/−2
- src/Clay/Text.hs +29/−4
clay.cabal view
@@ -1,5 +1,5 @@ Name: clay-Version: 0.12.2+Version: 0.12.3 Synopsis: CSS preprocessor as embedded Haskell. Description: Clay is a CSS preprocessor like LESS and Sass, but implemented as an embedded@@ -43,6 +43,7 @@ Clay.Border Clay.Box Clay.Color+ Clay.Comments Clay.Common Clay.Dynamic Clay.Display
src/Clay.hs view
@@ -22,6 +22,10 @@ , (-:) +-- ** Comments+-- $comments+, commenting+ -- * The selector language. , Selector@@ -69,8 +73,12 @@ , fontFace --- * Import other CSS files+-- * !important +, important++-- * Import other CSS files+ , importUrl -- * Pseudo elements and classes.@@ -138,6 +146,7 @@ import Clay.Box import Clay.Color import Clay.Time+import Clay.Comments (commenting) import Clay.Common import Clay.Display hiding (table) import Clay.Dynamic@@ -160,3 +169,19 @@ -- Because a large part of the names export by "Clay.Media" clash with names -- export by other modules we don't re-export it here and recommend you to -- import the module qualified.++-- $comments+--+-- It is occasionally useful to output comments in the generated css.+-- 'commenting' appends comments (surrounded by '@ /* @' and '@ */@') to the+-- values of the supplied 'Css' as+--+-- > key: value /* comment */;+--+-- Placing the comments before the semicolon ensures they are obviously+-- grouped with the preceding value when rendered compactly.+--+-- Note that /every/ generated line in the generated content will feature the+-- comment. +--+-- An empty comment generates '@/* */@'.
src/Clay/Box.hs view
@@ -3,7 +3,17 @@ ( BoxType , paddingBox, borderBox, contentBox , boxSizing+-- * @box-shadow@+-- $box-shadow , boxShadow+, shadow+, shadowWithBlur+, shadowWithSpread+, bsInset+, bsColor+-- ** Deprecated+-- $box-shadow-deprecated+, boxShadow' , boxShadowWithSpread , boxShadows , insetBoxShadow@@ -11,6 +21,7 @@ where import Data.Monoid+import Data.List.NonEmpty (NonEmpty) import Clay.Color import Clay.Common@@ -37,17 +48,127 @@ ------------------------------------------------------------------------------- -boxShadow :: Size a -> Size a -> Size a -> Color -> Css-boxShadow x y w c = prefixed (browsers <> "box-shadow") (x ! y ! w ! c)+-- $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.+--+-- > 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." #-}
+ src/Clay/Comments.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE OverloadedStrings #-}+module Clay.Comments where++import Data.Monoid ((<>))+import Data.Maybe (isNothing)+import Data.List (partition)++import Clay.Stylesheet++-- | Annotate the supplied 'Css' with the supplied comment.+-- Comments work with 'OverloadedStrings'. This will annotate every non-nested+-- value.+commenting :: CommentText -> Css -> Css+commenting c css = foldMap (rule . addComment c) $ runS css+infixl 3 `commenting`++-- The last case indicates there may be something wrong in the typing, as+-- it shouldn't be possible to comment a wrong rule. In practice, this implementation+-- means only the directly applied property rule is affected, i.e. no nested+-- rules. That could be changed by adding recursive cases.+addComment :: CommentText -> Rule -> Rule+addComment c (Property (PartitionComments xs (Just cs)) k v) = let c1 = Comment $ cs <> "; " <> c in+ Property (c1 : xs) k v+addComment c (Property ms k v ) = Property (Comment c : ms) k v+addComment _ r = r++pattern PartitionComments :: [Modifier] -> Maybe CommentText -> [Modifier]+pattern PartitionComments xs cs <- (fmap (foldMap _Comment) . partition (isNothing . _Comment) -> (xs, cs))
src/Clay/FontFace.hs view
@@ -16,13 +16,20 @@ ------------------------------------------------------------------------------- -data FontFaceFormat = WOFF | TrueType | OpenType | EmbeddedOpenType | SVG+data FontFaceFormat+ = WOFF+ | WOFF2+ | TrueType+ | OpenType+ | EmbeddedOpenType+ | SVG deriving Show -- | name of format according to CSS specification formatName :: FontFaceFormat -> Text formatName format = case format of WOFF -> "woff"+ WOFF2 -> "woff2" TrueType -> "truetype" OpenType -> "opentype" EmbeddedOpenType -> "embedded-opentype"
src/Clay/Property.hs view
@@ -5,6 +5,7 @@ import Control.Monad.Writer import Data.Fixed (Fixed, HasResolution (resolution), showFixed) import Data.List (partition, sort)+import Data.List.NonEmpty (NonEmpty, toList) import Data.Maybe import Data.String import Data.Text (Text, replace)@@ -92,16 +93,19 @@ value (Right a) = value a instance Val a => Val [a] where- value xs = intersperse "," (map value xs)+ value xs = intercalate "," (map value xs) -intersperse :: Monoid a => a -> [a] -> a-intersperse _ [] = mempty-intersperse s (x:xs) = foldl (\a b -> a <> s <> b) x xs+instance Val a => Val (NonEmpty a) where+ value = value . toList +intercalate :: Monoid a => a -> [a] -> a+intercalate _ [] = mempty+intercalate s (x:xs) = foldl (\a b -> a <> s <> b) x xs+ ------------------------------------------------------------------------------- noCommas :: Val a => [a] -> Value-noCommas xs = intersperse " " (map value xs)+noCommas xs = intercalate " " (map value xs) infixr !
src/Clay/Pseudo.hs view
@@ -3,8 +3,11 @@ import Data.Text (Text) +import Clay.Render (renderSelector) import Clay.Selector +import qualified Data.Text.Lazy as Lazy+ -- List of specific pseudo classes, from: -- https://developer.mozilla.org/en-US/docs/CSS/Pseudo-classes @@ -53,11 +56,13 @@ target = ":target" valid = ":valid" -lang, nthChild, nthLastChild, nthLastOfType, nthOfType, not :: Text -> Refinement+lang, nthChild, nthLastChild, nthLastOfType, nthOfType :: Text -> Refinement lang n = func "lang" [n] nthChild n = func "nth-child" [n] nthLastChild n = func "nth-last-child" [n] nthLastOfType n = func "nth-last-of-type" [n] nthOfType n = func "nth-of-type" [n]-not n = func "not" [n]++not :: Selector -> Refinement+not r = func "not" [Lazy.toStrict (renderSelector r)]
src/Clay/Render.hs view
@@ -8,12 +8,12 @@ , putCss , renderWith , renderSelector+, withBanner ) where import Control.Applicative import Control.Monad.Writer-import Data.Either import Data.Foldable (foldMap) import Data.List (sort) import Data.Maybe@@ -43,6 +43,7 @@ , warn :: Bool , align :: Bool , banner :: Bool+ , comments :: Bool } -- | Configuration to print to a pretty human readable CSS output.@@ -58,6 +59,7 @@ , warn = True , align = True , banner = True+ , comments = True } -- | Configuration to print to a compacted unreadable CSS output.@@ -73,6 +75,7 @@ , warn = False , align = False , banner = False+ , comments = False } -- | Configuration to print to a compacted unreadable CSS output for embedding inline with HTML.@@ -88,6 +91,7 @@ , warn = False , align = False , banner = False+ , comments = False } -- | Render to CSS using the default configuration (`pretty`) and directly@@ -121,10 +125,12 @@ renderBanner :: Config -> Lazy.Text -> Lazy.Text renderBanner cfg- | banner cfg = (<> b)+ | banner cfg = withBanner | otherwise = id- where b = "\n/* Generated with Clay, http://fvisser.nl/clay */" +withBanner :: Lazy.Text -> Lazy.Text+withBanner = (<> "\n/* Generated with Clay, http://fvisser.nl/clay */")+ kframe :: Config -> Keyframes -> Builder kframe cfg (Keyframes ident xs) = foldMap@@ -199,18 +205,18 @@ , (\(a, b) -> rules cfg (a : sel) b) `foldMap` mapMaybe nested rs , (\(a, b) -> query cfg a sel b) `foldMap` mapMaybe queries rs ]- where property (Property k v) = Just (k, v)- property _ = Nothing- nested (Nested a ns ) = Just (a, ns)- nested _ = Nothing- queries (Query q ns ) = Just (q, ns)- queries _ = Nothing- kframes (Keyframe fs ) = Just fs;- kframes _ = Nothing- faces (Face ns ) = Just ns- faces _ = Nothing- imports (Import i ) = Just i- imports _ = Nothing+ where property (Property m k v) = Just (m, k, v)+ property _ = Nothing+ nested (Nested a ns ) = Just (a, ns)+ nested _ = Nothing+ queries (Query q ns ) = Just (q, ns)+ queries _ = Nothing+ kframes (Keyframe fs ) = Just fs;+ kframes _ = Nothing+ faces (Face ns ) = Just ns+ faces _ = Nothing+ imports (Import i ) = Just i+ imports _ = Nothing imp :: Config -> Text -> Builder imp cfg t =@@ -220,8 +226,10 @@ , ");" , newline cfg ] +-- | A key-value pair with associated comment.+type KeyVal = ([Modifier], Key (), Value) -rule :: Config -> [App] -> [(Key (), Value)] -> Builder+rule :: Config -> [App] -> [KeyVal] -> Builder rule _ _ [] = mempty rule cfg sel props = let xs = collect =<< props@@ -245,36 +253,50 @@ Pop i -> merger (drop i (x:xs)) Self f -> case xs of [] -> star `with` f; _ -> merger xs `with` f -collect :: (Key (), Value) -> [Either Text (Text, Text)]-collect (Key ky, Value vl) =- case (ky, vl) of+data Representation+ = Warning Text+ | KeyValRep [Modifier] Text Text+ deriving (Show)++keys :: [Representation] -> [Text]+keys = mapMaybe f+ where+ f (KeyValRep _ k _) = Just k+ f _ = Nothing++collect :: KeyVal -> [Representation]+collect (ms, Key ky, Value vl) = case (ky, vl) of ( Plain k , Plain v ) -> [prop k v] ( Prefixed ks , Plain v ) -> flip map ks $ \(p, k) -> prop (p <> k) v ( Plain k , Prefixed vs ) -> flip map vs $ \(p, v) -> prop k (p <> v)- ( Prefixed ks , Prefixed vs ) -> flip map ks $ \(p, k) -> (Left (p <> k) `maybe` (prop (p <> k) . mappend p)) (lookup p vs)- where prop k v = Right (k, v)+ ( Prefixed ks , Prefixed vs ) -> flip map ks $ \(p, k) -> (Warning (p <> k) `maybe` (prop (p <> k) . mappend p)) (lookup p vs)+ where prop k v = KeyValRep ms k v -properties :: Config -> [Either Text (Text, Text)] -> Builder+properties :: Config -> [Representation] -> Builder properties cfg xs =- let width = 1 + maximum (Text.length . fst <$> rights xs)+ let width = 1 + maximum (Text.length <$> keys xs) ind = indentation cfg new = newline cfg finalSemi = if finalSemicolon cfg then ";" else ""- in (<> new) $ (<> finalSemi) $ intersperse (";" <> new) $ flip map xs $ \p ->+ in (<> new) $ (<> finalSemi) $ intercalate (";" <> new) $ flip map xs $ \p -> case p of- Left w -> if warn cfg+ Warning w -> if warn cfg then ind <> "/* no value for " <> fromText w <> " */" <> new else mempty- Right (k, v) ->+ KeyValRep ms k v -> let pad = if align cfg then fromText (Text.replicate (width - Text.length k) " ") else ""- in mconcat [ind, fromText k, pad, ":", sep cfg, fromText v]+ imptant = maybe "" ((" " <>) . fromText) . foldMap _Important $ ms+ comm = case (foldMap _Comment ms, comments cfg) of+ (Just c, True) -> " /* " <> fromText (unCommentText c) <> " */"+ _ -> mempty+ in mconcat [ind, fromText k, pad, ":", sep cfg, fromText v, imptant, comm] selector :: Config -> Selector -> Builder selector Config { lbrace = "", rbrace = "" } = rec where rec _ = ""-selector cfg = intersperse ("," <> newline cfg) . rec+selector cfg = intercalate ("," <> newline cfg) . rec where rec (In (SelectorF (Refinement ft) p)) = (<> foldMap predicate (sort ft)) <$> case p of Star -> if null ft then ["*"] else [""]@@ -298,6 +320,6 @@ AttrSpace a v -> [ "[" , fromText a, "~='", fromText v, "']" ] AttrHyph a v -> [ "[" , fromText a, "|='", fromText v, "']" ] Pseudo a -> [ ":" , fromText a ]- PseudoFunc a p -> [ ":" , fromText a, "(", intersperse "," (map fromText p), ")" ]+ PseudoFunc a p -> [ ":" , fromText a, "(", intercalate "," (map fromText p), ")" ] PseudoElem a -> [ "::", fromText a ]
src/Clay/Selector.hs view
@@ -157,13 +157,13 @@ deriving (Eq, Ord, Show) newtype Refinement = Refinement { unFilter :: [Predicate] }- deriving Show+ deriving (Show, Monoid) instance IsString Refinement where- fromString = filterFromText . fromString+ fromString = refinementFromText . fromString -filterFromText :: Text -> Refinement-filterFromText t = Refinement $+refinementFromText :: Text -> Refinement+refinementFromText t = Refinement $ case Text.uncons t of Just ('#', s) -> [Id s] Just ('.', s) -> [Class s]@@ -195,14 +195,14 @@ type Selector = Fix SelectorF instance IsString (Fix SelectorF) where- fromString = text . fromString+ fromString = selectorFromText . fromString -text :: Text -> Selector-text t = In $+selectorFromText :: Text -> Selector+selectorFromText t = case Text.uncons t of- Just ('#', s) -> SelectorF (Refinement [Id s]) Star- Just ('.', s) -> SelectorF (Refinement [Class s]) Star- _ -> SelectorF (Refinement []) (Elem t)+ Just (c, _) | elem c ("#.:@" :: [Char])+ -> with star (refinementFromText t)+ _ -> In $ SelectorF (Refinement []) (Elem t) #if MIN_VERSION_base(4,9,0) instance Semigroup (Fix SelectorF) where
src/Clay/Stylesheet.hs view
@@ -1,10 +1,15 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-} module Clay.Stylesheet where import Control.Applicative import Control.Arrow (second) import Control.Monad.Writer hiding (All)+import Data.Maybe (isJust)+import Data.Semigroup (Semigroup)+import Data.String (IsString) import Data.Text (Text) import Clay.Selector hiding (Child)@@ -25,6 +30,22 @@ data Feature = Feature Text (Maybe Value) deriving Show +newtype CommentText = CommentText { unCommentText :: Text }+ deriving (Show, IsString, Semigroup, Monoid)++data Modifier+ = Important+ | Comment CommentText+ deriving (Show)++_Important :: Modifier -> Maybe Text+_Important Important = Just "!important"+_Important (Comment _) = Nothing++_Comment :: Modifier -> Maybe CommentText+_Comment (Comment c) = Just c+_Comment Important = Nothing+ ------------------------------------------------------------------------------- data App@@ -39,7 +60,7 @@ deriving Show data Rule- = Property (Key ()) Value+ = Property [Modifier] (Key ()) Value | Nested App [Rule] | Query MediaQuery [Rule] | Face [Rule]@@ -71,7 +92,7 @@ -- words: can be converted to a `Value`. key :: Val a => Key a -> a -> Css-key k v = rule $ Property (cast k) (value v)+key k v = rule $ Property [] (cast k) (value v) -- | Add a new style property to the stylesheet with the specified `Key` and -- value, like `key` but use a `Prefixed` key.@@ -161,3 +182,21 @@ importUrl :: Text -> Css importUrl l = rule $ Import l +-------------------------------------------------------------------------------++-- | Indicate the supplied css should override css declarations that would+-- otherwise take precedence.+--+-- Use sparingly.+important :: Css -> Css+important = foldMap (rule . addImportant) . runS++-- The last case indicates there may be something wrong in the typing, as+-- it shouldn't be possible to make a non-property important. In practice,+-- this implementation means only the directly applied property rule is+-- affected, i.e. no nested rules. That could be changed by adding recursive cases.+addImportant :: Rule -> Rule+addImportant (Property ms@(filter (isJust . _Important) -> (_:_)) k v) =+ Property ms k v+addImportant (Property ms k v ) = Property (Important : ms) k v+addImportant r = r
src/Clay/Text.hs view
@@ -17,6 +17,7 @@ , textShadow -- * Text-indent.+-- $text-indent , TextIndent , textIndent@@ -134,13 +135,37 @@ ------------------------------------------------------------------------------- +-- $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, Other)+ deriving (Val, Inherit, Initial, Unset, Other) -eachLine, hanging :: TextIndent+-- | An internal function that ensures each-line and hanging are processed+-- correctly.+tagTextIndent :: Value -> TextIndent -> TextIndent+tagTextIndent v (TextIndent v0) = TextIndent . value $ (v0, v) -eachLine = TextIndent "each-line"-hanging = TextIndent "hanging"+-- | 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