-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Grid Support #210
Grid Support #210
Conversation
Exciting :) do assign me as a reviewer when you're ready. |
@turion Ready for review. I don't think have permissions for explicitly assigning you as reviewer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the extensive work so far! Here are some initial comments to get the review started. I'm going to have a second round later, when I understand your angle better.
clay.cabal
Outdated
@@ -75,7 +75,8 @@ Library | |||
Build-Depends: | |||
base >= 4.11 && < 5, | |||
mtl >= 1 && < 2.3, | |||
text >= 0.11 && < 1.3 | |||
text >= 0.11 && < 1.3, | |||
these < 1.2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you introduce an upper bound, shouldn't you also introduce a lower bound?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at the earliest version of the package on hackage, and it has the constructurs I'm making use of.
But I can add a lower bound for completeness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that would be nice, then noone is going to ask themselves that question anymore.
|
||
-- | Upcast a size unit | ||
upcast :: Size a -> Size AnyUnit | ||
upcast = coerce |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I think this is not a good idea. Can't you instead:
- Make
Size
into a GADT - Add an
Upcast :: Size a -> Size AnyUnit
constructor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate?
What's the functional difference from the user perspective?
It's more work to embed it in a constructor, I now have to add cases to sizeToText
& the Val
instance that do nothing but unwrap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the user perspective it's mostly the same I hope. But from the maintainer's perspective a huge burden is gone because noone has to worry about coerce
breaking anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to admit that I completely misunderstood what you did here. I mistook coerce
for unsafeCoerce
, which is - as the name says - unsafe, whereas coerce
is completely fine. It will never break anything because the type checker ensures that coercion only happens when the internal representations are indeed the same. If that was your goal, I'm sorry about the misdirection: feel free to disregard the stuff I said about GADTs, and let's make everyone's life easier by using coerce
.
@@ -47,8 +42,6 @@ spec = do | |||
sizeRepr (em 2 @+@ px 1) `shouldBe` "calc(2em + 1px)" | |||
it "returns calc for nested sum" $ | |||
sizeRepr (em 2 @+@ pt 1 @+@ px 3) `shouldBe` "calc((2em + 1pt) + 3px)" | |||
it "returns prefixed calc for simple sum" $ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this removed?
@@ -1,8 +1,16 @@ | |||
module Common where | |||
module Common | |||
( shouldRenderFrom |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is no need to filter the exports. Or was there a name clash?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No name clash. I introduced a new top level binding of testRender
& was preventing its export. It's not a big deal either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I'm fine if you don't restrict the exports in that case.
@turion To be clear, you're very opposed to partial But are you open to partial |
In my own libraries, I would not allow any partial functions that are reachable for library users. In In particular for a CSS processor many people will take the stance that in a sense clay is always run "before runtime" in that CSS is generated before the webserver starts. Still these errors don't show up during type checking and are therefore not in the typical Haskell dev workflow. You'd think that your program will run when it compiles, but it doesn't necessarily here. Since I don't want to undermine your efforts, I'd be willing to accept these partial functions if you really think they add value and cannot made be total with reasonable effort. But if it's just for being able to write an integer literal I'm not so sure it's all that much added value. Consider |
Would love to see this merged. |
Yes, that would be great :) @CharlesTaylor7 do you want to continue? I hope my review so far wasn't to rigorous to demotivate. Reading back what I wrote it sounds quite harsh in my ears. If it did that for you as well, I'm really sorry, and I'll try to write in a friendlier tone :) If you have any questions on how to proceed, feel free to ask. |
@turion I would like to complete this PR. I hate loose ends and do appreciate quality focused, thorough code reviews. I have no issue with you, just lost interest with this last year. I have the time and motivation to tackle this now. |
@turion #210 (comment) For sum types, I took the approach of prefixing constructor names with the name of type. This can be done with or without underscores. I removed the underscores, because they are at odds with the rest of the library which doesn't use underscores. (Though, I do think the underscores make it easier to visually parse). |
-- https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-start | ||
-- either grid index and/or named grid area is required, but span is optional | ||
-- Note: constuctor is not exported, 'GridIndex, or 'gridLocationData to fill this info in | ||
data GridLocationData = MkGridLocationData IsSpan (These Integer GridArea) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Constructor should have the same name as the type.
Fantastic, looking forward to reviewing further :)
This is a tough problem that I also often have. A few rules of thumb that I have for these situations:
Specifically for
In your case though, I'd simply remove the |
data IsSpan = Span | NoSpan | ||
deriving (Show, Eq) | ||
|
||
data GridLocation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is not a known CSS concept (as far as I know), describe a bit what it is and what it is good for.
|
||
------------------------------------------------------------------------------- | ||
|
||
gridRowStart :: GridLocation -> Css |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I thought grid rows don't support spans? See https://www.w3schools.com/cssref/pr_grid-row-start.asp. Maybe GridLocation
should be GridColumnLocation
?
class Hidden a where hidden :: a | ||
class Initial a where initial :: a | ||
class Unset a where unset :: a | ||
class MinContent a where minContent :: a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any chance that some other types than Value
will also be instances of your new classes?
, gridTemplateColumns | ||
) | ||
where | ||
( gap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there many definitions in this module that are not exported? If everything is exported, we can also simply not restrict the exports.
|
||
-- | Property sets the gaps (gutters) between rows and columns. | ||
gridGap :: Size a -> Css | ||
gridGap = key "grid-gap" | ||
-- Sets both "gap" & "grid-gap" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-- Sets both "gap" & "grid-gap" | |
-- | |
-- Sets both "gap" & "grid-gap" |
gap = key "gap" <> key "grid-gap" | ||
|
||
-- | Property sets the size of the gap (gutter) between an element's grid rows. | ||
-- Sets both "row-gap" & "grid-row-gap" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-- Sets both "row-gap" & "grid-row-gap" | |
-- | |
-- Sets both "row-gap" & "grid-row-gap" |
At least I believe this will make a paragraph in haddock.
rowGap = key "row-gap" <> key "grid-row-gap" | ||
|
||
-- | Property sets the size of the gap (gutter) between an element's grid columns. | ||
-- Sets both "column-gap" & "grid-column-gap" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
gridTemplateColumns = key "grid-template-columns" | ||
|
||
newtype GridTrackList a = GridTrackList Value | ||
deriving (Val, None, Inherit, Initial, Unset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deriving (Val, None, Inherit, Initial, Unset) | |
deriving (Val, None, Inherit, Initial, Unset, Auto, MaxContent, MinContent) |
gridTemplateColumns :: GridTrackList a -> Css | ||
gridTemplateColumns = key "grid-template-columns" | ||
|
||
newtype GridTrackList a = GridTrackList Value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since Size
is also an instance of None
, Initial
, etc., why not define it directly as a list of sizes?
newtype GridTrackList a = GridTrackList Value | |
newtype GridTrackList a = GridTrackList [Size a] |
gridTemplateColumns :: GridTrackList a -> Css | ||
gridTemplateColumns = key "grid-template-columns" | ||
|
||
newtype GridTrackList a = GridTrackList Value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding now is that GridTrackList
is a concept that has no corresponding CSS name, and it mirrors the possible values one can give to grid-template-columns
and grid-template-rows
. Maybe the naming can reflect this, and stay closer to known concepts? So for example GridTemplateSizes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe these are called "tracks" in the community, and I just don't know?
mkGridTrackList :: [Size a] -> GridTrackList a | ||
mkGridTrackList = GridTrackList . noCommas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mkGridTrackList :: [Size a] -> GridTrackList a | |
mkGridTrackList = GridTrackList . noCommas | |
gridTrackList :: [Size a] -> GridTrackList a | |
gridTrackList = GridTrackList . noCommas |
But see https://github.com/sebastiaanvisser/clay/pull/210/files#r780772464 first.
gridAutoColumns :: GridAutoTrackList a -> Css | ||
gridAutoColumns = key "grid-auto-columns" | ||
|
||
newtype GridAutoTrackList a = GridAutoTrackList Value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same comments as for GridTrackList
apply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First superficial round done. I like where this is going!
Co-authored-by: Manuel Bärenz <[email protected]>
Co-authored-by: Manuel Bärenz <[email protected]>
gridTemplateColumns none | ||
|
||
describe "list of sizes" $ do | ||
"{grid-template-columns:1em calc(20% + 1fr) auto}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the grid spec:
Note: <flex> values are not <length>s (nor are they compatible with <length>s, like some <percentage> values), so they cannot be represented in or combined with other unit types in calc() expressions.
So I obviously lost steam to work on this, and there's a newer pull request in place, so withdrawing this PR. #250 |
Resolves #176
Explicit support for all grid properties listed on mdn, except for a handful of shorthand properties:
The above shorthands have involved syntax which would make them a pain to support. The finer grained methods still encapsulate all the grid layout options.
I'm mostly happy with how this pr turned out. The main shortcoming for me is
upcast
. I tried a number of other things, but none of them worked very well. What would be nice here is Impredicative Polymorphism. I want to be able to create a list of type[forall a. Size a]
forgridTemplateRows
/gridTemplateColumns
, but GHC won't oblige me. Maybe something to revisit when we get Quick Look?