Creating a binding to Mui styled components

Hey guys, someone who struggles with ReScript here. I’m trying to write a binding to import { styled } from '@mui/material/styles';. This is what I have so far:

@module("@mui/material/styles")
external styledComponentWithTheme: React.component<'a> => (Mui.Theme.t => {..}) => React.component<
  'a,
> = "styled"

I think this is probably really not right because when I try to use the binding in a component, the compiler is telling me crazy stuff about how the component is a string and doesn’t accept props. Here’s an example:

let buttonOne = MuiSystem.styledComponentWithTheme(Mui.Button.make)(theme =>
  {
    "margin": "4px",
    "marginTop": "16px",
    "display": "flex",
    "alignItems": "center",
    "flexWrap": "wrap",
  }
)

let buttonTwo = MuiSystem.styledComponentWithTheme(Mui.Button.make)(theme =>
  {
    "margin": "4px",
    "marginTop": "16px",
    "display": "flex",
    "alignItems": "center",
    "flexWrap": "wrap",
    "color": "white",
  }
)

let icon = MuiSystem.styledElementWithTheme("span")(theme =>
  {
    "marginRight": "8px",
  }
)

@genType @react.component
let make = (~onClick, ~category, ~selected, ~icon, ~disabled) => {
  let (buttonElement, buttonVariant, iconClass) = switch selected {
  | true => (buttonOne, Mui.Button.Contained, "lnr lnr-check")
  | false => (buttonTwo, Mui.Button.Outlined, "lnr")
  }

  <buttonElement color=Mui.Button.Primary variant=buttonVariant onClick={_ => onClick(category)}>
    <icon className=iconClass />
    {category->React.string}
  </buttonElement>
}

In the jsx, when I hover over buttonElement it says it’s a string. And the compiler doesn’t like any of these props for MUI and says: This record expression is expected to have type JsxDOM.domProps The field color does not belong to type JsxDOM.domProps

Anyone charitable enough to help a fellow struggling coder? Thanks!

1 Like

That is because buttonElement starts with small case. If the JSX starts with a small case it is considered as host element instead of a component, eg: <div> , <p> (host elements) vs <Header> (components)

I hope the following binding works. (Playground link)

  1. The new component should be wrapped in a module with make function so that it can be used in JSX.
  2. Used uncurried function since the second argument to styledComponentWithTheme is a callback.
type muiTheme

@module("@mui/material/styles")
external styledComponentWithTheme: (
  . React.component<'a>,
  muiTheme => {..},
) => React.component<'a> = "styled"

module Name = {
  @react.component
  let make = () => React.null
}

module ButtonOne = {
  let make = styledComponentWithTheme(.Name.make, (_theme: muiTheme) =>
    {
      "margin": "4px",
      "marginTop": "16px",
      "display": "flex",
      "alignItems": "center",
      "flexWrap": "wrap",
    }
  )
}

let b = <ButtonOne />
1 Like

Thank you! That basically worked. I had to change how the state rendered things conditionally, but that’s fine!