Open nadenf opened 5 years ago
That's a good idea! Slinky does support the children parameter, which can be defined in the case class Props
as children: ReactElement*
. When combined with the @react
annotation, Slinky will automatically move the children
parameter into a curried parameter to match the tags API.
If we take this example. It will not compile since you can't have default arguments with a *-parameter. However I am finding optional arguments to be very common amongst Javascript libraries.
@JSImport("@atlaskit/tag-group", "TagGroup")
@js.native
object ReactTagGroup extends js.Object
@react object TagGroup extends ExternalComponent {
case class Props(alignment: Option[String] = None, children: ReactElement*)
override val component = ReactTagGroup
}
Alternatively could you detect if I make it curried myself like this and not do anything. Currently I get an error, "could not find implicit value for parameter pw: slinky.core.ExternalPropsWriterProvider"
case class Props(alignment: Option[String] = None)(children: ReactElement*)
UPDATE: this solution now permits default arguments and still curries the children
@shadaj @nadenf correct me if I'm wrong, but in the example @nadenf linked, for this to work children
must be a function, with formProps
as the argument.
I got a very basic example working to demonstrate, but hopefully there's a cleaner solution:
object Form {
// here are the default args and curried children - gotta love the plain old Object approach
def apply(onSubmit: () => Unit, disabled: Boolean = false)(children: FormState => ReactElement): ReactElement =
AtlaskitForm(onSubmit, disabled, children)
}
@JSImport("@atlaskit/form", JSImport.Default)
@js.native
object AtlaskitFormLibrary extends js.Object
@react object AtlaskitForm extends ExternalComponent {
// see my comment below - children must be a function and cannot be just a functional ReactElement like you might expect
case class Props(onSubmit: () => Unit, isDisabled: Boolean, children: FormState => ReactElement)
override val component = AtlaskitFormLibrary
}
@js.native
trait FormState extends js.Object {
val formProps: FormProps = js.native
val disabled: Boolean = js.native
val dirty: Boolean = js.native
val submitting: Boolean = js.native
val getValues: () => js.Object = js.native
}
@js.native
trait FormProps extends js.Object {
val ref: ReactRef[String] = js.native
val onSubmit: js.Function1[SyntheticEvent[html.Form, Event], Unit] = js.native
}
So, for example this can be used like:
Form(
onSubmit _,
)(
(formState: FormState) => {
form(
ref := formState.formProps.ref,
onSubmit := (formState.formProps.onSubmit(_))
)(
Button(Primary, Submit)("")
)
}
)
I borrowed heavily from here.
This PR https://github.com/shadaj/slinky/pull/478 provides a workaround for the curried optional arguments problem @nadenf described here: https://github.com/shadaj/slinky/issues/237#issuecomment-472819612. Likely not relevant to you @evbo.
@jedahu I updated my earlier comment with an approach for currying children and supporting default args. A little extra code, but supports the general case of children being a function too
One other side effect of the children: ReactElement*
argument is it forces you to specify even if you have no children:
MyComponent(id = 1)() // without "()" you will get error missing curried argument "children"
Would be nice if behavior matched that of, say, div
, where the curried children are optional:
div() // no children specified and that's okay!
Would be useful to have documentation for handling children. For example in this component:
https://atlaskit.atlassian.com/packages/core/form/docs/form