Skip to content
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

Naming the css units class? #4

Closed
Zaid-Ajaj opened this issue Jul 22, 2019 · 8 comments
Closed

Naming the css units class? #4

Zaid-Ajaj opened this issue Jul 22, 2019 · 8 comments

Comments

@Zaid-Ajaj
Copy link
Owner

I am not what to call the helper class that contains the different CSS units like px and rem. I have now called it length, implemented like this:

[<Erase>]
type length =
    static member inline px(value: int) : ICssUnit = unbox ((unbox<string>value) + "px")
    static member inline px(value: double) : ICssUnit = unbox ((unbox<string>value) + "px")
    static member inline cm(value: int) : ICssUnit = unbox ((unbox<string>value) + "cm")
    static member inline cm(value: double) : ICssUnit = unbox ((unbox<string>value) + "cm")
    /// etc. etc.

and you can use it like this:

style.margin (length.px 20)

but I am not sure if length is a good name for it, what do you think @MangelMaxime?

@MangelMaxime
Copy link
Contributor

Why not call it unit? Which is a more generic name.


Another option is to provide direct function in order to have a lightweight syntax:

let px (value  : float) : ICssUnit = unbox ((unbox<string>value) + "px")

// Usage
px 2.0

The problem is that we lose the overload support for conciseness.

In the future, when dotnet/fsharp#6805 is available, it should be possible to do:

type System.Int32 with
    static member inline toPixel (value : int) =
        (unbox<string> value + "px")

let inline pixel (value : ^a) =
    (^a : (static member inline toPixel: ^a -> string) (value))

let size = pixel 2 // this gives 2 + "px" -> "2px"

A possible workaround is:

type ToPixel = ToPixel with
    static member inline ($) (ToPixel, value: int  ) = unbox<string> value + "px"
    static member inline ($) (ToPixel, value: float) = unbox<string> value + "px"

let inline pixel value = ToPixel $ value 

let pixelFromInt = pixel 2
let prixelFromFloat = pixel 2.

But this version generates a much more verbose JavaScript:

import { union } from "fable-library/Reflection.js";
import { declare, Union } from "fable-library/Types.js";
export const ToPixel = declare(function DragAndDrop_ToPixel(tag, name, ...fields) {
  Union.call(this, tag, name, ...fields);
}, Union);
export function ToPixel$reflection() {
  return union("DragAndDrop.ToPixel", [], ToPixel, () => ["ToPixel"]);
}
export const pixelFromInt = (() => {
  const arg0 = new ToPixel(0, "ToPixel");
  return 2 + "px";
})();
export const prixelFromFloat = (() => {
  const arg0$$1 = new ToPixel(0, "ToPixel");
  return 2 + "px";
})();

It's possible to limit the verbosity by not inlining the ($) methods:

import { union } from "fable-library/Reflection.js";
import { declare, Union } from "fable-library/Types.js";
export const ToPixel = declare(function DragAndDrop_ToPixel(tag, name, ...fields) {
  Union.call(this, tag, name, ...fields);
}, Union);
export function ToPixel$reflection() {
  return union("DragAndDrop.ToPixel", [], ToPixel, () => ["ToPixel"]);
}
export function ToPixel$$$op_Dollar$$Z45FE3DAA(_arg1, value) {
  return value + "px";
}
export function ToPixel$$$op_Dollar$$49846331(_arg2, value$$1) {
  return value$$1 + "px";
}
export const pixelFromInt = ToPixel$$$op_Dollar$$Z45FE3DAA(new ToPixel(0, "ToPixel"), 2);
export const prixelFromFloat = ToPixel$$$op_Dollar$$49846331(new ToPixel(0, "ToPixel"), 2);

Side note:

Also, because you use unbox<string> you are relying entirely on JavaScript behaviour and don't do a F# cast.

This an interesting usage in order to reduce bundle size and have a small optimisation.

(unbox<string> 2) + "px"  
// generates: 2 + "px";

string 2 + "px"
// genertes: int32ToString(2) + "px";

I just wanted to note this behaviour as it's becoming an implementation detail of Feliz now. So using unbox<string> seems indeed the right move, as long as value type is a compatible type/native JavaScript type.

@MangelMaxime
Copy link
Contributor

Another implementation possible is:

type Utilities = Utilities with
    static member inline toPixel (value: int  ) = unbox<string> value + "px"
    static member inline toPixel (value: float) = unbox<string> value + "px"

let inline call (_:^Utilities) value = ((^Utilities or  ^a) : (static member inline toPixel: ^a -> string) (value))
let inline pixel value = call Utilities value

let pixelFromInt = pixel 2
let prixelFromFlaot = pixel 2.2

This generates:

import { union } from "fable-library/Reflection.js";
import { declare, Union } from "fable-library/Types.js";
export const Utilities = declare(function DragAndDrop_Utilities(tag, name, ...fields) {
  Union.call(this, tag, name, ...fields);
}, Union);
export function Utilities$reflection() {
  return union("DragAndDrop.Utilities", [], Utilities, () => ["Utilities"]);
}
export const pixelFromInt = (() => {
  const _arg1 = new Utilities(0, "Utilities");

  return 2 + "px";
})();
export const prixelFromFlaot = (() => {
  const _arg1$$1 = new Utilities(0, "Utilities");

  return 2.2 + "px";
})();

@Zaid-Ajaj
Copy link
Owner Author

Thanks @MangelMaxime for the suggestions, I cannot use unit because it would clash with functions returning unit and the user would have to specify which unit type has to be returned Feliz.unit vs Microsoft.FSharp.Core.unit

Also although I like an overloaded pixel function using srtp, the problem is that the function becomes globally available and you have to remember the names of these functions instead of remembering to dot through one type to get the possible options

Alright, I think I will keep it as is for now, thanks again for the input Maxime ❤️

@MangelMaxime
Copy link
Contributor

MangelMaxime commented Jul 22, 2019

Ah yes right.

Perhaps size or sizeIn then?

  • size.px
  • sizeIn.px

I am not convinced with sizeIn but still wanted to mention it :)

Also although I like an overloaded pixel function using srtp, the problem is that the function becomes globally available and you have to remember the names of these functions instead of remembering to dot through one type to get the possible options

Indeed, but we can have a separate library with this syntax in it as Feliz seems easier to extends. :) If I prefer that this syntax perhaps I will work on it. Will first wait to Feliz to bo done :)

@Zaid-Ajaj
Copy link
Owner Author

I thought of size too and it looks nice for font-size but doesn't make sense for width because usually size is associated with two dimensions (height and width, i.e. size of a rectangle) where length is one-dimensional and most numbers in css are one-dimensional too

@NatElkins
Copy link

Would dotnet/fsharp#6807 help with this? I think then you could open length (or similar) and get access to the overloads without having to type out the full name of the type/class.

@MangelMaxime
Copy link
Contributor

@NatElkins I think that when it will be available yes it should help because I have also linked this PR for #2 (comment)

And the problem is similar I think.

@Zaid-Ajaj
Copy link
Owner Author

@NatElkins Actually at this point I wouldn't recommend opening types such as length, style or Html because you lose the ability to "dot through" the static type so that don't have to remember anything

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants