I’m new to ReScript and struggling a bit with understanding how to do bindings correctly.
Right now, I’m trying to bind the react-hot-toast library, and I have two questions.
First, the library is imported in JS/TS with a named export like so: import { toast } from 'react-hot-toast'
Then it lets you call toast directly with toast("some text here") but also makes it possible to call it with functions like error toast.error("some err").
Is it possible to use named exports in ReScript? I can only figure out how to do top-level imports. @module("react-hot-toast") compiles to import * as ReactHotToast from.... If I do @module("react-hot-toast/toast") it compile to import * as Toast from...
Question 1
Can I make it compile to import { toast } from 'react-hot-toast somehow?
Right now I have two module mappings to get both available in ReScript. @module("react-hot-toast") external simple: string => unit = "toast" this lets me call simple("some text here") which is equivilant to the direct call. This works fine and is uncurried in the compiled code.
This compiles to something like ReactHotToast.toast.error("some err");
And it works fine. But if I don’t uncurry the error call, it doesn’t seem to work. Then it compiles to: Curry._1(ReactHotToast.toast.error, "some err"); and then it doesn’t work when I call it.
Question 2
What am I missing to make the “default” curried call work?
On a higher level: nothing. Because there’s no such thing as curried call in JS. The fact that externals compile to clean uncurried code is a special case actually.
Edit: believer beat me to it. But yes, if you want to also bind to Toaster as a default export, then add that too. Basically, use @send.
A follow up question. Now I’m trying to bind to the headlessui package from TailwindLabs.
I’m trying to use a named export from their package called Transition.
Normally I would import it like this: import { Transition } from '@headlessui/react' and then just use the Transition component in my markup.
This got me a long way. Thank you very much!
The next blocker I’m facing is how to map the Transition.Child from the package.
I can see that you don’t use it yet, so there’s not a solution I can steal
The TransitionChild is not exported so again I’m unsure how to go about this.
But I get the error Attempted import error: 'Child' is not exported from '@headlessui/react' (imported as 'React$1').
I’m guessing I need to change the type returned from Transition element. But how do I create a type that will allow Transition itself to be a React.element and also have a Child which is a React.element?
In case you don’t know: You can find all our interop decorators (+ examples) in our syntax discovery widget (feel free to open an issue on the docs issue tracker in case anything you find there is unclear)
We appreciate the questions / threads! Keep it going
Usage would look like this: <HeadlessUICom _as=#div> ... </HeadlessUIComp>
Looks like HeadlessUI defines as as a union type (either "div" | ... | React.fragment). ReScript doesn’t support polymorphic values too well, so you need a helper module to unify these types.
Kinda like this:
type state
module As: {
type t
let fragment: t
let dom: [#div] => t
} = {
type t
@module("react")
external fragment: t = "Fragment"
external dom: [#div] => t = "%identity"
}
module MyComp = {
@module("@headlessui/react") @react.component
external make: (
~_as: As.t=?,
~className: string=?,
~children: state => React.element,
) => React.element = "Menu"
}
let _ = <MyComp _as=As.fragment> {(_) => <div/>} </MyComp>
let _ = <MyComp _as=As.dom(#div)> {(_) => <div/>} </MyComp>
The best way to debug this is to look at the JS output. Did your program actually compile and yield the JS output you’d expect? Does it look exactly like in the HeadlessUI docs and still doesn’t work?