Correct point to add props to external React.componentLike

I’m writing bindings to the nativewind styled function which adds a className prop to react native components. I’ve managed to create local components and pass them through the external styled function and everything generally renders as expected, but the final piece is getting a usable className prop on each new local component. Here’s what I have working so far:

@module("nativewind")
external setStyled: React.componentLike<'props, 'return> => React.componentLike<'props, 'return> =
  "styled"

module View = {
  let makeProps = ReactNative.View.makeProps
  let make = ReactNative.View.make->setStyled
}

module Text = {
  let makeProps = ReactNative.Text.makeProps
  let make = ReactNative.Text.make->setStyled
}

So that works (renders) but again doesn’t reflect the className prop which was added as of the call to setStyled. In my perfect world, I’d somehow be able to do this at the point of binding:

@module("nativewind")
external setStyled: React.componentLike<'props, 'return> => React.componentLike<
{
   ...'props,
  "className": string /* This doesn't even come close to working, but it's effectively what I need */
}, 'return> =
  "styled"

So assuming I can’t do anything like the last idea, what it seems like I should do is something like the following in a second wrapping step:

module Wrapper = {
  let make = (~props, ~children, ~className) => {
    React.cloneElement(Text.make(/*this wouldn't work*/~props, ~children), {"className": className})
  }
}

But that doesn’t work either. So I guess my question is: what’s the best point of intercept to add a prop to a component in a flexible way that preserves other props, children, etc.?

In case it helps anyone, I think in terms of bindings/interop I came up with a workable solution using a wrapper for any elements I need nativewind styling on:

@module("nativewind")
external setStyled: React.componentLike<'props, 'return> => React.componentLike<'props, 'return> =
  "styled"

module NwWrapper = {
  module ClonedComponent = {
    @react.component
    let make = (~className: string, ~children: React.element) => <>
      {children->React.cloneElement({"className": className})}
    </>
  }
  let makeProps = ClonedComponent.makeProps
  let make = ClonedComponent.make->setStyled
}

So then on the react side, it looks like this:

  <View>
    <NwWrapper className={"text-7xl"}>
      <Text> {React.string("Hello world")} </Text>
    </NwWrapper>
  </View>

I’m still working out getting the styling to apply, but that’s likely not a rescript issue.

@glennsl has answered a similar hoc question on stackoverflow

There the hoc returns a component which will accept the same props as input component, in this case it accepts a new prop along with existing props.

I am not exactly sure to how to handle this in binding level

Great find! I ended up taking a different approach but this is a really good one to know about.