Search code examples
clojurescriptshadow-cljsjoy-ui

Translating and importing Joy UI dark mode to ClojureScript


I am trying to use Joy UI and its dark mode https://mui.com/joy-ui/customization/dark-mode/ in my cljs project and am stuck with translating the part below to cljs code.

import * as React from 'react';
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';
import Sheet from '@mui/joy/Sheet';
import Chip from '@mui/joy/Chip';
import Typography from '@mui/joy/Typography';

const theme = extendTheme({ cssVarPrefix: 'demo' });

export default function DarkModeByDefault() {
  return (
    <CssVarsProvider
      defaultMode="dark"
      // the props below are specific to this demo,
      // you might not need them in your app.
      //
      theme={theme}
      // the selector to apply CSS theme variables stylesheet.
      colorSchemeSelector="#demo_dark-mode-by-default"
      //
      // the local storage key to use
      modeStorageKey="demo_dark-mode-by-default"
      //
      // set as root provider
      disableNestedContext
    >
      <div id="demo_dark-mode-by-default">
        <Sheet sx={{ px: 3, py: 1.5, borderRadius: 'sm' }}>
          <Typography
            component="div"
            endDecorator={
              <Chip variant="outlined" color="primary" size="sm">
                Default
              </Chip>
            }
            fontSize="lg"
          >
            Dark mode
          </Typography>
        </Sheet>
      </div>
    </CssVarsProvider>
  );
}

I am using shadow-cljs, and I tried to translate it like the following

(ns ....
  (:require
    ...
   ["@mui/joy/Button" :as mui-joy-button]
   ["@mui/joy/Grid" :as mui-joy-grid]
   ["@mui/joy/styles" :as mui-joy-styles]))

(def btn (rc/adapt-react-class (.-default mui-joy-button)))
(def grd (rc/adapt-react-class (.-default mui-joy-grid)))
(def cvp (rc/adapt-react-class mui-joy-styles/CssVarsProvider))
(def ext mui-joy-styles/extendTheme)

(def theme (ext {:cssVarPrefix "demo"}))

(defn main-page []
  [cvp {:defaultMode "dark"
        :theme theme
        :colorSchemeSelector "#demo_dark-mode-by-default"
        :modeStorageKey "demo_dark-mode-by-default"
        :disableNestedContext true}]
  [:div {:id "demo_dark-mode-by-default"}
   [grd {:container true :spacing 2}
    [grd {:xs 8} [:p "asdasdfasdf"]]
    [grd {:xs 4} [btn {:variant :solid} "asdf"]]]])

But the theming and dark mode do not work. I believe my problem is CssVarsProvider part. I am not sure how I can import it.

Can someone please provide a clue?


Solution

  • The (def theme ...) is calling the (ext ...) JS function with a CLJS Map. It won't support that, it will likely need to be either (def theme (ext #js {:cssVarPrefix "demo"})) or (def theme (clj->js {:cssVarPrefix "demo"})), so that it is converted to a proper JS Object first. Which one you use depends on if you add nested structures. The #js works only for simple objects, which in this case would fit.

    You can also shrink the code a bit by using the :> operator and the require sugar, so that you don't need all the extra defs.

    (ns ...
      (:require
        ...
        ["@mui/joy/Button$default" :as btn]
        ["@mui/joy/Grid$default" :as grd]
        ["@mui/joy/styles" :as mui-joy-styles :refer (CssVarsProvider extendTheme)]))
    
    (def theme (extendTheme #js {:cssVarPrefix "demo"}))
    
    (defn main-page []
      [:> CssVarsProvider
       {:defaultMode "dark"
        :theme theme
        :colorSchemeSelector "#demo_dark-mode-by-default"
        :modeStorageKey "demo_dark-mode-by-default"
        :disableNestedContext true}
       [:div {:id "demo_dark-mode-by-default"}
        [:> grd {:container true :spacing 2}
         [:> grd {:xs 8}
          [:p "asdasdfasdf"]]
         [:> grd {:xs 4}
          [:> btn {:variant "solid"} "asdf"]]]]])