solid: Directive function is not defined

Hello,

I used the vite-solid-tailwind-starter package to start a project and integrate the app with Phoenix Framework.

The starter features a dropdown so I decided to integrate the clickOutside directive from the tutorial.

I added this bit to my div:

use:clickOutside={() => setShowProfileMenu(false)}

First it has this error:

Type '{ children: Element; "use:clickOutside": () => boolean; class: string; }' is not assignable to type 'HTMLAttributes<HTMLDivElement>'.
  Property 'use:clickOutside' does not exist on type 'HTMLAttributes<HTMLDivElement>'.ts(2322)

But as the tutorial features a //@ts-nocheck comment I guess it is a known bug.

Now, when I run the app, I have an error:

Uncaught ReferenceError: clickOutside is not defined

If I add a dummy console.log(clickOutside) anywhere in the file then the directive works as expected.

It looks like the tree is shaken a bit too much.

I get the same behaviour with the default code in the starter (without configuring for Phoenix).

I am not sure if I am missing something, as it should work, since it works in the tutorial.

Thank you

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 24 (11 by maintainers)

Most upvoted comments

The option is here now; it should be solidPlugin({ typescript: { onlyRemoveTypeImports: true } }).

Note that you have to both declare the directive and add the plugin option, not just one or the other. The first prevents typescript from complaining that the directive doesn’t exist in props, and the second prevents typescript from removing the import during compilation as it assumes you didn’t use it anywhere (but Solid’s transform will, resulting in a runtime error).

It’s specific to the hot reload plugin. So yeah we should look at the file times. By default the playground(tutorials) only offers up .tsx and .css. I think we should expand that.

Right! That works. I’ve also finally found how to configure with Vite:

import { defineConfig } from "vite";
import solidPlugin from "vite-plugin-solid";

export default defineConfig({
  plugins: [solidPlugin({ babel: { onlyRemoveTypeImports: true } })],
  // ...
})  

Also the declaration works if it is right above the code:

import { onCleanup } from "solid-js";

declare module "solid-js" {
  namespace JSX {
    interface Directives {
      clickOutside?: () => void;
    }
  }
}

export default function clickOutside(el, accessor) {
  const onClick = (e) => !el.contains(e.target) && accessor()?.();
  document.body.addEventListener("click", onClick);

  onCleanup(() => document.body.removeEventListener("click", onClick));
}

“go to definition” shortcuts on code editors would then directly go to the right file.

Thank you for your help 👍