Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte 5: The on of svelte/events is restricted to use with Element only #12045

Closed
Serator opened this issue Jun 16, 2024 · 3 comments · Fixed by #12053
Closed

Svelte 5: The on of svelte/events is restricted to use with Element only #12045

Serator opened this issue Jun 16, 2024 · 3 comments · Fixed by #12053

Comments

@Serator
Copy link

Serator commented Jun 16, 2024

Describe the problem

Let's say I want to create a handler with matchMedia:

const matchMedia = window.matchMedia(mediaQueryString)
matchMedia.addEventListener('change', listener)

The Element type of the on function will prevent me from using something like

const matchMedia = window.matchMedia(mediaQueryString)
on(matchMedia, 'change', listener)

Describe the proposed solution

If this is a deliberate limitation, it's worth mentioning it in the documentation.
Otherwise, it should be possible to use on with objects other than Element.

Importance

nice to have

@Serator Serator changed the title Svelte 5: The on of svelte/events is restricted to use with Element only Svelte 5: The on of svelte/events is restricted to use with Element only Jun 16, 2024
dummdidumm added a commit that referenced this issue Jun 17, 2024
- give autocompletion for types and more precise event types for html elements
- allow to pass other kinds of event target nodes, like window

closes #12027
fixes #12045
@dummdidumm dummdidumm added this to the 5.0 milestone Jun 17, 2024
@Serator
Copy link
Author

Serator commented Jun 17, 2024

@dummdidumm It still doesn't work.

I have the following code that I am trying to rewrite using on:

export const useMediaQuery = (mediaQueryString: string) => {
  let isMatch = $state(globalThis.matchMedia?.(mediaQueryString).matches ?? false)
  let listeners = 0
  let unsubscribe: VoidFunction

  return {
    get isMatch() {
      if ($effect.tracking()) {
        $effect(() => {
          if (listeners++ === 0) {
            const listener = (event: MediaQueryListEvent) => (isMatch = event.matches)
            const matchMedia = window.matchMedia(mediaQueryString)
            matchMedia.addEventListener('change', listener)
            unsubscribe = () => matchMedia.removeEventListener('change', listener)
          }

          return () => {
            if (--listeners === 0) {
              unsubscribe()
            }
          }
        })
      }

      return isMatch
    },
  }
}

It goes like this:

import {on} from 'svelte/events'

export const useMediaQuery = (mediaQueryString: string) => {
  let isMatch = $state(globalThis.matchMedia?.(mediaQueryString).matches ?? false)
  let listeners = 0
  let unsubscribe: VoidFunction

  return {
    get isMatch() {
      if ($effect.tracking()) {
        $effect(() => {
          if (listeners++ === 0) {
            unsubscribe = on(
              window.matchMedia(mediaQueryString),
              'change',
              (event: MediaQueryListEvent) => (isMatch = event.matches),
            )
          }

          return () => {
            if (--listeners === 0) {
              unsubscribe()
            }
          }
        })
      }

      return isMatch
    },
  }
}
image

@Serator
Copy link
Author

Serator commented Jun 17, 2024

@Serator
Copy link
Author

Serator commented Jun 21, 2024

@dummdidumm Maybe I should create a separate issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants