0.0.1-alpha.305 • Published 1 year ago

@incremental.design/device-input-event-handlers v0.0.1-alpha.305

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

@incremental.design/device-input-event-handlers

Handle every device input, without the boilerplate.

The best user interfaces respond to everything a user does: every mouse movement, touch, keypress, and even device motion. Over the past decade, browser APIs have connected to more devices: from mice and keyboards, to touchscreens, accelerometers, gamepads, and even webcams. However, responding to all of these inputs takes a lot of logic. The more inputs your code responds to, the more logic it needs to contain, and the more bloated it becomes. device-input-event-handlers moves all of this logic out of your code, so you can handle everything, without the bloat.

Use the handlers in this package to:

  • Filter the useful information out of device input events, with just five lines of code:

    Feed an event into its corresponding handler in device-input-event-handler and get an object with just the values you actually need to handle the event. For example: It takes as few as 5 lines of code to add a handler to a Vue component.

  • Calculate changes between occurrences of device input events, with a single argument:

    Feed a handler an event, and the object it returned from any previous event, and it will automatically calculate the changes between the two. For example:

    To make the handler function calculate the differences between an event and a previous event, feed the results of the previous event back into the handler.

    When you feed the results of a previous event back into a handler, the handler calculates the difference between the previous and current event

Installation:

  1. Add the @incremental.design/device-input-event-handlers package to your project:

  2. Import the handlers you need into your project's code:

    @incremental.design/device-input-event-handlers exports a default handle(...) function. It also exports several named functions; one for each of the events that it handles:

Usage:

Add event handlers to your Vue 3 components:

If you want your Vue components to feel native, they have to do more than respond to mouse clicks. They need to track every mouse movement. And that's not all: they also have to trace touch gestures, measure key presses, and keep track of the document's focus. In other words, they need to hear everything that happens in a browser window. But listening to every change can add up to many hundreds of lines of redundant code in every component - not to mention dozens of hours of technical debt later on. The quickest way to save yourself the trouble is to utilize one of the many listeners in this package. All you need to do is:

  1. Add a variable to your component's data.
  2. Place a v-on directive in your component's template.

  3. Call a listener from within the v-on directive.

  4. Assign the results of the listener to the variable you made in the first step.

  5. Add a watcher to the variable, and use it to trigger your component's behaviors.

Once you import the handler, you only need to write a few lines of code, rather than a few hundred, to make your component hear everything.

There are three ways to add a handler to a Vue component:

  1. Call the handle(...) function from within any supported v-on directive.
  2. Call the handleDrag(...), handleFocus(...), handleKeyboard(...) handleMouse(...), handleTouch(...), or handleWheel(...) functions from their corresponding v-on listeners.
  3. Call the handle(...), handleDevice(...), handleGamepad(...), handleWindowResize(...) functions from within your Vue component's <script> block.

Call the handle(...) function from within any supported v-on directive:

<template>
  <div
    v-on:click="
      (event) => {
        previousEventInfo = handle(event, previousEventInfo);
      }
    "
  ></div>
</template>

<script>
export default {

  data(){

    return {

      previousEventInfo: null

    }

  },

  watch {

    previousEventInfo(new, old){

      /* your logic here */

    }

  }
}
</script>

The handle(...) function takes two arguments:

The handle(...) function returns one of the following objects, depending on the type of event that was passed into it:

The handle(...) function only supports the following v-on listeners:

The handle(...) function does not support the following v-on listeners, because these listeners do not hear events that are triggered by device inputs. If you try to pass an event from one of these to the handle(...) function, it will error.

The handle(...) does not support custom Vue events, because they aren't browser events. If you try to pass a custom event to this function, it will error.

  • Keep in mind that v-on listens for browser events when you add it to HTML Elements, such as <div>, <p>, or <span>, and custom events when you add it to vue components. Therefore, if you use handle(...) in v-on directive on a vue component, it will always fail.

Call the handleDrag(...), handleFocus(...), handleKeyboard(...) handleMouse(...), handleTouch(...), or handleWheel(...) functions from their corresponding v-on listeners.

If you want minimize your project's final bundle size, consider importing just a few of the above handler functions. They are smaller than the generic handle(...) function, because they don't implement all of the logic needed to handle every single input device event. Just like their generic counterpart, all of these handler functions:

  • can be called from within v-on
  • take roughly the same arguments.
  • return an object with information about the event they received.

If none of this makes sense to you, that's OK. Just use the handle(...) function. But if you're still following, keep reading to find out the differences between the specific handlers and their generic counterpart.

The handleDrag(...) function returns an EventInfo<DragInput> object. Unlike the handle(...) function, it only supports the following v-on listeners:

The handleFocus(...) function returns an EventInfo<FocusInput> object. Unlike the handle(...) function, it only supports the following v-on listeners:

The handleKeyboard(...) function returns an EventInfo<KeyboardInput> object. Unlike the handle(...) function, it only supports the following v-on listeners:

The handleMouse(...) function returns an EventInfo<PointerInput> object. Unlike the handle(...) function, it only supports the following v-on listeners:

The handleTouch(...) function returns an EventInfo<PointerInput> object. Unlike the handle(...) function, it only supports the following v-on listeners:

The handleWheel(...) function returns an EventInfo<ScrollInput> object. Unlike the handle(...) function, it only supports the following v-on listeners:

Like the handle(...) function, none of these handlers support custom Vue events.

Call the handle(...), handleDevice(...), handleGamepad(...), or handleWindowResize(...) functions from within your Vue component's <script> block.

Unlike MouseEvents, KeyboardEvents, WheelEvents and TouchEvents, DeviceMotionEvents, DeviceOrientationEvents, and GamepadEvents, aren't emitted from DOM elements. They are emitted from the window itself. So, there's no v-on listener that can hear them. To use handle(...) to handle these events, you need to:

  1. Call it from within a method in the methods option of your Vue component.
  2. Feed it into a window.addEventListener(...) function call in the mounted hook of your Vue component.
  3. Feed it into a window.removeEventListener(...) function in the beforeUnmount hook of your Vue component.
<script>
import handle from '@incremental.design/device-input-event-handlers'

export default {

  data(){

    return {
      eventInfo: null;
    }

  },

  methods: {

    handleDeviceMotion(e: Event){
      this.eventInfo = handle(event, this.eventInfo);
    }

  },

  watch: {

    eventInfo(new, old){
      /* trigger component behaviors */
    }

  },

  mounted(){
    window.addEventListener('devicemotion', this.handleDeviceMotion)
  },

  beforeUnmount(){
    window.removeEventListener(this.handleDeviceMotion)
  },

}
</script>

The handle(...) function can bind to any of the following event listeners:

The handle(...) function returns one of EventInfo<DeviceInput>, EventInfo<FocusInput>, EventInfo<GamepadInput>, EventInfo<KeyboardInput>, EventInfo<DragInput>, EventInfo<PointerInput>, EventInfo<ScrollInput>, EventInfo<WindowResizeInput>, depending on the type of event passed into it.

If you want to slim your project's final bundle size, and you don't need to handle all of the above events, consider importing and using the handleDevice(...) or handleGamepad(...) functions, instead of the handle(...) function.

The handleDevice(...) function returns an EventInfo<DeviceInput> object, and can only bind to the following event listeners:

The handleGamepad(...) function returns a EventInfo<GamepadInput> object, and can only bind to the following event listeners:

The handleWindowResize(...) function returns an EventInfo<WindowResizeInput> object, and can only bind to the following event listener:

How @incremental.design/device-input-event-handlers works:

If you peel back the surface of a modern web browser, there are a lot of events firing all of the time. As you scroll this webpage, hundreds of events are firing every second! But, listening to all of those events is a lot of work for the browser. If it had to describe everything that was happening in a given second, it would run out of memory in a matter of a few minutes! That's why browser have event listeners. When you use a v-on directive, or call addEventListener on an object in the browser's API, you're telling it what to listen for and when to alert you. Depending on what you listen for, you might receive just a few events, or you might receive a continuous stream. That's where this package's handlers shine.

Most user input is continuous. When you scroll on a webpage, anywhere from sixty to a few hundred events fire every second. Every time you move the page even a pixel, an entirely new event fires. And if you want your components to truly hear everything, you have to process all of them. Every handler in this package does just that. It reduces the event it receives into just a few, essential metrics. Then, it compares each metric to those of the event it just processed.

You've probably noticed that every handler in this package shares roughly the same method signature, and all return an object that contain common members, such as the eventType field. That's because every handler in this package extends the same, generic function, and every returned object extends the same generic returned object. This makes it easy to get a 'feel' for the functions in this package. Once you understand how one of them works, it's not a stretch to understand them all.

If you've been using handle(...) function, rather than its more specific counterparts, it turns out that you've actually been using the specific counterparts the entire time! That's because all the handle(...) function does is check the type of event it received and the type listener that sent it, and route the event to the function that knows how to handle that event. Of course, this means that the handle(...) function has to wrap all of the other functions it calls, increasing the final bundle size of your project. But, it's a small tradeoff for the convenience.

Package Folder Structure

File or FolderWhat it does:
src/*Exports all of the methods in this package.
package.jsonLists this package's dependencies, scripts, and exports.
tsconfig.jsonConfigures Typescript, which builds the code in src
0.0.1-alpha.420

1 year ago

0.0.1-alpha.421

1 year ago

0.0.1-alpha.425

1 year ago

0.0.1-alpha.422

1 year ago

0.0.1-alpha.423

1 year ago

0.0.1-alpha.428

1 year ago

0.0.1-alpha.429

1 year ago

0.0.1-alpha.426

1 year ago

0.0.1-alpha.427

1 year ago

0.0.1-alpha.413

1 year ago

0.0.1-alpha.411

1 year ago

0.0.1-alpha.412

1 year ago

0.0.0

1 year ago

0.0.1-alpha.417

1 year ago

0.0.1-alpha.418

1 year ago

0.0.1-alpha.415

1 year ago

0.0.1-alpha.416

1 year ago

0.0.1-alpha.387

2 years ago

0.0.1-alpha.388

2 years ago

0.0.1-alpha.380

2 years ago

0.0.1-alpha.399

2 years ago

0.0.1-alpha.391

2 years ago

0.0.1-alpha.394

2 years ago

0.0.1-alpha.395

2 years ago

0.0.1-alpha.365

2 years ago

0.0.1-alpha.366

2 years ago

0.0.1-alpha.363

2 years ago

0.0.1-alpha.364

2 years ago

0.0.1-alpha.403

2 years ago

0.0.1-alpha.400

2 years ago

0.0.1-alpha.367

2 years ago

0.0.1-alpha.376

2 years ago

0.0.1-alpha.377

2 years ago

0.0.1-alpha.374

2 years ago

0.0.1-alpha.375

2 years ago

0.0.1-alpha.378

2 years ago

0.0.1-alpha.379

2 years ago

0.0.1-alpha.373

2 years ago

0.0.1-alpha.362

2 years ago

0.0.1-alpha.343

2 years ago

0.0.1-alpha.341

2 years ago

0.0.1-alpha.342

2 years ago

0.0.1-alpha.325

2 years ago

0.0.1-alpha.326

2 years ago

0.0.1-alpha.340

2 years ago

0.0.1-alpha.329

2 years ago

0.0.1-alpha.327

2 years ago

0.0.1-alpha.328

2 years ago

0.0.1-alpha.332

2 years ago

0.0.1-alpha.333

2 years ago

0.0.1-alpha.330

2 years ago

0.0.1-alpha.331

2 years ago

0.0.1-alpha.336

2 years ago

0.0.1-alpha.337

2 years ago

0.0.1-alpha.334

2 years ago

0.0.1-alpha.335

2 years ago

0.0.1-oops.327

2 years ago

0.0.1

2 years ago

0.0.1-alpha.338

2 years ago

0.0.1-alpha.339

2 years ago

0.0.1-alpha.322

2 years ago

0.0.1-alpha.315

2 years ago

0.0.1-alpha.323

2 years ago

0.0.1-alpha.313

2 years ago

0.0.1-alpha.319

2 years ago

0.0.1-alpha.316

2 years ago

0.0.1-alpha.314

2 years ago

0.0.1-alpha.312

2 years ago

0.0.1-alpha.311

2 years ago

0.0.1-alpha.310

2 years ago

0.0.1-alpha.309

2 years ago

0.0.1-alpha.308

2 years ago

0.0.1-alpha.307

2 years ago

0.0.1-alpha.306

2 years ago

0.0.1-alpha.305

2 years ago