click outside directive in typescript

o/ i'm trying to implement https://www.solidjs.com/tutorial/bindings_directives?solved but in typescript. not sure what to fill types in (other than any). any idea?
SolidJS
Solid is a purely reactive library. It was designed from the ground up with a reactive core. It's influenced by reactive principles developed by previous libraries.
18 Replies
thetarnav
thetarnav2y ago
type Directive<P = true> = (el: Element, props: Accessor<P>) => void;

const clickOutside: Directive<VoidFunction> = (el, accessor) => {
const onClick = (e: MouseEvent) =>
e.target instanceof Element && !el.contains(e.target) && accessor()();

document.body.addEventListener("click", onClick);

onCleanup(() => document.body.removeEventListener("click", onClick));
};
type Directive<P = true> = (el: Element, props: Accessor<P>) => void;

const clickOutside: Directive<VoidFunction> = (el, accessor) => {
const onClick = (e: MouseEvent) =>
e.target instanceof Element && !el.contains(e.target) && accessor()();

document.body.addEventListener("click", onClick);

onCleanup(() => document.body.removeEventListener("click", onClick));
};
Revxrsal
Revxrsal2y ago
appreciate that! what does <P = true> mean though?
thetarnav
thetarnav2y ago
<div use:clickOutside /> === <div use:clickOutside={true} /> So if you don't want any arguments, you'll just get true
Revxrsal
Revxrsal2y ago
ohh that makes sense. thanks a lot!
Revxrsal
Revxrsal2y ago
Revxrsal
Revxrsal2y ago
i exported everything in the clickOutside
thetarnav
thetarnav2y ago
declare module "solid-js" {
namespace JSX {
interface Directives {
clickOutside: VoidFunction;
}
}
}
declare module "solid-js" {
namespace JSX {
interface Directives {
clickOutside: VoidFunction;
}
}
}
There are a ton of issues with directives, in typescript especially, becasue directives are just strings that have to be specially handled by the custom transform. But typescript isn't aware of them I ususaly never use them
Revxrsal
Revxrsal2y ago
do you think it's better to use solidjs with JS instead of TS? me choosing ts was an arbitrary decision really
thetarnav
thetarnav2y ago
ts is always better there are some edge-cases like directives that are worse, but it's a great library to be paired up with typescript This is how you can use "directives" the "normal" and typesafe way:
<div ref={el => {
useClickOutside(el, () => console.log("outside"))
}} />
<div ref={el => {
useClickOutside(el, () => console.log("outside"))
}} />
Where useClickOutside is just a normal function
Revxrsal
Revxrsal2y ago
thanks, that worked! had to change clickOutside: Directive<VoidFunction> to clickOutside: Directive<any> though (apparently returning void doesn't appeal to VoidFunction)
thetarnav
thetarnav2y ago
now you can throw out the Directive type really As there is no bounding shape of the function's interface that it has to follow It's just a normal function that can have any shape But if you want it to be compatable with directives, then sure, you can still use it The second srgument is an accessor through So you'd have to use it like that useClickOutside(el, () => () => concol.log("outside"))
Revxrsal
Revxrsal2y ago
ohh i see now. so just a normal effect?
thetarnav
thetarnav2y ago
effect?
Revxrsal
Revxrsal2y ago
i mean hook if that's what they're called in solid
thetarnav
thetarnav2y ago
ah ok, yes
Revxrsal
Revxrsal2y ago
thanks for the help!
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
thetarnav
thetarnav2y ago
what about this design:
import { use, clickOutside } from '~/directives'
function MyComponent (): JSX.Element {
return <div ref={use(clickOutside, () => alert('test'))}>inside</div>
}
import { use, clickOutside } from '~/directives'
function MyComponent (): JSX.Element {
return <div ref={use(clickOutside, () => alert('test'))}>inside</div>
}
would be nice it this was possible too
import { use, clickOutside, otherDirective } from '~/directives'
function MyComponent (): JSX.Element {
return <div ref={use(
[clickOutside, () => alert('test')],
[otherDirective]
)}>inside</div>
}
// or
import { chain, use, clickOutside, otherDirective } from '~/directives'
function MyComponent (): JSX.Element {
return <div ref={chain(
use(clickOutside, () => alert('test')),
use(otherDirective)
)}>inside</div>
}
import { use, clickOutside, otherDirective } from '~/directives'
function MyComponent (): JSX.Element {
return <div ref={use(
[clickOutside, () => alert('test')],
[otherDirective]
)}>inside</div>
}
// or
import { chain, use, clickOutside, otherDirective } from '~/directives'
function MyComponent (): JSX.Element {
return <div ref={chain(
use(clickOutside, () => alert('test')),
use(otherDirective)
)}>inside</div>
}
idk