scala-dom-types
scala-dom-types copied to clipboard
Add flow-relative CSS properties
Such as:
- margin-block, margin-block-start, margin-block-end
- margin-inline, margin-inline-start, margin-inline-end
- padding-block, padding-block-start, padding-block-end
- padding-inline, padding-inline-start, padding-inline-end
- inset
- inset-block, inset-block-start, inset-block-end
- inset-inline, inset-inline-start, inset-inline-end
- etc
For example, margin-block-start is basically equivalent to margin-top except it's aware of flow direction and text direction.
There's more to these than just dimensional props, see this spec – note the TOC on the left, the new values for text-align, the new logical keyword, etc.
cc @Lasering
Main question is how to encode these props. We could spell out each property like we do for e.g. marginTop, marginBottom, etc. but then the myriad of new props would "pollute" autocomplete.
Few people use these new props (and actually test their websites to make sure they work with the different text directions), so I'm not sure if that's a good tradeoff. And in general I loathe having to define repetitive props.
Alternatively, we could make those props nested, such as margin.blockStart or borderColor.inlineEnd. We would also need to add old ones like margin.top for consistency I guess. I don't think I'm ready to completely replace the existing props like marginTop with margin.top, both options might need to co-exist for a while.
Regarding the logical keyword, I think its best to not include it for now since issue 1 on the spec clearly defines it as unstable.
I don't see the autocomplete "pollution" as a problem but rather as a feature it helps with the discoverability. But I do understand why it isn't the most good looking option.
Making the props nested could be a very elegant solution. Here is a very rough idea (does not handle things like border-block-start-width):
object Setter {
def instance[T](name: String): Setter[T] = (value: T) => s"$name: $value"
}
trait Setter[T] {
def :=(value: T): String
}
class TopBottomLeftRight[T](prefix: String) {
val top: Setter[T] = Setter.instance(s"$prefix-top")
val bottom: Setter[T] = Setter.instance(s"$prefix-bottom")
val left: Setter[T] = Setter.instance(s"$prefix-left")
val right: Setter[T] = Setter.instance(s"$prefix-right")
// (top and bottom, left and right).
def :=(t: (T, T)): String = s"$prefix: ${t._1} ${t._2}"
// (top, left and right, bottom).
def :=(t: (T, T, T)): String = s"$prefix: ${t._1} ${t._2} ${t._3}"
// (top, right, bottom, left)
def :=(t: (T, T, T, T)): String = s"$prefix: ${t._1} ${t._2} ${t._3} ${t._4}"
}
class BlockInline[T](prefix: String) extends Setter[T] {
override def :=(value: T): String = s"$prefix: $value"
// (start, end)
def :=(t: (T, T)): String = s"$prefix: ${t._1} ${t._2}"
val start: Setter[T] = Setter.instance(s"$prefix-start")
val end: Setter[T] = Setter.instance(s"$prefix-end")
}
class FourSidesProperty[T](prefix: String) extends TopBottomLeftRight[T](prefix) with Setter[T] {
override def :=(value: T): String = s"$prefix: $value"
val block: BlockInline[T] = new BlockInline(s"$prefix-block")
val inline: BlockInline[T] = new BlockInline(s"$prefix-inline")
}
@main def main(): Unit =
val margin: FourSidesProperty[Int] = new FourSidesProperty[Int]("margin")
val padding: FourSidesProperty[Int] = new FourSidesProperty[Int]("padding")
println(margin := 5)
println(margin := (5, 25, 5))
println(margin.top := 5)
println(margin.block := 5)
println(margin.block.start := 5)
println(margin.inline.end := 5)
println(padding.inline.end := 5)
margin: 5
margin: 5 25 5
margin-top: 5
margin-block: 5
margin-block-start: 5
margin-inline-end: 5
padding-inline-end: 5
Even the documentation could be easily done via interpolation.