diff --git a/formidable/src/main/scala-2/Form-Scala2.scala b/formidable/src/main/scala-2/Form-Scala2.scala index 304259d..85a25df 100644 --- a/formidable/src/main/scala-2/Form-Scala2.scala +++ b/formidable/src/main/scala-2/Form-Scala2.scala @@ -1,7 +1,6 @@ package formidable import outwatch._ -import outwatch.dsl._ import colibri.reactive._ import magnolia1._ @@ -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) @@ -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 + ) } } diff --git a/formidable/src/main/scala-3/Form-Scala3.scala b/formidable/src/main/scala-3/Form-Scala3.scala index 614606b..31ad02e 100644 --- a/formidable/src/main/scala-3/Form-Scala3.scala +++ b/formidable/src/main/scala-3/Form-Scala3.scala @@ -1,7 +1,6 @@ package formidable import outwatch._ -import outwatch.dsl._ import colibri.reactive._ import magnolia1._ @@ -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) @@ -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 + ) } } diff --git a/formidable/src/main/scala/FormConfig.scala b/formidable/src/main/scala/FormConfig.scala index 56fad02..1996580 100644 --- a/formidable/src/main/scala/FormConfig.scala +++ b/formidable/src/main/scala/FormConfig.scala @@ -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 {}