GithubHelp home page GithubHelp logo

bs-css's People

Contributors

amirmoh10 avatar arecvlohe avatar arnarthor avatar baldurh avatar bloodyowl avatar bobzhang avatar bwarni avatar cdebotton avatar chenglou avatar cullophid avatar davesnx avatar dependabot-preview[bot] avatar dependabot[bot] avatar erykpiast avatar fhammerschmidt avatar giraud avatar glennsl avatar happylinks avatar jakubmarkiewicz avatar jeong-sik avatar knowbody avatar logason avatar lucasweng avatar mobily avatar poeschko avatar ruslangrigoryev avatar rusty-key avatar steinararnason avatar tomis avatar wegry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bs-css's Issues

CSS grid support

Hey, I'm going to submit a PR with some CSS grid values that are currently not supported.

One minor problem that needs to be decided on before I do so is if it should be a breaking change or not, but as a consequence not give compile time errors for the difference between flex and grid.

The problem is that both Flex and CSS grid use the align-items key to tell how to align items within a grid or flex container.

For flex box the valid values for this property are:

normal; 
stretch; 
center;
start;
end;
flex-start;
flex-end
self-start; 
self-end; 
baseline; 
first baseline; 
last baseline;
safe center; 
unsafe center; 
inherit; 
initial; 
unset;

But for grid they are just a subset of these

auto
normal
start
end
center
stretch
baseline
first baseline
last baseline

Should grid just not have the same compile time guarantees and just add the missing fields for that. Or should the user specify that its using Flex by doing something like alignItems(`flex(`flexEnd))?

I'm leaning towards non compile guarantees since the CSS grid properties are just a subset of flex (apart from auto), but at the same time it breaks the contract of typesafe CSS in the library.

All thoughts greatly appreciated. I'm really torn here πŸ˜„

Need to be able to set pixels as floating point values

We’re creating a fluid grid system which requires floating point pixels since spacing and sizes are calculated values. What would be the best option? Changing `px to accept float would be a breaking change. So maybe adding `pxFloat?

Support for nesting children?

I've looked through the code and don't see this option, but I may have missed something. I think it would be pretty useful to be able to target any html tag ("a", "button", ".some-classname", etc) within the component using bs-css.

Support elm-css's property function

elm-css supports letting users embed any CSS declaration with an api like such:

property "grid-template-areas" """
  "header header header"
  "sidebar content content"
  "footer footer footer"
"""

property "grid-area" "content"

It's a nice escape hatch for when properties or values don't have type definitions so users can sacrifice a little type-safety to not be blocked by lack of existing definitions in the library.

I looked at the source and it seems the d function already does this, but isn't exposed in Css.rei--I could maybe create a PR, but I'm not quite sure how to test it all.

The elm-css implementation:

https://github.com/rtfeldman/elm-css/blob/8d0e7c1a1affb500f014c010efd71b91356be9ac/src/Css.elm#L7243-L7246

polymorphic variant in rei

should we use [< | `some_tag | ... ] instead of [ | `some_tag | ... ] whenever possible?

https://github.com/SentiaAnalytics/bs-css/blob/master/src/Css.rei#L499 like here,
I've got a [<| `color | `url(string)], but when I pass it into background, it could not compiles:

  This has type:
    [< `currentColor
     | `hex(string)
     | `hsl(int, int, int)
     | `hsla(int, int, int, int)
     | `rgb(int, int, int)
     | `rgba(int, int, int, int)
     | `transparent
     | `url(string)
     > `hex ]
  But somewhere wanted:
    [ `currentColor
    | `hex(string)
    | `hsl(int, int, int)
    | `hsla(int, int, int, float)
    | `linearGradient(Css.angle, list((int, Css.color)))
    | `none
    | `radialGradient(list((int, Css.color)))
    | `repeatingLinearGradient(Css.angle, list((int, Css.color)))
    | `repeatingRadialGradient(list((int, Css.color)))
    | `rgb(int, int, int)
    | `rgba(int, int, int, float)
    | `transparent
    | `url(string) ]

Add repeat to gridLength

Maybe an approach similar to this would be helpful. But I'm bogged down in polymorphic variants trying to patch this up myself.

 The implementation src/Css.mlast
       does not match the interface src/css.cmi:
       Values do not match:
         let gridTemplateColumns:
           list(([< `auto
                  | `calc([< `add | `sub ],
                         ([< `calc([< `add | `sub ], 'b, 'b) &
                               ([< `add | `sub ], 'b, 'b)
                           | `ch(float)
                           | `cm(float)
                           | `em(float)
                           | `ex(float)
                           | `mm(float)
                           | `percent(float)
                           | `pt(int)
                           | `px(int)
                           | `pxFloat(float)
                           | `rem(float)
                           | `vh(float)
                           | `vmax(float)
                           | `vmin(float)
                           | `vw(float)
                           | `zero ]
                          as 'b),
                         ([< `calc([< `add | `sub ], 'c, 'c) &
                               ([< `add | `sub ], 'c, 'c)
                           | `ch(float)
                           | `cm(float)
                           | `em(float)
                           | `ex(float)
                           | `mm(float)
                           | `percent(float)
                           | `pt(int)
                           | `px(int)
                           | `pxFloat(float)
                           | `rem(float)
                           | `vh(float)
                           | `vmax(float)
                           | `vmin(float)
                           | `vw(float)
                           | `zero ]
                          as 'c))
                  | `ch(float)
                  | `cm(float)
                  | `em(float)
                  | `ex(float)
                  | `fr(float)
                  | `maxContent
                  | `minContent
                  | `mm(float)
                  | `percent(float)
                  | `pt(int)
                  | `px(int)
                  | `pxFloat(float)
                  | `rem(float)
                  | `repeat([< `autoFill | `autoFit | `n(int) ], 'a)
                  | `vh(float)
                  | `vmax(float)
                  | `vmin(float)
                  | `vw(float)
                  | `zero ]
                 as 'a)) =>
           [> `declaration(string, string) ]
       is not included in
         let gridTemplateColumns:
           list([ `auto
                | `calc([ `add | `sub ], length, length)
                | `ch(float)
                | `cm(float)
                | `em(float)
                | `ex(float)
                | `fr(float)
                | `maxContent
                | `minContent
                | `mm(float)
                | `percent(float)
                | `pt(int)
                | `px(int)
                | `pxFloat(float)
                | `rem(float)
                | `repeat(repeatValue, gridLength)
                | `vh(float)
                | `vmax(float)
                | `vmin(float)
                | `vw(float)
                | `zero ]) =>
           rule

from

diff --git a/src/Css.re b/src/Css.re
index 1963f48..e3e4067 100644
--- a/src/Css.re
+++ b/src/Css.re
@@ -3,8 +3,7 @@ include Css_Colors;
 module Emotion = {
   type css = string;
   [@bs.module "emotion"] external _make: Js.Json.t => css = "css";
-  [@bs.module "emotion"]
-  external injectGlobal: Js.Json.t => unit = "";
+  [@bs.module "emotion"] external injectGlobal: Js.Json.t => unit = "";
   [@bs.module "emotion"]
   external rawInjectGlobal: string => unit = "injectGlobal";
   [@bs.module "emotion"]
@@ -291,9 +290,12 @@ type selector = [ | `selector(string, list(rule))];
 let empty = [];
 
 let merge = List.concat;
-let global = (selector, rules: list(rule)) => {
-  Emotion.injectGlobal([(selector, Emotion.makeDict(rules))]->Js.Dict.fromList->Js.Json.object_);
-}
+let global = (selector, rules: list(rule)) =>
+  Emotion.injectGlobal(
+    [(selector, Emotion.makeDict(rules))]
+    ->Js.Dict.fromList
+    ->Js.Json.object_,
+  );
 
 let insertRule = raw => Emotion.rawInjectGlobal(raw);
 
@@ -391,7 +393,21 @@ type length = [
   | `zero
 ];
 
-type gridLength = [ length | `fr(float) | `minContent | `maxContent];
+type repeatValue = [ | `autoFill | `autoFit | `n(int)];
+
+let repeatValueToJs =
+  fun
+  | `autoFill => "auto-fill"
+  | `autoFit => "auto-fit"
+  | `n(x) => x->string_of_int;
+
+type gridLength = [
+  length
+  | `fr(float)
+  | `minContent
+  | `maxContent
+  | `repeat(repeatValue, gridLength)
+];
 
 let string_of_length_cascading =
   fun
@@ -757,7 +773,7 @@ let paddingRight = x => d("paddingRight", string_of_length(x));
 let paddingTop = x => d("paddingTop", string_of_length(x));
 let paddingBottom = x => d("paddingBottom", string_of_length(x));
 
-let string_of_dimension =
+let rec string_of_dimension =
   fun
   | `auto => "auto"
   | `calc(`add, a, b) =>
@@ -781,7 +797,9 @@ let string_of_dimension =
   | `fr(x) => string_of_float(x) ++ "fr"
   | `zero => "0"
   | `minContent => "min-content"
-  | `maxContent => "max-content";
+  | `maxContent => "max-content"
+  | `repeat(n, x) =>
+    "repeat(" ++ repeatValueToJs(n) ++ ", " ++ string_of_dimension(x) ++ ")";
 
 let width = x => d("width", string_of_dimension(x));
 let maxWidth = x => d("maxWidth", string_of_dimension(x));
@@ -815,8 +833,8 @@ let gridAutoFlow = direction =>
 let string_of_dimensions = dimensions =>
   dimensions |> List.map(string_of_dimension) |> String.concat(" ");
 
-let gridTemplateColumns = dimensions =>
-  d("gridTemplateColumns", string_of_dimensions(dimensions));
+let gridTemplateColumns =
+  dimensions => d("gridTemplateColumns", string_of_dimensions(dimensions));
 
 let gridTemplateRows = dimensions =>
   d("gridTemplateRows", string_of_dimensions(dimensions));

Rule list order should be preserved after Emotion.makeDict

On current master, the order of properties is backwards from how it ultimately ends up in CSS.

  Css.[
    background(red),
    borderBottom(px(5), solid, black),
    width(px(50)),
    height(px(50)),
    margin(px(10)),
];
margin: 10px;
height: 50px;
width: 50px;
border-bottom: 5px solid #000000;
background: #FF0000;

Presumably this is because here we reverse the rule list before passing it into the JS object creator.

I noticed this because of the interaction between properties like border and border left. Order matters in this case.

Changing the order to match existing CSS was part of #92, but was stripped out with the merge changes I'd added. I've been using my own fork because of this, but I'd like to have it patched upstream. What better than a major release?

fontSize does not support absolute and relative sizes

According to the formal syntax for font-size, it's supposed to support absolute and relative sizes like large, larger, etc.

Would you agree that bs-css needs types for absolute and relative sizes so that they can be supported by fontSize, or have you already thought through this?

I think typed css in reason has lots of potential, and that this project would flourish with more contributors and users. I'm still learning the language but I'll try and dedicate time to this.

backgroundPosition(align, [align])

The current implementation of backgroundPosition looks like this:

let backgroundPosition = (x, y) =>
  d("backgroundPosition", string_of_length(x) ++ " " ++ string_of_length(y));

Unfortunately, this prevents things like backgroundPosition: center;. Is it possible to support string_of_align() here as well?

Selectors resolving to [object Object]

v6.1.0, though I believe this affected v5 as well.

I'm having trouble using selectors:

  let table = style([
    selector("span", [
      margin(unit(1.0))
    ])
  ]);
<div className=Styles.table>

This results in:

screen shot 2018-02-01 at 4 05 42 pm

Any ideas on how I can troubleshoot?

Thanks for a great project!

Compose

Is there a good way to compose multiple styles?

Losing styles when merging nested selectors

We're building components by composing different styles. However, if we use the same sub-selector in two places, only one will be compiled. Eg:

let buttonStyles = [
  padding(px(5)),
  media("(min-width: 768px)", [
    padding(px(10)),
  ]),
]

let typographyStyles = [
  fontSize(px(14)),
  media("(min-width: 768px)", [
    fontSize(px(16)),
  ]),
]

let Button = style(merge([
  buttonStyles,
  typographyStyles,
]))

In this case, only the buttonStyles media query works. This happens for any sub-selector, eg &:hover, &:focus, [dir=rtl] &.

Looking through the implementation, it seems like this issue is quite baked in, with how bs-css abstracts glamor objects as reason lists.

The example above may be arbitrary, but IMO a big draw for CSS-in-JS, and glamor especially, is composability. This bug and abstraction break it quite severely.

Wrong value for minWidth/maxWidth

We have

let minWidth: [ length | `auto] => rule;
let maxWidth: [ length | `auto] => rule;

"auto" is a valid keyword value for "min-width", but invalid or "max-width".
"none" is a missing keyword value for "max-width".
So we should have

let minWidth: [ length | `auto] => rule;
let maxWidth: [ length | `none] => rule;

CSS grid not defined

Hello!

grid is a valid value for display, but it does not seem to be defined.

Would you accept a PR adding this?

Thanks,
Louis

Looking for (co)maintainers

First of all Thanks to everyone who are using and or contributing to bs-css!
I am sorry that it often takes a while before I get to answer issues, or review pull requests.
Between Baby and startup I dont have much time on my hands.

If any of you are using bs-css and would like to help maintain the project (answer issues, review/merge PR's) I would really appreciate it.
I will ofc still be here as much as i can.

Colon-like infix operator

I know most people don't like operators, but since it's DSL, I wanted to share idea.
We have this fat and ugly operator ( @@ ), that is perfect for reducing number of parentheses on function call, so instead of this:

let card = style([
  display(flexBox),
  flexDirection(column), 
  alignItems(stretch),
  backgroundColor(white),
]); 

we get this:

let card = style([
  display @@ flexBox,
  flexDirection @@ column, 
  alignItems @@ stretch,
  backgroundColor @@ white,
]); 

Which looks a bit nicer, but far from perfect.
We can define a better operator, that behaves exactly like ( @@ ), but looks more CSS-like and lightweight:

let card = style([
  display^: flexBox,
  flexDirection^: column, 
  alignItems^: stretch,
  backgroundColor^: white,
]); 

We can define it like this:

let ( ^: ) = ( @@ );

Or like this:

external ( ^: ) : ('a => 'b) => 'a => 'b = "%apply";

What is the way of generating (min-width: 960px) with bs-css

Hi folks,

I was using Css.media(string, Css.rule) and wanted to compute (min-width: 960px) with bs-css.

Initially my thought was that was possible because internally we have string_of_length, we also have minWidth.
After trying a bit I did not found a way to do that.

Thank you for wrapping Glamor.

This is my first css in js (reason actually) experience.

DSL macro expansion

Hi guys, thanks for creating such a beginner-friendly CSS tool for Reason beginners like myself.

Are there any plans to improve the verbosity of the DSL through something like a macro expansion extension to Reason? https://github.com/cyrus-/relit

To a beginner, it feels like the holy grail of css-in-Reason is to write in plain (or nearly plain) css. Something like:

module Styles = {
  open Css_notation;

  let card = $css `
    display: flexbox;
    flex-direction: column;
    align-items: stretch;
    background-color: white;
    box-shadow: 3px 5px rgba(0, 0, 0, 0.3);
    padding: ${Theme.basePadding};
  `;
};

I'm not sure what's technologically feasible here, so I'd be really interested to know whether this is worth looking into or just a total dead end. Thanks.

Possible to use multiple background layers?

I'm trying to an image url on top of a linear gradient as a background, but it seems like the type system is limiting me to one or the other. Is there a way to use multiple background layers with bs-css?

E.g. generate something like this:

background: url("../img/bg-pattern.png"), linear-gradient(to left, #7b4397, #dc2430);

Fraction unit (fr) for grid

I can't use fr unit for gridTemplateColumns/gridTemplateRows.
e.g.

gridTemplateColumns([fr(1), fr(2)]),   // <-- error

Error output

This has type:
    [> `fr(float) ]
  But somewhere wanted:
    [ `auto
    | `calc([ `add | `sub ], Css.length, Css.length)
    | `ch(float)
    | `cm(float)
    | `em(float)
    | `ex(float)
    | `mm(float)
    | `percent(float)
    | `pt(int)
    | `px(int)
    | `rem(float)
    | `vh(float)
    | `vmax(float)
    | `vmin(float)
    | `vw(float)
    | `zero ]
    at <anonymous>nt type does not allow tag(s) `fr

Is fr maybe missing from function string_of_dimension?

Expose `string_of` functions

It might be a good idea to expose the string_of_length and similar functions as sometimes they are needed. Normally when you're down to the definition level and you have constants defined elsewhere as length. At the moment they are hidden from the interface and I literally grabbed them from the source. But this way if bs-css changes my forked functions will get out of sync.
These functions are also useful when you have a theme and you need to add some inline styles.
I would just alias the functions within a Utils submodule. I can make a pull request if you think it's a good idea

Media queries

Can't seem to get them working, are there any examples of how to use it?

Proposal: A better type system for values

I've been toying a bit with the type system to get value types to compose better. This will make declarations more concise, but will also solve some issues that I don't think can be solved with the current approach. AND I actually think the errors this produces is better.

The problem

CSS is typed as lots of nested unions. These unions are currently modeled in one of two ways:

  1. As string-backed abstract types, e.g. cssunit, color. These are efficient and concise, but do not nest and need to be uniquely named.
  2. As ordinary vairants, e.g. background. These nest and do not need to be uniquely named, but are inefficient and verbose.

A common problem for both approaches is that they need to enumerate every single possible value of that type, which for 1. is practically impossible due to the need for unique names, and for 2. makes the implementation very verbose and repetitive.

More specifically, the practical problem is with implementing these CSS features:

  1. The universal values, inherit, initial and unset, which should be appllicable to every css property.
  2. Nested unions can become pretty verbose, either when used or when implemented (or a bit of both, as it is now). For example, a DRY implementation of background would have usage look like background(Image(Url(url("http://...")))). Alternatively it can be "flattened" to justbackground(Url("http://...")), but at the cost of needing to explicitly enumerate and convert all possible values in the implementation of each property.

Proposal

By using a phantom polymorphic variant type, we can model this more precisely.

This is what it could look like in use:

Css.(style([
  background(white),
  background(url("http://...")),
  background(linearGradient(...)),
  color(unset),
]));

Compared to today:

Css.(style([
  background(Color(white)),
  background(Image("http://...")),

  /* gradients currently aren't valid images, so including them would require adding another
   * level (which would also make the url declaration above more verbose), or alternatively
   * another variant constructor if flattened
   */
  background(Image(Gradient(linearGradient(...)))),

  /* not implemented today, but could be hacked together to look like this and be somewhat
   * type-safe
   */
  unset(color),
]));

Error would look like this:
2017-12-18-120530_312x148_scrot

Implementation

Time for magic. Let's first look at the interface:

  /* The type of all css values */
  type value('a);
  
  /* [`color] is the type of a polymorphic variant with a single constructor, `color */
  type color = value([`color]);
  let white: color;
  
  /* The aliases aren't strictly necessary, but gives nicer error messages */
  type url = value([`url]);
  let url: string => url;
  
  /* [< `color ...] means we'll accept any polymorphic variant type containing a subset of
   * these constructors. So value([`color]) is good, as would value([`color | `url]) be,
   * but not value([`color | `length])
   */
  type background('a) = value([< `color | `url | `gradient] as 'a);
  let background: background('a) => rule;

To implement it, we'll define a couple of helpers to avoid blind casting magic and ensure what we put in and get out are actually strings, as expected:

  external makeValue : string => value(_) = "%identity";
  external getValue : value(_) => string = "%identity";

We'll also represent the rule as just a tuple for simplicity:

type rule = (string, string);

And then the meat of the implementation:

  type value('a);
  
  type color = value([`color]);
  let white = makeValue("white");
  
  type url = value([`url]);  
  let url = url => makeValue({j|url($url)|j});
  
  type background('a) = value([< `color | `url | `gradient] as 'a);
  let background = value => ("background", getValue(value));

A playground with this code, as well as an example of how to define a universal value

Conclusion

More testing is of course needed to ensure there aren't any problems when things get more complex, or if CSS does something super weird that doesn't fit this model either. But I think this approach is worth exploring further. If everything works out it's looking to be more concise, flexible, efficient and give better errors, but at the cost of making the implementation a bit harder to understand.

Support for `inherit` value

Inherit is a useful value with properties like borderRadius, borderColor, fontSize, etc...

If there is a way to do this already, would you mind pointing me in the right direction?

lineheight unit

Today, lineHeight has the type float => rule
But lineHeight is supposed to be able to receive pixel, rem, em etc., in addition to the float.

It would be better if lineHeight had the following type: [ lenght | `abs(float) ]

boxSizing needs cascading values

Of course a lot of other properties need this as well, but right now I need it for boxSizing! πŸ˜„
I’m writing some base css for my app and want this rule:
*, *::before, *::after { box-sizing: inherit; }

I want to be able to do it cleanly like so:
global("*, *::before, *::after", [boxSizing(`inherit)])

But right now I have to do:
insertRule("*, *::before, *::after { box-sizing: inherit; }")

SSR?

With this support server-side rendering?

Can't use it as a library

[email protected] is dependent on bs-platform@^3.0.0 but it is published with js files compiled with the 2.2.2 version.
The published js files are still using Pervasives.string_of_int that doesn't exist anymore in bs 3.3.0.
This is breaking my code when I use it in a transitive dependency.

inherit/unset values

I'm trying to add these values to the different properties, but it's a very long work to add it to every css prop.

  1. I'd like to know what are the most important properties to start with, and focus on these first.
  2. I also have a problem when using inherit because it's a keyword. I'm using inherit_ right now, but I'd like to know if someone has a better suggestion.

thanks.

Should we add generated js files to .gitignore?

@giraud what do you think about removing these files from git?

The benefits, I think, are

  • Smaller diffs and PRs
  • Easier time merging

But I can see that adding the compiled JS means bs-css's users can

  • try the example/index page without building
  • get a feel for how heavy the library code is without node_module dependencies

Update README with v8 changes

Changes:

  • Emotion is now the backing library. If you're using tools like browserslist, you should see less unnecessary autoprefixing. #94
  • merge no longer merges a list(list(rule)) and instead only merges list(string) into a string. If you need the old list behavior, List.concat has you covered. #97
  • Rule lists are applied in the order they are provided instead of reversed like they were in v7. #96
  • Font weight now requires the use of the num polymorphic variant instead of just ints. #98

lineHeight unit

What unit to use for lineHeight? I'm trying to pass 1.3, but px requires whole numbers, what unit should be used? Not even sure if it should have been px as in css we don't add px to the end of the value.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.