Skip to content

Commit

Permalink
configurable subtype selection (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
fdietze committed Dec 11, 2022
1 parent ea0a4f4 commit f8b95e1
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 35 deletions.
30 changes: 13 additions & 17 deletions formidable/src/main/scala-2/Form-Scala2.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package formidable

import outwatch._
import outwatch.dsl._
import colibri.reactive._

import magnolia1._
Expand All @@ -15,7 +14,7 @@ trait FormDerivation {
def join[T](ctx: CaseClass[Typeclass, T]): Form[T] = new Form[T] {
override def default: T = ctx.construct(param => param.default.getOrElse(param.typeclass.default))

override def render(state: Var[T], config: FormConfig): VModifier = Owned {
override def render(state: Var[T], config: FormConfig): VModifier = Owned.function { implicit owner =>
val subStates: Var[Seq[Any]] =
state.imap[Seq[Any]](seq => ctx.rawConstruct(seq))(_.asInstanceOf[Product].productIterator.toList)

Expand All @@ -38,26 +37,23 @@ trait FormDerivation {
val defaultSubtype = ctx.subtypes.find(_.annotations.exists(_.isInstanceOf[Default])).getOrElse(ctx.subtypes.head)
defaultSubtype.typeclass.default
}
override def render(state: Var[T], config: FormConfig): VModifier = Owned {
val labelToSubtype =
ctx.subtypes.view.map { sub => sub.typeName.short -> sub }.toMap
override def render(selectedValue: Var[T], config: FormConfig): VModifier = Owned.function { implicit owner =>

div(
select(
ctx.subtypes.map { subtype =>
option(
subtype.typeName.short,
selected <-- state.map(value => ctx.split(value)(_ == subtype)),
)
}.toSeq,
onChange.value.map(label => labelToSubtype(label).typeclass.default) --> state,
val selectedSubtype: Var[Subtype[Form, T]] =
selectedValue.imap[Subtype[Form, T]](subType => subType.typeclass.default)(value => ctx.split(value)(identity))

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

}
Expand Down
34 changes: 16 additions & 18 deletions formidable/src/main/scala-3/Form-Scala3.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package formidable

import outwatch._
import outwatch.dsl._
import colibri.reactive._

import magnolia1._
Expand All @@ -13,7 +12,7 @@ trait FormDerivation extends AutoDerivation[Form] {
override def join[T](ctx: CaseClass[Typeclass, T]): Form[T] = new Form[T] {
override def default: T = ctx.construct(param => param.default.getOrElse(param.typeclass.default))

override def render(state: Var[T], config: FormConfig): VModifier = Owned {
override def render(state: Var[T], config: FormConfig): VModifier = Owned.function { implicit owner =>
val subStates: Var[Seq[Any]] =
state.imap[Seq[Any]](seq => ctx.rawConstruct(seq))(_.asInstanceOf[Product].productIterator.toList)

Expand All @@ -35,26 +34,25 @@ trait FormDerivation extends AutoDerivation[Form] {
val defaultSubtype = ctx.subtypes.find(_.annotations.exists(_.isInstanceOf[Default])).getOrElse(ctx.subtypes.head)
defaultSubtype.typeclass.default
}
override def render(state: Var[T], config: FormConfig): VModifier = Owned {
val labelToSubtype =
ctx.subtypes.view.map { sub => sub.typeInfo.short -> sub }.toMap

div(
select(
ctx.subtypes.map { subtype =>
option(
subtype.typeInfo.short,
selected <-- state.map(value => ctx.choose(value)(_.subtype == subtype)),
)
}.toSeq,
onChange.value.map(label => labelToSubtype(label).typeclass.default) --> state,
override def render(selectedValue: Var[T], config: FormConfig): VModifier = Owned.function { implicit owner =>

val selectedSubtype: Var[SealedTrait.Subtype[Form, T, _]] =
selectedValue.imap[SealedTrait.Subtype[Form, T, _]](subType => subType.typeclass.default)(value =>
ctx.choose(value)(_.subtype),
)

config.unionSubform(
config.selectInput[SealedTrait.Subtype[Form, T, _]](
options = ctx.subtypes,
selectedValue = selectedSubtype,
show = subtype => subtype.typeInfo.short,
),
state.map { value =>
selectedValue.map { value =>
ctx.choose(value) { sub =>
VModifier.when(value.isInstanceOf[T])(sub.typeclass.asInstanceOf[Form[T]].render(state, config))
VModifier.when(value.isInstanceOf[T])(sub.typeclass.asInstanceOf[Form[T]].render(selectedValue, config))
}
},
): VModifier
)
}

}
Expand Down
16 changes: 16 additions & 0 deletions formidable/src/main/scala/FormConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ trait FormConfig {
validationMessage.map(_.map(msg => div(msg, color.red))),
): VModifier
}

def selectInput[T](options: Seq[T], selectedValue: Var[T], show: T => String): VModifier = {
select(
Owned.function { implicit owner =>
options.zipWithIndex.map { case (opt, ind) =>
option(dsl.value := ind.toString)(
show(opt),
selectedValue.map(sel => selected := opt == sel),
)
}
},
onChange.value.map(index => options(index.toInt)) --> selectedValue,
)
}

def unionSubform(selectForm: VModifier, subForm: VModifier) = div(selectForm, subForm)
}
object FormConfig {
val default: FormConfig = new FormConfig {}
Expand Down

0 comments on commit f8b95e1

Please sign in to comment.