npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2024 – Pkg Stats / Ryan Hefner

svelte-preprocess-delegate-events

v0.4.4

Published

You can delegate events by on:* πŸŽ‰

Downloads

1,443

Readme

NPM license NPM version Code Style: Prettier Build Status Coverage Status

Delegate events with on:* πŸŽ‰

  • πŸ’‘ Easy to use
  • ⚑️ No performance impact
  • πŸ”‘ No type errors with svelte-check

Try it on Stackblitz πŸš€.

Overview

Since 2019, one popular issue on the Svelte GitHub repository has been delegating all events. https://github.com/sveltejs/svelte/issues/2837

This repository aims to solve this issue.

Example

Component.svelte

<!-- Delegate all events with `on:*` πŸŽ‰ -->
<input on:* />

App.svelte

<script>
  import Component from './Component.svelte';
</script>

<!-- Handle events as desired -->
<Component
  on:input="{(e) => console.log(e.target.value)}"
  on:blur="{() => console.log('blur')}"
/>

Prerequisites

This library needs Svelte 3 or Svelte 4.

Installation

npm install -D svelte-preprocess-delegate-events

Usage

After installation, add this as a Svelte preprocessor.

// svelte.config.js
import delegateEvents from "svelte-preprocess-delegate-events/preprocess";

const config = {
  // Add this preprocessor at the end of the array.
  preprocess: [delegateEvents()],
};

export default config;

Integration with svelte-check

If you want to use svelte-check, create svelte-jsx.d.ts at the project root and update [tj]sconfig.json.

svelte-jsx.d.ts

declare namespace svelteHTML {
  /**
   * base: https://github.com/sveltejs/language-tools/blob/651db67858d18ace44d000d263ac57ed5590ea05/packages/svelte2tsx/svelte-jsx.d.ts#L42
   */
  type HTMLProps<Property extends string, Override> =
    Omit<
      Omit<import('svelte/elements').SvelteHTMLElements[Property], keyof EventsWithColon<Omit<svelte.JSX.IntrinsicElements[Property & string], svelte.JSX.AttributeNames>>> & EventsWithColon<Omit<svelte.JSX.IntrinsicElements[Property & string], svelte.JSX.AttributeNames>>,
      keyof Override
    > & Override & (Record<'on:*', (event: Event & { currentTarget: EventTarget & EventTarget }) => any | never> | object);
}

[tj]sconfig.json

{
+ "include": ["./svelte-jsx.d.ts"]
}

How the Preprocessor Works?

This chapter explains how the preprocessor functions. The preprocessor operates differently for Elements and Components.

Element

Consider the following simple example:

<!-- Parant.svelte -->
<script>
  import Child from './Child.svelte';
</script>
<Child on:click={() => console.log('clicked!')} />

<!-- Child.svelte -->
<button on:*>Click Me</button>

Svelte executes events registered in component.$$.callbacks when an event is triggered in a child component. In the example above, component.$$.callbacks is as follows:

component.$$.callbacks = {
  click: () => console.log('clicked!')
}

This preprocessor adds a process to listen for events registered in component.$$.callbacks for elements with on:*. After preprocessing, Child.svelte looks like this:

<!-- Child.svelte -->
<script>
  import { boundElements, registerDelegatedEvents } from 'svelte-preprocess-delegate-events/runtime';
  import { get_current_component } from 'svelte/internal';
  let button = boundElements();
  const component = get_current_component();
  $: registerDelegatedEvents(button.bounds, component, (handler) => handler, {});
</script>

<button bind:this={button.bounds}>Click Me</button>

NOTE: The reason for binding <button> to button.bounds instead of binding it to the button variable is to support cases where multiple elements exist, such as <button> in a {#each} block.

In this way, only events that are being listened to by the parent component are listened to, thus providing a mechanism with no performance overhead.

Component

Component uses a different mechanism than Element. Consider the following simple example:

<!-- Parant.svelte -->
<script>
  import Child from './Child.svelte';
</script>
<Child on:click={() => console.log('clicked!')} />

<!-- Child.svelte -->
<script>
  import GrandChild from './GrandChild.svelte';
</script>
<GrandChild on:* />

<!-- GrandChild.svelte -->
<button on:click on:blur>Click Me</button>

If you are using on:* in Child.svelte, you need to forward all events from GrandChild to Parent. However, Child does not know what events are coming from GrandChild, so you need to do something. Specifically, when GrandChild triggers an event, it will refer to component.$$.callbacks to run its event handlers. By proxying component.$$.callbacks, you will know which events have been forwarded. Forwarded events can be communicated to the parent component so that the Parent component can handle the event.

After preprocessing, it looks like this:

<!-- Child.svelte -->
<script>
  import { boundComponents, proxyCallbacks } from 'svelte-preprocess-delegate-events/runtime';
  import { get_current_component } from 'svelte/internal';
  import GrandChild from './GrandChild.svelte';

  const GrandChild = boundComponents();
  const component = get_current_component();
  $: proxyCallbacks(component, GrandChild.bounds, false);
  </script>

<GrandChild bind:this={GrandChild.bounds} />

Note

on:* does not support specifying event handlers directly because a useful use case could not be found. If you have a useful use case, please create a new issue.

<script>
  import Component from './Component.svelte';
  const handleEvent = (e) => {
    console.log(e);
  }
</script>

<!-- Specifying event handler directly is not supported -->
<input on:*="{handleEvent}" />

<!-- Specifying event handler directly is not supported -->
<Component on:*="{handleEvent}" />

For Svelte 5 Users

For Svelte 5, event forwarding is natively supported.πŸŽ‰

https://svelte-5-preview.vercel.app/docs/event-handlers#bubbling-events