Last active
February 4, 2024 22:24
-
-
Save jonshipman/a81f98a6b2a98aed983bb0444af8a1b8 to your computer and use it in GitHub Desktop.
Media size dispatcher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts"> | |
import { createEventDispatcher } from 'svelte'; | |
import { ResizeStore } from './window-events'; | |
import type { ResizeDetail } from './resize.svelte.d'; | |
export let debounce = 0; | |
export let mobile: boolean | null = null; | |
const dispatch = createEventDispatcher<{ resize: ResizeDetail }>(); | |
let timeout: ReturnType<typeof setTimeout>; | |
function mount(node: HTMLDivElement) { | |
const unsub = ResizeStore.subscribe(() => { | |
clearTimeout(timeout); | |
timeout = setTimeout(() => { | |
const visible = node.offsetParent === null; | |
mobile = visible; | |
dispatch('resize', { visible: { md: visible } }); | |
}, debounce); | |
}); | |
return { | |
destroy() { | |
clearTimeout(timeout); | |
unsub(); | |
} | |
}; | |
} | |
</script> | |
<div class="hidden md:block" use:mount /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { SvelteComponent } from 'svelte'; | |
export interface ResizeDetail { | |
visible: { md: boolean }; | |
} | |
export type ResizeEvent = Event & { detail: ResizeDetail }; | |
export default class Resize extends SvelteComponent {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Allows one listener per type in the application. | |
* e.g. If you have 500 InView components, you'll only have one scroll listener. | |
*/ | |
function createWindowEventStore(event: string) { | |
const subs: Array<() => void> = []; | |
let listener = false; | |
function on() { | |
for (const cb of subs) { | |
cb(); | |
} | |
} | |
return { | |
subscribe(cb: () => void) { | |
subs.push(cb); | |
cb(); | |
if (!listener) { | |
window.addEventListener(event, on); | |
listener = true; | |
} | |
return () => { | |
const index = subs.findIndex((fn) => fn === cb); | |
subs.splice(index, 1); | |
if (subs.length < 1) { | |
window.removeEventListener(event, on); | |
listener = false; | |
} | |
}; | |
} | |
}; | |
} | |
export const ResizeStore = createWindowEventStore('resize'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment