Skip to content

Commit

Permalink
update to use new internals
Browse files Browse the repository at this point in the history
  • Loading branch information
sviripa committed Jul 2, 2024
1 parent f77e853 commit 4acf14f
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 36 deletions.
1 change: 1 addition & 0 deletions packages/runed/src/lib/utilities/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./activeElement/index.js";
export * from "./useClickOutside/index.js";
export * from "./useDebounce/index.js";
export * from "./ElementSize/index.js";
export * from "./useEventListener/index.js";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { box, type WritableBox } from "$lib/functions/box/box.svelte.js";
import { watch } from "$lib/functions/watch/watch.svelte.js";
import type { MaybeGetter } from "../../internal/types.js";
import { watch } from "../watch/watch.svelte.js";
import { extract } from "../extract/extract.js";

type ClickOutside = {
start: () => void;
Expand All @@ -16,27 +17,28 @@ type ClickOutside = {
* @see {@link https://runed.dev/docs/functions/use-click-outside}
*/
export function useClickOutside<T extends Element>(
container: WritableBox<T | null>,
fn: () => void
container: MaybeGetter<T | undefined>,
callback: () => void
): ClickOutside {
const isEnabled = box<boolean>(true);
let isEnabled = $state<boolean>(true);
const el = $derived<T | undefined>(extract(container));

function start() {
isEnabled.value = true;
isEnabled = true;
}

function stop() {
isEnabled.value = false;
isEnabled = false;
}

function handleClick(event: MouseEvent) {
if (event.target && !container.value?.contains(event.target as Node)) {
fn();
if (event.target && !el?.contains(event.target as Node)) {
callback();
}
}

watch([container, isEnabled], ([currentContainer, currentIsEnabled]) => {
if (currentContainer && currentIsEnabled) {
watch([() => el, () => isEnabled], ([currentEl, currentIsEnabled]) => {
if (currentEl && currentIsEnabled) {
window.addEventListener("click", handleClick);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { describe, expect, vi } from "vitest";
import { tick } from "svelte";
import { testWithEffect } from "$lib/test/util.svelte.js";
import { box } from "$lib/functions/box/box.svelte.js";
import { useClickOutside } from "./useClickOutside.svelte.js";
import { testWithEffect } from "$lib/test/util.svelte.js";

describe("useClickOutside", () => {
testWithEffect("calls a given callback on an outside of container click", async () => {
Expand All @@ -16,7 +15,7 @@ describe("useClickOutside", () => {

const callbackFn = vi.fn();

useClickOutside(box.from(container), callbackFn);
useClickOutside(() => container, callbackFn);
await tick();

button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
Expand All @@ -38,7 +37,7 @@ describe("useClickOutside", () => {

const callbackFn = vi.fn();

const clickOutside = useClickOutside(box.from(container), callbackFn);
const clickOutside = useClickOutside(() => container, callbackFn);

clickOutside.stop();
await tick();
Expand Down
32 changes: 19 additions & 13 deletions sites/docs/content/utilities/use-click-outside.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: useClickOutside
description:
A function that calls a callback when a click event is triggered outside of a given container
element.
category: Elements
category: Browser
---

<script>
Expand All @@ -18,17 +18,20 @@ import Demo from '$lib/components/demos/use-click-outside.svelte';

```svelte
<script lang="ts">
import { box, useClickOutside } from "runed";
import { useClickOutside } from "runed";
const container = box<HTMLDivElement | null>(null);
let el = $state<HTMLDivElement | undefined>(undefined);
useClickOutside(container, () => {
console.log("clicked outside of container");
});
useClickOutside(
() => el,
() => {
console.log("clicked outside of container");
}
);
</script>
<main>
<div bind:this={container.value}>Container</div>
<div bind:this={el}>Container</div>
<button>Click Me</button>
</main>
```
Expand All @@ -38,18 +41,21 @@ functiosn returned by `useClickOutside`.

```svelte
<script lang="ts">
import { box, useClickOutside } from "runed";
import { useClickOutside } from "runed";
const container = box<HTMLDivElement | null>(null);
let el = $state<HTMLDivElement | undefined>(undefined);
const outsideClick = useClickOutside(container, () => {
console.log("clicked outside of container");
});
const outsideClick = useClickOutside(
() => el,
() => {
console.log("clicked outside of container");
}
);
</script>
<main>
<button onclick={outsideClick.stop}>Stop listening for outside clicks</button>
<button onclick={outsideClick.start}>Start listening again</button>
<div bind:this={container.value}></div>
<div bind:this={el}></div>
</main>
```
18 changes: 10 additions & 8 deletions sites/docs/src/lib/components/demos/use-click-outside.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<script lang="ts">
import { box, useClickOutside } from "runed";
import { useClickOutside } from "runed";
let containerText = "Has not clicked yet";
let containerText = $state("Has not clicked yet");
let el = $state<HTMLDivElement | undefined>(undefined);
const container = box<HTMLDivElement | null>(null);
useClickOutside(container, () => {
containerText = "Has clicked outside of container";
});
useClickOutside(
() => el,
() => {
containerText = "Has clicked outside of container";
}
);
</script>

<main>
<div bind:this={container.value}>
<div bind:this={el}>
<p>{containerText}</p>

<button onclick={() => (containerText = "Has clicked within container")}>
Expand Down

0 comments on commit 4acf14f

Please sign in to comment.