Skip to content

Commit

Permalink
Merge pull request #252 from qwbarch/master
Browse files Browse the repository at this point in the history
Replace usage of 'Double' with 'Fixed E5' to avoid floating precision errors
  • Loading branch information
turion authored Jul 7, 2023
2 parents a68f105 + 0fbcc1f commit d6dfa00
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 71 deletions.
2 changes: 1 addition & 1 deletion clay.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Name: clay
Version: 0.14.0
Version: 0.15.0
Synopsis: CSS preprocessor as embedded Haskell.
Description:
Clay is a CSS preprocessor like LESS and Sass, but implemented as an embedded
Expand Down
4 changes: 2 additions & 2 deletions examples/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ main :: IO ()
main = putCss logo

where
s = 80 :: Double
m = 30 :: Double
s = 80 :: Number
m = 30 :: Number
cs = [ "#78e700"
, "#00b454"
, "#ff3900"
Expand Down
4 changes: 4 additions & 0 deletions spec/Clay/SizeSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import Data.Text
import Data.Text.Lazy (toStrict)
import Data.List

import Prelude hiding (rem)

sizeRepr :: Size a -> Text
sizeRepr = plain . unValue . value

Expand Down Expand Up @@ -42,6 +44,8 @@ spec = do
sizeRepr (px 1) `shouldBe` "1px"
it "return 50% for (pct 50)" $
sizeRepr (pct 50) `shouldBe` "50%"
it "returns 0.6rem for (rem 0.6)" $
sizeRepr (rem 0.6) `shouldBe` "0.6rem"
describe "calc addition" $ do
it "returns proper calc for simple sum" $
sizeRepr (em 2 @+@ px 1) `shouldBe` "calc(2em + 1px)"
Expand Down
2 changes: 1 addition & 1 deletion src/Clay/Animation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ animationIterationCounts = prefixed (browsers <> "animation-iteration-count")
infinite :: IterationCount
infinite = IterationCount "infinite"

iterationCount :: Double -> IterationCount
iterationCount :: Number -> IterationCount
iterationCount = IterationCount . value

-------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/Clay/Display.hs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ rect t r b l = Clip (mconcat ["rect(", value t, ",", value r, ",", value b, ",",

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

opacity :: Double -> Css
opacity :: Number -> Css
opacity = key "opacity"

zIndex :: Integer -> Css
Expand Down
2 changes: 1 addition & 1 deletion src/Clay/Filter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ url u = Filter ("url(" <> value u <> ")")
blur :: Size LengthUnit -> Filter
blur i = Filter ("blur(" <> value i <> ")")

brightness :: Double -> Filter
brightness :: Number -> Filter
brightness i = Filter ("brightness(" <> value i <> ")")

contrast :: Size Percentage -> Filter
Expand Down
22 changes: 13 additions & 9 deletions src/Clay/Property.hs
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,6 @@ instance Val Integer where
data E5 = E5
instance HasResolution E5 where resolution _ = 100000

instance Val Double where
value = Value . Plain . cssDoubleText

cssDoubleText :: Double -> Text
cssDoubleText = fromString . showFixed' . realToFrac
where
showFixed' :: Fixed E5 -> String
showFixed' = showFixed True

instance Val Value where
value = id

Expand All @@ -106,6 +97,19 @@ intercalate s (x:xs) = foldl (\a b -> a `mappend` s `mappend` b) x xs

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

-- | A number type to represent the CSS @number@ type.
-- It has fixed precision, supporting up to 5 decimal places.
newtype Number = Number { unNumber :: Fixed E5 }
deriving (Enum, Eq, Fractional, Num, Ord, Read, Real, RealFrac, Show)

instance Val Number where
value = Value . Plain . cssNumberText

cssNumberText :: Number -> Text
cssNumberText = fromString . showFixed True . unNumber

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

noCommas :: Val a => [a] -> Value
noCommas xs = intercalate " " (map value xs)

Expand Down
2 changes: 1 addition & 1 deletion src/Clay/Render.hs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ kframe cfg (Keyframes ident xs) =
)
(unPrefixed browsers)

frame :: Config -> (Double, [Rule]) -> Builder
frame :: Config -> (Number, [Rule]) -> Builder
frame cfg (p, rs) =
mconcat
[ fromText (pack (show p))
Expand Down
84 changes: 42 additions & 42 deletions src/Clay/Size.hs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ data Size a =
SimpleSize Text |
forall b c. SumSize (Size b) (Size c) |
forall b c. DiffSize (Size b) (Size c) |
MultSize Double (Size a) |
DivSize Double (Size a) |
MultSize Number (Size a) |
DivSize Number (Size a) |
OtherSize Value

deriving instance Show (Size a)
Expand All @@ -115,8 +115,8 @@ sizeToText :: Size a -> Text
sizeToText (SimpleSize txt) = txt
sizeToText (SumSize a b) = mconcat ["(", sizeToText a, " + ", sizeToText b, ")"]
sizeToText (DiffSize a b) = mconcat ["(", sizeToText a, " - ", sizeToText b, ")"]
sizeToText (MultSize a b) = mconcat ["(", cssDoubleText a, " * ", sizeToText b, ")"]
sizeToText (DivSize a b) = mconcat ["(", sizeToText b, " / ", cssDoubleText a, ")"]
sizeToText (MultSize a b) = mconcat ["(", cssNumberText a, " * ", sizeToText b, ")"]
sizeToText (DivSize a b) = mconcat ["(", sizeToText b, " / ", cssNumberText a, ")"]
sizeToText (OtherSize a) = plain $ unValue a

instance Val (Size a) where
Expand All @@ -135,87 +135,87 @@ nil :: Size a
nil = SimpleSize "0"

-- | Unitless size (as recommended for line-height).
unitless :: Double -> Size a
unitless :: Number -> Size a
unitless i = SimpleSize ((plain . unValue . value) i)

cm, mm, inches, px, pt, pc :: Double -> Size LengthUnit
cm, mm, inches, px, pt, pc :: Number -> Size LengthUnit

-- | Size in centimeters.
cm i = SimpleSize (cssDoubleText i <> "cm")
cm i = SimpleSize (cssNumberText i <> "cm")

-- | Size in millimeters.
mm i = SimpleSize (cssDoubleText i <> "mm")
mm i = SimpleSize (cssNumberText i <> "mm")

-- | Size in inches (1in = 2.54 cm).
inches i = SimpleSize (cssDoubleText i <> "in")
inches i = SimpleSize (cssNumberText i <> "in")

-- | Size in pixels.
px i = SimpleSize (cssDoubleText i <> "px")
px i = SimpleSize (cssNumberText i <> "px")

-- | Size in points (1pt = 1/72 of 1in).
pt i = SimpleSize (cssDoubleText i <> "pt")
pt i = SimpleSize (cssNumberText i <> "pt")

-- | Size in picas (1pc = 12pt).
pc i = SimpleSize (cssDoubleText i <> "pc")
pc i = SimpleSize (cssNumberText i <> "pc")

em, ex, ch, rem, lh, rlh, vw, vh, vmin, vmax, vb, vi, svw, svh, lvw, lvh, dvw, dvh, fr :: Double -> Size LengthUnit
em, ex, ch, rem, lh, rlh, vw, vh, vmin, vmax, vb, vi, svw, svh, lvw, lvh, dvw, dvh, fr :: Number -> Size LengthUnit

-- | Size in em's (computed cssDoubleText of the font-size).
em i = SimpleSize (cssDoubleText i <> "em")
-- | Size in em's (computed cssNumberText of the font-size).
em i = SimpleSize (cssNumberText i <> "em")

-- | SimpleSize in ex'es (x-height of the first avaliable font).
ex i = SimpleSize (cssDoubleText i <> "ex")
ex i = SimpleSize (cssNumberText i <> "ex")

-- | SimpleSize in ch's (The width of the glyph "0" of the element's font).
ch i = SimpleSize (cssDoubleText i <> "ch")
ch i = SimpleSize (cssNumberText i <> "ch")

-- | SimpleSize in rem's (em's, but always relative to the root element).
rem i = SimpleSize (cssDoubleText i <> "rem")
rem i = SimpleSize (cssNumberText i <> "rem")

-- | SimpleSize in lh's (Line height of the element).
lh i = SimpleSize (cssDoubleText i <> "lh")
lh i = SimpleSize (cssNumberText i <> "lh")

-- | SimpleSize in rlh's (lh's, but always relative to the root element).
rlh i = SimpleSize (cssDoubleText i <> "rlh")
rlh i = SimpleSize (cssNumberText i <> "rlh")

-- | SimpleSize in vw's (1vw = 1% of viewport width).
vw i = SimpleSize (cssDoubleText i <> "vw")
vw i = SimpleSize (cssNumberText i <> "vw")

-- | SimpleSize in vh's (1vh = 1% of viewport height).
vh i = SimpleSize (cssDoubleText i <> "vh")
vh i = SimpleSize (cssNumberText i <> "vh")

-- | SimpleSize in vmin's (the smaller of vw or vh).
vmin i = SimpleSize (cssDoubleText i <> "vmin")
vmin i = SimpleSize (cssNumberText i <> "vmin")

-- | SimpleSize in vmax's (the larger of vw or vh).
vmax i = SimpleSize (cssDoubleText i <> "vmax")
vmax i = SimpleSize (cssNumberText i <> "vmax")

-- | SimpleSize in vb's (1vb = 1% of the parent's size in the direction of the root element's block axis).
vb i = SimpleSize (cssDoubleText i <> "vb")
vb i = SimpleSize (cssNumberText i <> "vb")

-- | SimpleSize in vi's (1vi = 1% of the parent's size in the direction of the root element's inline axis).
vi i = SimpleSize (cssDoubleText i <> "vi")
vi i = SimpleSize (cssNumberText i <> "vi")

-- | SimpleSize in svw's (1svw = 1% of the small viewport's width).
svw i = SimpleSize (cssDoubleText i <> "svw")
svw i = SimpleSize (cssNumberText i <> "svw")

-- | SimpleSize in svh's (1svh = 1% of the small viewport's height).
svh i = SimpleSize (cssDoubleText i <> "svh")
svh i = SimpleSize (cssNumberText i <> "svh")

-- | SimpleSize in lvw's (1lvw = 1% of the large viewport's width).
lvw i = SimpleSize (cssDoubleText i <> "lvw")
lvw i = SimpleSize (cssNumberText i <> "lvw")

-- | SimpleSize in lvh's (1lvh = 1% of the large viewport's height).
lvh i = SimpleSize (cssDoubleText i <> "lvh")
lvh i = SimpleSize (cssNumberText i <> "lvh")

-- | SimpleSize in dvw's (1dvw = 1% of the dynamic viewport's width).
dvw i = SimpleSize (cssDoubleText i <> "dvw")
dvw i = SimpleSize (cssNumberText i <> "dvw")

-- | SimpleSize in dvh's (1dvh = 1% of the dynamic viewport's height).
dvh i = SimpleSize (cssDoubleText i <> "dvh")
dvh i = SimpleSize (cssNumberText i <> "dvh")

-- | 'SimpleSize' in fr's (a fractional unit and 1fr is for 1 part of the available space in grid areas).
fr i = SimpleSize (cssDoubleText i <> "fr")
fr i = SimpleSize (cssNumberText i <> "fr")

-- | SimpleSize for the intrinsic preferred width.
maxContent :: Size LengthUnit
Expand All @@ -234,8 +234,8 @@ fitContent :: Size LengthUnit
fitContent = SimpleSize "fit-content"

-- | SimpleSize in percents.
pct :: Double -> Size Percentage
pct i = SimpleSize (cssDoubleText i <> "%")
pct :: Number -> Size Percentage
pct i = SimpleSize (cssNumberText i <> "%")

instance Num (Size LengthUnit) where
fromInteger = px . fromInteger
Expand Down Expand Up @@ -280,17 +280,17 @@ a @-@ b = DiffSize a b

-- | Times operator to combine sizes into calc function
infixl 7 *@
(*@) :: Double -> Size a -> Size a
(*@) :: Number -> Size a -> Size a
a *@ b = MultSize a b

-- | Reversed times operator to combine sizes into calc function
infixl 7 @*
(@*) :: Size a -> Double -> Size a
(@*) :: Size a -> Number -> Size a
a @* b = MultSize b a

-- | Division operator to combine sizes into calc function
infixl 7 @/
(@/) :: Size a -> Double -> Size a
(@/) :: Size a -> Number -> Size a
a @/ b = DivSize b a

-------------------------------------------------------------------------------
Expand All @@ -315,19 +315,19 @@ newtype Angle a = Angle Value
deriving (Val, Auto, Inherit, Other)

-- | Angle in degrees.
deg :: Double -> Angle Deg
deg :: Number -> Angle Deg
deg i = Angle (value i <> "deg")

-- | Angle in radians.
rad :: Double -> Angle Rad
rad :: Number -> Angle Rad
rad i = Angle (value i <> "rad")

-- | Angle in gradians (also knows as gons or grades).
grad :: Double -> Angle Grad
grad :: Number -> Angle Grad
grad i = Angle (value i <> "grad")

-- | Angle in turns.
turn :: Double -> Angle Turn
turn :: Number -> Angle Turn
turn i = Angle (value i <> "turn")

instance Num (Angle Deg) where
Expand Down
4 changes: 2 additions & 2 deletions src/Clay/Stylesheet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ data App
| Sub Selector
deriving Show

data Keyframes = Keyframes Text [(Double, [Rule])]
data Keyframes = Keyframes Text [(Number, [Rule])]
deriving Show

data Rule
Expand Down Expand Up @@ -165,7 +165,7 @@ queryOnly ty fs rs = rule $ Query (MediaQuery (Just Only) ty fs) (runS rs)

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

keyframes :: Text -> [(Double, Css)] -> Css
keyframes :: Text -> [(Number, Css)] -> Css
keyframes n xs = rule $ Keyframe (Keyframes n (map (second runS) xs))

keyframesFromTo :: Text -> Css -> Css -> Css
Expand Down
20 changes: 10 additions & 10 deletions src/Clay/Transform.hs
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,16 @@ transformOrigin = prefixed (browsers <> "transform-origin") . noCommas

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

scale :: Double -> Double -> Transformation
scale :: Number -> Number -> Transformation
scale x y = Transformation ("scale(" <> value [x, y] <> ")")

scaleX, scaleY, scaleZ :: Double -> Transformation
scaleX, scaleY, scaleZ :: Number -> Transformation

scaleX x = Transformation ("scaleX(" <> value x <> ")")
scaleY y = Transformation ("scaleY(" <> value y <> ")")
scaleZ z = Transformation ("scaleZ(" <> value z <> ")")

scale3d :: Double -> Double -> Double -> Transformation
scale3d :: Number -> Number -> Number -> Transformation
scale3d x y z = Transformation ("scale3d(" <> value [x, y, z] <> ")")

-------------------------------------------------------------------------------
Expand All @@ -124,7 +124,7 @@ rotateX x = Transformation ("rotateX(" <> value x <> ")")
rotateY y = Transformation ("rotateY(" <> value y <> ")")
rotateZ z = Transformation ("rotateZ(" <> value z <> ")")

rotate3d :: Double -> Double -> Double -> Angle a -> Transformation
rotate3d :: Number -> Number -> Number -> Angle a -> Transformation
rotate3d x y z a = Transformation ("rotate3d(" <> value [value x, value y, value z, value a] <> ")")

-------------------------------------------------------------------------------
Expand Down Expand Up @@ -154,16 +154,16 @@ skewY y = Transformation ("skewY(" <> value y <> ")")

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

perspective :: Double -> Transformation
perspective :: Number -> Transformation
perspective p = Transformation ("perspective(" <> value p <> ")")

matrix :: Double -> Double -> Double -> Double -> Double -> Double -> Transformation
matrix :: Number -> Number -> Number -> Number -> Number -> Number -> Transformation
matrix u v w x y z = Transformation ("matrix(" <> value [ u, v, w, x, y, z ] <> ")")

matrix3d :: Double -> Double -> Double -> Double
-> Double -> Double -> Double -> Double
-> Double -> Double -> Double -> Double
-> Double -> Double -> Double -> Double
matrix3d :: Number -> Number -> Number -> Number
-> Number -> Number -> Number -> Number
-> Number -> Number -> Number -> Number
-> Number -> Number -> Number -> Number
-> Transformation
matrix3d w0 x0 y0 z0
w1 x1 y1 z1
Expand Down
2 changes: 1 addition & 1 deletion src/Clay/Transition.hs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ stepsStart, stepsStop :: Integer -> TimingFunction
stepsStart s = other ("steps(" <> value s <> ", start)")
stepsStop s = other ("steps(" <> value s <> ", end)")

cubicBezier :: Double -> Double -> Double -> Double -> TimingFunction
cubicBezier :: Number -> Number -> Number -> Number -> TimingFunction
cubicBezier a b c d = other ("cubic-bezier(" <> value [a, b, c, d] <> ")")

transitionTimingFunction :: TimingFunction -> Css
Expand Down

0 comments on commit d6dfa00

Please sign in to comment.