Skip to content

Commit

Permalink
Refactor import statements (#213)
Browse files Browse the repository at this point in the history
* Refactor import statements
* Render product as table
* Bugfix: renderSelect in enumForm to update variable and sync parent
  • Loading branch information
cheleb authored Sep 27, 2024
1 parent 604b3ff commit 140eb45
Show file tree
Hide file tree
Showing 22 changed files with 618 additions and 405 deletions.
Binary file modified docs/_assets/images/simple-form.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 5 additions & 18 deletions docs/_docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,18 @@ libraryDependencies += "dev.cheleb" %%% "laminar-form-derivation-shared" % "{{ p
## Sample

```scala sc:nocompile
import com.raquo.laminar.api.L.*
import dev.cheleb.scalamigen.*

// Declare model case class
case class Cat(name: String, age: Int)
case class Dog(name: String, age: Int)

case class EitherSample(
either: Either[Cat, Dog],
optionalInt: Option[Int]
kind: Boolean = true
)

// Laminar variable binding
val eitherVar = Var(EitherSample(Left(Cat("Scala le chat", 6)), Some(1)))

val eitherVar = Var(Cat("Scala le chat", 6))
div(
// (1) Debug output of the model as soon as it changes.
child <-- eitherVar.signal.map { item =>
div(
s"$item"
s"$item" // (1) debug case class
)
},
// (2) Render the forms
Form.renderVar(eitherVar)
eitherVar.asForm // (2) form rendering
)

```

Will be rendered as:
Expand Down
8 changes: 0 additions & 8 deletions docs/_docs/test.md

This file was deleted.

56 changes: 56 additions & 0 deletions docs/_docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Usage

## Basic usage

```scala sc:nocompile
import dev.cheleb.scalamigen.*
```
This import is necessary to bring the implicit conversions into scope.

Now you can use the `asForm` method on any `Var` to render a form for the value it holds with double binding.

```scala sc:nocompile

case class Cat(name: String, age: Int)

val eitherVar = Var(Cat("Scala le chat", 6))

eitherVar.asForm // (2) form rendering

```

As long as the case class is built on elments that have a `Form[..]` instance, the form will be rendered correctly.

## Supported types

* `String`, `Int`, `Long`, `Double`, `Boolean`
* `LocalDate`
* `Option[A]`
* `List[A]`
* `Either[A, B]`
* `IronType[T, C]`
* `Positive`

## Customizing the form rendering

At anytime you can customize the form rendering by providing a `Form` instance for the type you want to render.

* `opaque type`
```scala sc:nocompile
opaque type Password = String
object Password:
def apply(password: String): Password = password
given Form[Password] = secretForm(apply) // (1) form instance

```
* `IronType`

```scala sc:nocompile
doubleGreaterThanEight: Double :| GreaterEqual[8.0]

given IronTypeValidator[Double, GreaterEqual[8.0]] =
_.toDoubleOption match
case None => Left("Not a number")
case Some(double) => double.refineEither[GreaterEqual[8.0]]

```
6 changes: 6 additions & 0 deletions docs/sidebar.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
index: index.html
subsection:
- title: Getting Started
page: getting-started.html
- title: Usage
index: usage.html
3 changes: 0 additions & 3 deletions examples/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
<link rel="icon" type="image/png" href="ui5-logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css" />
<!-- Loads the Quicksand font -->
<link href="https://fonts.googleapis.com/css?family=Quicksand:300,400,500,700" rel="stylesheet" />
<title>Demo Laminar SAP UI5 bindings</title>
<style>
.panel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ case class Sample(name: String, component: HtmlElement)

object App extends App {

val sample = Var(samples.sealedClasses.component)
val sample = Var(samples.either.component)

private def item(name: String) = SideNavigation.item(
_.text := name,
Expand Down
15 changes: 10 additions & 5 deletions examples/client/src/main/scala/samples/EitherSample.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package samples

import dev.cheleb.scalamigen.{*, given}

import dev.cheleb.scalamigen.*
import com.raquo.laminar.api.L.*

import com.raquo.airstream.state.Var

val either = {

@Panel("Either", false)
case class EitherSample(
either: Either[Cat, Dog],
primitiveEither: Either[Cat, String],
optionalInt: Option[Int]
)

val eitherVar = Var(EitherSample(Left(Cat("Scala le chat", 6)), Some(1)))
val eitherVar = Var(
EitherSample(
Left(Cat("Scala le chat", 6)),
Right("Forty two"),
Some(1)
)
)
Sample(
"Either", {

Expand Down
11 changes: 3 additions & 8 deletions examples/client/src/main/scala/samples/EnumSample.scala
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
package samples

import dev.cheleb.scalamigen.{*, given}

import com.raquo.laminar.api.L.*

import com.raquo.airstream.state.Var

import com.raquo.laminar.api.L
import dev.cheleb.scalamigen.*

val enums = {
enum Color(val code: String):
case Black extends Color("000")
case White extends Color("FFF")
case Isabelle extends Color("???")

case class Basket(color: Color, cat: Cat)

given colorForm: Form[Color] = enumForm(Color.values, Color.fromOrdinal)

case class Basket(color: Color, cat: Cat)

case class Cat(
name: String,
age: Int,
Expand Down
7 changes: 4 additions & 3 deletions examples/client/src/main/scala/samples/ListElement.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package samples

import dev.cheleb.scalamigen.{*, given}

import com.raquo.laminar.api.L.*
import dev.cheleb.scalamigen.*

val list = {
case class Person2(id: Int, name: String, age: Int)
Expand All @@ -11,11 +10,12 @@ val list = {
ints: List[Person2]
)

given (Person2 => Int) = _.id

val listPersonVar = Var(
ListElement(List(1, 2, 3).map(id => Person2(id, "Vlad", 20)))
)

given (Person2 => Int) = _.id
Sample(
"List",
div(
Expand All @@ -27,4 +27,5 @@ val list = {
listPersonVar.asForm
)
)

}
6 changes: 2 additions & 4 deletions examples/client/src/main/scala/samples/Persons.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package samples

import dev.cheleb.scalamigen.{*, given}

import com.raquo.laminar.api.L.*
import magnolia1.*
import dev.cheleb.scalamigen.*
import java.time.LocalDate

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.all.*
import java.time.LocalDate

val person = {
// Define some models
Expand Down
26 changes: 20 additions & 6 deletions examples/client/src/main/scala/samples/Sealed.scala
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
package samples

import dev.cheleb.scalamigen.{*, given}
import dev.cheleb.scalamigen.*

import com.raquo.laminar.api.L.*

import com.raquo.airstream.state.Var
import com.raquo.laminar.nodes.ReactiveHtmlElement

val sealedClasses = {

enum Color(val code: String):
case Black extends Color("000")
case White extends Color("FFF")
case Isabelle extends Color("???")

given colorForm: Form[Color] = enumForm(Color.values, Color.fromOrdinal)

sealed trait Animal

case class Horse(name: String, age: Int) extends Animal
case class Lama(name: String, age: Int, splitDistance: Int) extends Animal
case class Horse(name: String, age: Int, color: Color) extends Animal

case class Lama(
name: String,
age: Int,
splitDistance: Int,
color: Color = Color.Isabelle
) extends Animal

case class Otter(name: String, age: Int) extends Animal

case class Owner(name: String, pet: Animal)

Sample(
"Sealed", {

val eitherVar = Var(Owner("Agnes", Horse("Niram <3", 6)))
val eitherVar = Var(Owner("Agnes", Horse("Niram <3", 6, Color.Isabelle)))

case class Switcher(
name: String,
Expand All @@ -41,7 +55,7 @@ val sealedClasses = {

val switchers = List(
Switcher(
Horse("Niram", 13)
Horse("Niram", 13, Color.Black)
),
Switcher(
Lama("Lama", 3, 2)
Expand Down
5 changes: 1 addition & 4 deletions examples/client/src/main/scala/samples/SimpleSample.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package samples

import dev.cheleb.scalamigen.{*, given}

import com.raquo.laminar.api.L.*

import com.raquo.airstream.state.Var
import dev.cheleb.scalamigen.*

val simple = {
val eitherVar = Var(Cat("Scala le chat", 6))
Expand Down
4 changes: 1 addition & 3 deletions examples/client/src/main/scala/samples/Tree.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package samples

import dev.cheleb.scalamigen.{*, given}
import dev.cheleb.scalamigen.*

import com.raquo.laminar.api.L.*

import com.raquo.airstream.state.Var

val tree = {

enum Tree[+T]:
Expand Down
4 changes: 1 addition & 3 deletions examples/client/src/main/scala/samples/Validation.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package samples

import dev.cheleb.scalamigen.{*, given}
import dev.cheleb.scalamigen.*

import com.raquo.laminar.api.L.*

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.all.*

import com.raquo.airstream.state.Var

val validation = {

given Form[CurrencyCode] = stringForm(CurrencyCode(_))
Expand Down
12 changes: 11 additions & 1 deletion examples/client/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@ body {
margin: 0;
}

.srf-panel {

border: 1px solid #d9d9d9;
}

.srf-field {
padding-left: 1em;
padding-right: 1em;
}

/** Reducing the size of ui5 inputs of type number to only 100px */
ui5-input[type="Number"] {
width: 100px;
min-width: 100px;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package dev.cheleb.scalamigen

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.all.*

/** Typeclass for default values.
*
* This typeclass is used to provide default values for a given type. It is
Expand All @@ -19,3 +22,24 @@ trait Defaultable[A] {
*/
def label: String = default.getClass.getSimpleName()
}

object Defaultable {

/** Default value for Int is 0.
*/
inline given Defaultable[Int] with
def default = 0

/** Default value for String is "".
*/
inline given Defaultable[String] with
def default = ""

/** Default value for [Iron type Double
* positive](https://iltotore.github.io/iron/io/github/iltotore/iron/constraint/numeric$.html#Positive-0)
* is 0.0.
*/
inline given Defaultable[IronType[Double, Positive]] with
def default = 1.0.refineUnsafe[Positive]

}
Loading

0 comments on commit 140eb45

Please sign in to comment.