justintaddei / v-wave

The material-ripple directive for Vue that actually works
https://justintaddei.github.io/v-wave/
MIT License
388 stars 15 forks source link
material-design micro-interactions microinteractions nuxtjs vue vuejs

v-wave

The material-ripple directive for Vue that actually works

GitHub Actions Workflow Status Vue Support Issues NPM version Downloads per month Total downloads Language License

Also available for React: use-wave

Why did I make this?


Because every ripple plugin I've tried to use in the past either didn't work or was missing basic features. **Here's what you can expect from this plugin:** - It works ([see for yourself](https://justintaddei.github.io/v-wave)). - The wave appears on `pointerdown` instead of `pointerup` _(you might think that's an obvious choice... but you'd be wrong)._ - The wave responds to keyboard events on keyboard-accessible elements (i.e. Enter and Space on `

[Live Demo]

Quick start

After installing and registering the plugin, this is all you need to get started:

<button v-wave>Click here</button>

Example of default options

Out of the box, this will provide you with a ripple that matches the text color of the element it has been applied to, with reasonable defaults for a responsive feeling ripple.
You can change the look and feel of the ripple on a per-element basis, or by modifying the global defaults.

Contents

Installation

See: npm, cdn

Via NPM

See: Vue, Nuxt

$ npm i v-wave

Vue

import { createApp } from 'vue'
import VWave from 'v-wave'
import App from './App.vue'

const app = createApp(App)

app.use(VWave)
Vue 2 ```js // Vue 2 import Vue from 'vue' import VWave from 'v-wave' Vue.use(VWave) ```

or

Nuxt

// nuxt.config.js

// Nuxt 3
export default {
    modules: ['v-wave/nuxt']
}

// Nuxt 2
export default {
    modules: ['v-wave/nuxt/v2']
}

Via CDN

Expand examples ```html ``` ```js // With a CDN, `VWave` is made available as a global Vue.use(VWave) ```

Configuration

See: configuring globally, configuring locally

Configuring globally

See: Vue, Nuxt

Vue

import { createApp } from 'vue'
import VWave from 'v-wave'
import App from './App.vue'

const app = createApp(App)

app.use(VWave, {
  color: 'red',
  initialOpacity: 0.5,
  easing: 'ease-in'
})
Vue 2 ```js // Vue 2 import Vue from 'vue' import VWave from 'v-wave' Vue.use(VWave, { color: 'red', initialOpacity: 0.5, easing: 'ease-in' }) ```

or

Nuxt

// nuxt.config.js

export default {
  modules: ['v-wave/nuxt'],
  vWave: {
    color: 'red',
    initialOpacity: 0.5,
    easing: 'ease-in'
  }
}

Configuring locally

<button
  v-wave="{
    color: 'red',
    initialOpacity: 0.5,
    easing: 'ease-in',
}"
>
  Click here
</button>

Options

See: summary, details

Summary

Name Default Type
color "currentColor" string
initialOpacity 0.2 number
finalOpacity 0.1 number
duration 0.4 number
dissolveDuration 0.15 number
waitForRelease true boolean
easing ease-out string
cancellationPeriod 75 number
trigger "auto" string \| boolean \| "auto"
disabled false boolean
respectDisabledAttribute true boolean
respectPrefersReducedMotion true boolean
stopPropagation false boolean
tagName "div" string

Details

color

Sets the background of the ripple.
Supports any value that the CSS background property does.

Expand examples See: [color](#simple-color-), [gradient](#gradient-), [image](#image-) #### Simple color ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-red.gif) #### Gradient ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-gradient.gif) #### Image ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-image.gif)

initialOpacity

The opacity of the ripple when it first appears.

Expand examples See: [initialOpacity: 1](#initialopacity-of-1-), [initialOpacity: 0](#initialopacity-of-0-) #### initialOpacity of 1 ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-initial-opacity-1.gif) #### initialOpacity of 0 ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-initial-opacity-0.gif)

finalOpacity

The opacity the ripple should be when it has stopped moving.

Expand examples See: [finalOpacity: 1](#finalopacity-of-1-), [finalOpacity: 0](#finalopacity-of-0-) #### finalOpacity of 1 ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-final-opacity-1.gif) #### finalOpacity of 0 ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/color-final-opacity-0.gif)

duration

The duration of the ripple in seconds.
The total duration is duration + dissolveDuration

Expand example #### duration of 3 seconds ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/duration-3s.gif)

dissolveDuration

The duration of the "dissolve animation" in seconds.
This is the fade-out animation that plays once the wave has reached its maximum size.
The total duration is duration + dissolveDuration

Expand example #### dissolve duration of 3 seconds ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/dissolve-duration-3s.gif)

waitForRelease

When true, the wave will not dissolve until the user releases the pointer.

easing

Any valid CSS <easing-function> (see more)

Expand example #### cubic-bezier ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/easing.gif)

cancellationPeriod

The delay, in milliseconds, during which the animation will be canceled if the user moves their figure/pointer (e.g. while scrolling on a mobile device).

Note: The ripple will not appear until after the delay. This means a delay greater than 100ms can feel sluggish.

trigger

Sets the behavior of the wave when used with triggers. (See the dedication section on triggers for more details).

Expand example #### basic trigger ```html ``` ![](https://raw.githubusercontent.com/justintaddei/v-wave/assets/tigger.gif)

disabled

Disables the wave effect on the element regardless of respectDisabledAttribute.

respectDisabledAttribute

When true, the wave effect will be disabled if the html disabled attribute is present on the element.

<!-- The wave will *not* appear on this button -->
<button v-wave disabled>Click me!</button>
<!-- The wave *will* appear on this button -->
<button v-wave="{respectDisabledAttribute: false}" disabled>Click me!</button>

respectPrefersReducedMotion

If true, the wave effect will be disabled if the user's prefers-reduced-motion preference is set to reduce.

stopPropagation

Prevents the pointerdown event from propagating to parent elements.

tagName

Sets the tag name of the element used as the wave container. This is is useful in scenarios where the default div may interfere with :last-of-type or similar selectors.


Using triggers

Triggers allow you to activate a wave on an element when, and only when, a different element receives input.

In the following example, the wave will only activate for the label element when the user clicks or taps on the <img/>.

<label v-wave>
  <span>Password</span>
  <input :type="showPassword ? 'text' : 'password'" />
  <img v-wave-trigger src="https://github.com/justintaddei/v-wave/raw/master/eye.svg" @click="() => showPassword = !showPassword" />
</label>

In this next example, clicking one of the buttons will activate the wave on the other button.

<button v-wave="{trigger: 'button2'}" v-wave-trigger:button1>Button 1</button>

<button v-wave="{trigger: 'button1'}" v-wave-trigger:button2>Button 2</button>

Triggers that use an ID support many-to-many relationships. See the grid example on the example page.

Advanced

Registering the directive locally

Local registration with Composition API:

<script>
  import VWave from 'v-wave'
  const { vWave, vWaveTrigger } = VWave.createLocalWaveDirective({
    /* global options */
  })
</script>

<template>
  <button v-wave>Click me!</button>
</template>

Local registration with Options API:

<script>
  import VWave from 'v-wave'
  const { wave, waveTrigger } = VWave.createLocalWaveDirective({
    /* global options */
  })

  export default {
    directives: {
      wave,
      waveTrigger
    }
  }
</script>

<template>
  <button v-wave>Click me!</button>
</template>
Vue 2 If you are using Vue 2, you need to pass `"vue2"` as the second argument to `createLocalWaveDirective` ```html ```

Changing the directive's name

If you are migrating from another ripple directive you can change the name of the directive v-wave uses if you want to avoid changing it in your source code.
Simply pass a new name for the directive using the directive option:

//main.js

import Vue from 'vue'
import VWave from 'v-wave'

Vue.use(VWave, {
  directive: 'ripple'
})

Now you can use the plugin like so:

<button v-ripple>Click me!</button>

Keep in mind that this option can only be set globally (i.e. it cannot be set on individual directives).

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for more details.

License

This project is distributed under the MIT License.

The MIT License (MIT)

Copyright (c) 2021 Justin Taddei

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.