Search code examples
reactjsclojurescriptreagentshadow-cljstailwind-elements

Using TWE-React with ClojureScript (import() in cljs)


I am currently trying to use TailWindElements-React in Clojure Script. In JS an example would look like this:

import React, { useState } from "react";
import { TECollapse, TERipple } from "tw-elements-react";

export default function App(): JSX.Element {
  const [show, setShow] = useState(false);

  const toggleShow = () => setShow(!show);

  return (
    <>
      <TERipple rippleColor="light">
        <a
          className="inline-block rounded bg-primary mr-2 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] dark:shadow-[0_4px_9px_-4px_rgba(59,113,202,0.5)] dark:hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)]"
          role="button"
          onClick={toggleShow}
        >
          Link
        </a>
      </TERipple>
      <TERipple rippleColor="light">
        <button
          type="button"
          className="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] dark:shadow-[0_4px_9px_-4px_rgba(59,113,202,0.5)] dark:hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)]"
          onClick={toggleShow}
        >
          Button
        </button>
      </TERipple>

      <TECollapse show={show}>
        <div className="block rounded-lg bg-white p-6 shadow-lg dark:bg-neutral-700 dark:text-neutral-50">
          Some placeholder content for the collapse component. This panel is
          hidden by default but revealed when the user activates the relevant
          trigger.
        </div>
      </TECollapse>
    </>
  );
}

However, (afaik) TWE uses/requires the import() function. This seems to make problems for CLJS and the workaround is

(ns my.app
  (:require
    [shadow.esm :refer (dynamic-import)]
    [shadow.cljs.modern :refer (js-await)]))

(defn foo []
  (js-await [mod (dynamic-import "https://cdn.pika.dev/preact@^10.0.0")]
    (js/console.log "loaded module" mod)))

as shown here using ES.

So I adapted this to

(ns my.app
  (:require
    [shadow.esm :refer (dynamic-import)]
    [shadow.cljs.modern :refer (js-await)]))

(defn TERipple []
  (js-await [mod (dynamic-import "tw-elements-react")]
    (js/console.log "loaded module" mod)))

However this results in CLJS telling me shadow_esm_import is not defined. I guess I need to change my target in the config to :esm, but then I am unable to mount my app into the DOM. I am realtively new to CLJS so this is all very confusing. Can someone help me?

Edit: Thomas Heller pointed out, that this is no use of import() but only the basic import syntax. Which would lead to an import via

(:require ["tw-elements-react" :refer (TECollapse TERipple)])

and then using it like

[:> TERipple
...
]

This, however gives me

[:app] Build failure:
Closure compilation failed with 1 errors
--- node_modules/tw-elements-react/dist/js/tw-elements-react.umd.min.js:13
Dynamic import expressions cannot be transpiled.

Solution

  • The JS example is not using import(). It is just a regular import. I know they look similar, but they are entirely different.

    There are a lot of common translation examples available in the shadow-cljs docs.

    So, import { TECollapse, TERipple } from "tw-elements-react"; translates to

    (ns my.app
      (:require ["tw-elements-react" :refer (TECollapse TERipple)]))
    

    Incidentally the tw-elements-react package does indeed use import() internally. This does not change how you :require it from CLJS, but shadow-cljs version 2.26.6+ is required for that to work.