Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fdietze committed Dec 15, 2022
1 parent 741b42f commit 2cb1d4b
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 11 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ inThisBuild(

val versions = new {
val outwatch = "1.0.0-RC13"
val colibri = "0.7.8"
val colibri = "0.7.8+10-e7dd4fb2-SNAPSHOT" // https://github.com/cornerman/colibri/pull/275
val funPack = "0.3.2"
val scalaTest = "3.2.12"
}
Expand Down
20 changes: 20 additions & 0 deletions cypress/e2e/spec.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,24 @@ describe('Form interactions', () => {
cy.get('.value').should('have.text', 'Cons(Cat(,4),Cons(Dog(,true),Nil))')
})
})

it('backup entered values (sealed trait)', () => {
cy.get('.Pet').within(($form) => {
cy.get('select').select('Cat')
cy.contains('tr', 'name:').find('input[type="text"]').clear().type('Tiger')
cy.get('select').select('Dog') // select different case
cy.get('select').select('Cat') // back to previously selected case
cy.get('.value').should('have.text', 'Cat(Tiger,4)') // test default value
})
})

it('backup entered values (Option[Int])', () => {
cy.get('.Option\\[Int\\]').within(($form) => {
cy.get('input[type="checkbox"]').check()
cy.get('input[type="text"]').clear().type('15')
cy.get('input[type="checkbox"]').uncheck()
cy.get('input[type="checkbox"]').check()
cy.get('.value').should('have.text', 'Some(15)')
})
})
})
4 changes: 4 additions & 0 deletions demo/src/main/scala/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ object Pet {
case class Cat(name: String, legs: Int = 4) extends Pet
}

case class Address(city: String, street: String)
case class Company(name: String, address: Option[Address])

case class Tree(value: Int = 2, children: Seq[Tree])

sealed trait BinaryTree
Expand Down Expand Up @@ -51,6 +54,7 @@ object Main extends Extras {
formFrame[(Int, String, Option[Long])]("Tuple"),
formFrame[Person]("Person"),
formFrame[Pet]("Pet"),
formFrame[Company]("Company"),
formFrame[Tree]("Tree"),
formFrame[BinaryTree]("BinaryTree"),
formFrame[GenericLinkedList[Pet]]("GenericLinkedList[Pet]"),
Expand Down
53 changes: 46 additions & 7 deletions formidable/src/main/scala-2/Form-Scala2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package formidable

import outwatch._
import colibri.reactive._
import scala.collection.mutable

import magnolia1._

Expand All @@ -15,13 +16,23 @@ trait FormDerivation {
override def default: T = ctx.construct(param => param.default.getOrElse(param.typeclass.default))

override def render(state: Var[T], config: FormConfig): VModifier = Owned.function { implicit owner =>
val subStates: Var[Seq[Any]] =
println(s"product[${ctx.typeName.short}]: rendering")
val combinedFieldState: Var[Seq[Any]] =
state.imap[Seq[Any]](seq => ctx.rawConstruct(seq))(_.asInstanceOf[Product].productIterator.toList)

subStates.sequence.map { subStates =>
combinedFieldState.sequence.map { fieldStates =>
println(
s"product[${ctx.typeName.short}]: state changed: ${ctx.parameters
.map(_.label)
.zip(fieldStates.map(_.now()))
.map { case (label, value) =>
s"$label: $value"
}
.mkString(",")}",
)
config.labeledFormGroup(
ctx.parameters
.zip(subStates)
.zip(fieldStates)
.map { case (param, subState) =>
val subForm = ((s: Var[param.PType], c) => param.typeclass.render(s, c))
.asInstanceOf[(Var[Any], FormConfig) => VModifier]
Expand All @@ -38,18 +49,46 @@ trait FormDerivation {
defaultSubtype.typeclass.default
}
override def render(selectedValue: Var[T], config: FormConfig): VModifier = Owned.function { implicit owner =>
println(s"sum[${ctx.typeName.short}]: rendering")

val valueBackup = mutable.HashMap.empty[Subtype[Form, T], T].withDefault(_.typeclass.default)
val selectedSubtype: Var[Subtype[Form, T]] =
selectedValue.imap[Subtype[Form, T]](subType => subType.typeclass.default)(value => ctx.split(value)(identity))
selectedValue.imap[Subtype[Form, T]](subtype => valueBackup(subtype)) { value =>
val subtype = ctx.split(value)(identity)
valueBackup(subtype) = value
subtype
}

val subFormBackup = mutable.HashMap.empty[Subtype[Form, T], (Var[T], VModifier)]

config.unionSubform(
config.selectInput[Subtype[Form, T]](
options = ctx.subtypes,
selectedValue = selectedSubtype,
show = subtype => subtype.typeName.short,
),
subForm = selectedValue.map { value =>
ctx.split(value) { sub =>
VModifier.when(value.isInstanceOf[T])(sub.typeclass.asInstanceOf[Form[T]].render(selectedValue, config))
subForm = selectedValue.map { newValue =>
println(s"sum[${ctx.typeName.short}]: state changed: $newValue")
ctx.split(newValue) { subtype =>

val (formState, form) = subFormBackup.getOrElseUpdate(
key = subtype,
defaultValue = {
val formInstance = subtype.typeclass.asInstanceOf[Form[T]]
val state = Var(formInstance.default)
val form = formInstance.render(state, config) // TODO: this is lazy and always re-rendered....
(state, form)
},
)

println(subFormBackup.size)

formState.set(newValue)

VModifier(
VModifier.managedEval(formState.observable.unsafeForeach(selectedValue.set)),
form,
)
}
},
)
Expand Down
4 changes: 3 additions & 1 deletion formidable/src/main/scala/FormConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ trait FormConfig {
div(display.flex, VModifier.style("gap") := "0.5rem", subForms)
def labeledFormGroup(subForms: Seq[(String, VModifier)]): VModifier =
table(
subForms.map { case (label, subForm) => tr(td(b(label, ": "), verticalAlign := "top"), td(subForm)) }
subForms.map { case (label, subForm) =>
tr(td(b(label, ": "), verticalAlign := "top"), td(subForm))
}
)

def formSequence(subForms: Seq[VModifier], addButton: VModifier): VModifier =
Expand Down
9 changes: 7 additions & 2 deletions formidable/src/main/scala/instances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,15 @@ package object formidable {
implicit def optionForm[T: Form]: Form[Option[T]] = new Form[Option[T]] {
def default = None
def render(state: Var[Option[T]], config: FormConfig) = Owned {
var valueBackup: Option[T] = None
val checkboxState = state.transformVar[Boolean](_.contramap {
case true => Some(Form[T].default)
case true =>
valueBackup.orElse(Some(Form[T].default))
case false => None
})(_.map(_.isDefined))
})(_.map { value =>
value.foreach(some => valueBackup = Some(some))
value.isDefined
})

config.withCheckbox(
subForm = state.sequence.map(
Expand Down

0 comments on commit 2cb1d4b

Please sign in to comment.