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

feat: add initial transform API #23

Merged
merged 12 commits into from
Sep 3, 2024
8 changes: 8 additions & 0 deletions sketch/src/sketch.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import sketch/internals/cache/setup as cache
import sketch/internals/style
import sketch/media.{type Query}
import sketch/size.{type Size}
import sketch/transform.{type Transform}

// Types

Expand Down Expand Up @@ -1983,10 +1984,17 @@ pub fn touch_action(value: String) {
property("touch-action", value)
}

/// `transform` will be turned into `transform_` in 4.0.0
pub fn transform(transform: String) {
property("transform", transform)
}

/// `transform_` uses `sketch.transform` to offer an enhanced API for CSS transforms
pub fn transform_(transform_args: List(Transform)) {
let transform_string = transform.to_string(transform_args)
property("transform", transform_string)
}

pub fn transform_box(transform_box: String) {
property("transform-box", transform_box)
}
Expand Down
33 changes: 33 additions & 0 deletions sketch/src/sketch/angle.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import gleam/float

pub opaque type Angle {
Deg(Float)
Rad(Float)
Grad(Float)
Turn(Float)
}

pub fn deg(value: Float) {
Deg(value)
}

pub fn rad(value: Float) {
Rad(value)
}

pub fn grad(value: Float) {
Grad(value)
}

pub fn turn(value: Float) {
Turn(value)
}

pub fn to_string(angle: Angle) {
case angle {
Deg(value) -> float.to_string(value) <> "deg"
Rad(value) -> float.to_string(value) <> "rad"
Grad(value) -> float.to_string(value) <> "grad"
Turn(value) -> float.to_string(value) <> "turn"
}
}
91 changes: 91 additions & 0 deletions sketch/src/sketch/transform.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import gleam/float
import gleam/list
import gleam/string
import sketch/angle.{type Angle}
import sketch/size.{type Size}

pub opaque type Transform {
Translate(Size, Size)
TranslateX(Size)
TranslateY(Size)
Scale(Float, Float)
ScaleX(Float)
ScaleY(Float)
Rotate(Angle)
SkewX(Angle)
SkewY(Angle)
}

fn transform_to_string(value: Transform) {
case value {
Translate(x, y) ->
"translate("
<> string.join([size.to_string(x), size.to_string(y)], ",")
<> ")"
TranslateX(x) -> "translateX(" <> size.to_string(x) <> ")"
TranslateY(y) -> "translateY(" <> size.to_string(y) <> ")"
Scale(x, y) ->
"scale("
<> string.join([float.to_string(x), float.to_string(y)], ",")
<> ")"
ScaleX(x) -> "scaleX(" <> float.to_string(x) <> ")"
ScaleY(y) -> "scaleY(" <> float.to_string(y) <> ")"
Rotate(ang) -> "rotate(" <> angle.to_string(ang) <> ")"
SkewX(x) -> "skewX(" <> angle.to_string(x) <> ")"
SkewY(y) -> "skewY(" <> angle.to_string(y) <> ")"
}
}

pub fn translate2(x: Size, y: Size) {
Translate(x, y)
}

/// `translate(x)` is `translate2(x, size.percent(0))`
pub fn translate(x: Size) {
translate2(x, size.percent(0))
}

pub fn translate_x(x: Size) {
TranslateX(x)
}

pub fn translate_y(y: Size) {
TranslateY(y)
}

pub fn scale2(x: Float, y: Float) {
Scale(x, y)
}

/// `scale(x)` is `scale2(x, x)`
pub fn scale(x: Float) {
scale2(x, x)
}

pub fn scale_x(x: Float) {
ScaleX(x)
}

pub fn scale_y(y: Float) {
ScaleY(y)
}

pub fn rotate(value: Angle) {
Rotate(value)
}

pub fn skew_x(x: Angle) {
SkewX(x)
}

pub fn skew_y(x: Angle) {
SkewY(x)
}

pub fn to_string(value: List(Transform)) {
case value {
[] -> "none"
transform_list ->
list.map(transform_list, transform_to_string) |> string.join(" ")
}
}
91 changes: 91 additions & 0 deletions sketch/test/transform_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import gleeunit/should
import sketch/angle
import sketch/size
import sketch/transform

pub fn translate_test() {
[transform.translate(size.px(10))]
|> transform.to_string
|> should.equal("translate(10.0px,0.0%)")
}

pub fn translate2_test() {
[transform.translate2(size.px(10), size.rem(3.0))]
|> transform.to_string
|> should.equal("translate(10.0px,3.0rem)")
}

pub fn translate_x() {
[transform.translate_x(size.px(10))]
|> transform.to_string
|> should.equal("translateX(10px)")
}

pub fn translate_y() {
[transform.translate_y(size.px(10))]
|> transform.to_string
|> should.equal("translateY(10px)")
}

pub fn scale2_test() {
[transform.scale2(10.0, 10.0)]
|> transform.to_string
|> should.equal("scale(10.0,10.0)")
}

pub fn scale_test() {
[transform.scale(10.0)]
|> transform.to_string
|> should.equal("scale(10.0,10.0)")
}

pub fn scale_x_test() {
[transform.scale_x(10.0)]
|> transform.to_string
|> should.equal("scaleX(10.0)")
}

pub fn scale_y_test() {
[transform.scale_y(10.0)]
|> transform.to_string
|> should.equal("scaleY(10.0)")
}

pub fn rotate_test() {
[transform.rotate(angle.rad(2.0))]
|> transform.to_string
|> should.equal("rotate(2.0rad)")
}

pub fn skew_x() {
[transform.skew_x(angle.rad(2.0))]
|> transform.to_string
|> should.equal("skewX(2.0rad)")
}

pub fn skew_y() {
[transform.skew_y(angle.rad(2.0))]
|> transform.to_string
|> should.equal("skewY(2.0rad)")
}

pub fn translate_equiv_test() {
let current = [transform.translate(size.px(10))] |> transform.to_string
let expected =
[transform.translate2(size.px(10), size.percent(0))]
|> transform.to_string

should.equal(current, expected)
}

pub fn scale_equiv_test() {
let current = [transform.scale(10.0)] |> transform.to_string
let expected = [transform.scale2(10.0, 10.0)] |> transform.to_string

should.equal(current, expected)
}

pub fn transform_none_test() {
transform.to_string([])
|> should.equal("none")
}
Loading