Git Product home page Git Product logo

vueuse's Introduction

VueUse - Collection of essential Vue Composition Utilities VueUse - Collection of essential Vue Composition Utilities
Collection of essential Vue Composition Utilities

NPM version NPM Downloads Docs & Demos Function Count
GitHub stars

๐Ÿš€ Features

  • ๐ŸŽช Interactive docs & demos
  • ๐Ÿ•ถ Seamless migration: Works for both Vue 3 and 2
  • โšก Fully tree shakeable: Only take what you want, bundle size
  • ๐Ÿฆพ Type Strong: Written in TypeScript, with TS Docs
  • ๐Ÿ”‹ SSR Friendly
  • ๐ŸŒŽ No bundler required: Usable via CDN
  • ๐Ÿ”ฉ Flexible: Configurable event filters and targets
  • ๐Ÿ”Œ Optional Add-ons: Router, Firebase, RxJS, etc.

๐Ÿฆ„ Usage

import { useLocalStorage, useMouse, usePreferredDark } from '@vueuse/core'

export default {
  setup() {
    // tracks mouse position
    const { x, y } = useMouse()

    // if user prefers dark theme
    const isDark = usePreferredDark()

    // persist state in localStorage
    const store = useLocalStorage(
      'my-storage',
      {
        name: 'Apple',
        color: 'red',
      },
    )

    return { x, y, isDark, store }
  },
}

Refer to functions list or documentations for more details.

๐Ÿ“ฆ Install

๐ŸŽฉ From v4.0, it works for Vue 2 & 3 within a single package by the power of vue-demi!

npm i @vueuse/core

Add ons | Nuxt Module

From v6.0, VueUse requires vue >= v3.2 or @vue/composition-api >= v1.1

Demos

CDN

<script src="https://unpkg.com/@vueuse/shared"></script>

<script src="https://unpkg.com/@vueuse/core"></script>

It will be exposed to global as window.VueUse

๐Ÿชด Project Activity

Alt

๐Ÿงฑ Contribute

See the Contributing Guide

๐ŸŒธ Thanks

This project is heavily inspired by the following awesome projects.

And thanks to all the contributors on GitHub!

๐Ÿ‘จโ€๐Ÿš€ Contributors

Financial Contributors on Open Collective

๐Ÿ“„ License

MIT License ยฉ 2019-PRESENT Anthony Fu

vueuse's People

Contributors

alfred-skyblue avatar anteriovieira avatar antfu avatar azaleta avatar btea avatar cawa-93 avatar chaii3 avatar curtgrimes avatar doctor-wu avatar ferferga avatar harmyderoman avatar huiliangshen avatar huynl-96 avatar jbaubree avatar lstoeferle avatar michealroberts avatar okxiaoliang4 avatar patak-dev avatar renovate[bot] avatar scottbedard avatar shinigami92 avatar sibbng avatar sun0day avatar sxzz avatar userquin avatar vaakian avatar waleed-kh avatar webfansplz avatar wheatjs avatar wvffle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vueuse's Issues

Review: Add JSDocs to functions

Add basic JSDocs to each function. The minimal work will be copying the first sentence of docs to it.

Checklist

This is a checklist of all the functions of VueUse. It's is useful for review or making changes the go through every function.

shared (21)

  • biSyncRef
  • controlledComputed
  • debouncedWatch
  • extendRef
  • makeDestructurable
  • pausableWatch
  • syncRef
  • throttledWatch
  • tryOnMounted
  • tryOnUnmounted
  • useDebounce
  • useDebounceFn
  • useInterval
  • useIntervalFn
  • useThrottle
  • useThrottleFn
  • useTimeout
  • useTimeoutFn
  • utils
  • watchWithFilter
  • when

core (51)

  • asyncComputed
  • createGlobalState
  • onStartTyping
  • useAsyncState
  • useBattery
  • useBrowserLocation
  • useClipboard
  • useCounter
  • useCssVar
  • useDeviceLight
  • useDeviceMotion
  • useDeviceOrientation
  • useDevicePixelRatio
  • useDocumentVisibility
  • useElementVisibility
  • useEventListener
  • useEventSource
  • useFavicon
  • useFullscreen
  • useGeolocation
  • useIdle
  • useIntersectionObserver
  • useLocalStorage
  • useMediaQuery
  • useMouse
  • useMouseInElement
  • useMutationObserver
  • useNetwork
  • useOnline
  • usePageLeave
  • useParallax
  • usePermission
  • usePreferredColorScheme
  • usePreferredDark
  • usePreferredLanguages
  • useRafFn
  • useRefHistory
  • useResizeObserver
  • useSessionStorage
  • useShare
  • useSpeechRecognition
  • useStorage
  • useTimestamp
  • useTitle
  • useTransition
  • useVModel
  • useWebSocket
  • useWebWorker
  • useWebWorkerFn
  • useWindowScroll
  • useWindowSize

router (2)

  • useRouteHash
  • useRouteQuery

integrations (3)

  • useAxios
  • useCookies
  • useQRCode

rxjs (4)

  • from
  • toObserver
  • useObservable
  • useSubscription

firebase (2)

  • useFirestore
  • useRTDB

Clean up useTransition function

A follow up to the conversation started here https://github.com/antfu/vueuse/issues/166#issuecomment-723396628. Our useTransition behavior can use a bit of polishing before the upcoming stable release. I'm using this issue just as a place to keep track of things.

  • Extract named presets to a tree shakeable constant
  • Improve documentation page to demonstrate all three easing function syntaxes (named preset, cubic bezier curve, and custom function)
  • Add a test to verify custom function support
  • Hoist useRafFn usage out of watch callback

Adding utility to test viewport visibility

First off, awesome repo you have here!

Would you accept a utility for determining a component's position within the viewport? This sort of thing can be handy when trying to defer expensive operations like data fetching or complex rendering. Here is a brief example of what I am proposing...

<template>
  <div>
    {{ elementIsVisible ? "I'm visible in the viewport" : "You can't see me" }}
  </div>
</template>

<script>
export default {
  setup() {
    const { elementIsVisible } = useElementVisibility();

    return { elementIsVisible };
  },
};
</script>

If you're open to this util, I'll put together a PR. And just for fun, here is a more realistic example showing how this kind of thing could be used to do infinite-scroll pagination ๐Ÿคทโ€โ™‚๏ธ

import { useElementVisibility } from '@vueuse/core'

export default {
  setup() {
    const { elementIsVisible } = useElementVisibility();

    return { elementIsVisible };
  },
  watch: {
    elementIsVisible(visible) {
      if (visible) this.$emit('enter-viewport');
    },
  },
};
<template>
  <div>
    <Whatever
      v-for="thing in things"
      :thing="thing"
      :key="thing.id"
    />
    <InfiniteScroll @enter-viewport="fetchMoreArticles" />
  </div>
</template>

Including @vueuse causes the vue instance to initialize twice @4.0.0-beta.4

This took me a while to track down, but after upgrading to @4.0.0-beta.4 my whole app started throwing a million errors as the main instance got initialised twice.

I used @4.0.0-beta.2 fine.

Not even sure how to describe this bug.

The library has great potential! Thank you for your work. I only use one function from it so i will be removing it for now.

I wish i could provide a simple bug, but at the moment we're in crunch mode to launch production and this has cost me 2 days already :(

I might return back with a proper issue once i have time.

Type error with usePermission declaration

When using the current version of this package and TypeScript 3.7.4, I get the following error on compilation:

ERROR in /my/folder/node_modules/@vueuse/core/index.d.ts(201,138):
201:138 Cannot find name 'State'.
    199 |     name: DescriptorNamePolyfill;
    200 | };
  > 201 | declare function usePermission(permissionDesc: GeneralPermissionDescriptor | PermissionDescriptor['name'] | DescriptorNamePolyfill): Ref<State>;
        |                                                                                                                                          ^
    202 |
    203 | declare function usePreferredColorScheme(): Readonly<Ref<"dark" | "light" | "no-preference">>;
    204 |

This appears to be because the function signature is exported but not the type from usePermission:

https://github.com/antfu/vueuse/blob/91a5c40130d195fdef42a36d9b3f5bbf12eff190/packages/core/usePermission/index.ts#L13

Add isSupported for useShare function

@antfu what do you think about adding isSupported to useShare? This will break the current implementation.

export async function useShare(shareOpts: ShareOptions) {
  const _navigator = (window.navigator as NavigatorWithShare)
  const isSupported = _navigator && _navigator.share

  const share = () => {
    if (isSupported) {
      let granted = true

      if (shareOpts.files && _navigator.canShare)
        granted = _navigator.canShare({ files: shareOpts.files })

      if (granted)
        return _navigator.share(shareOpts)
    }
  }

  return {
    isSupported,
    share,
  }
}

Demo

<script>
import { useShare } from '@vueuse/core'

setup() {
   const { isSupported, share } = useShare({ title: 'Hello', text: 'Hello my friend!', url: location.href })
   return {
     isSupported
     share,
   }
},
</script>

<div>
    <button @click="share" :disabled="!isSupported">Share</button>
</div>

i18n warning

got the warning when using the i18n package.

 warning  in ./node_modules/@vueuse/i18n/index.esm.js

"export 'default' (imported as 'Vue') was not found in 'vue'

the project freshly created with vue-cli with typescript and vue3 option.

Invalid Y coordinate in useMouseInElement()

Hello!

Just letting you know that here y.value is currently set to event.pageX and event.touches[0].clientX. There's also kind of the same problem a bit further down with elY.

Right now this causes y and elementY to return x and elementX respectively.

Thank you for your work!

Edit: I actually noticed this because I thought useParallax() was acting weird and indeed it looks like it's because of useMouseInElement() and elementY.

Types seems to be broken with composition-api v0.6.3

I get errors like

ERROR in node_modules/@vueuse/core/index.d.ts(1,21):
1:21 Cannot find module '@vue/composition-api/dist/reactivity/ref' or its corresponding type declarations.
  > 1 | import { Ref } from '@vue/composition-api/dist/reactivity/ref';

Same code works with composition-api v0.6.1

RFC: possible useRefHistory API improvements

Hey @antfu! Thanks for all the work with the lib โค๏ธ

Great to see you added a composable for ref history! We had to build one because the useUndo from vue-composable was not flexible enough for our use case. I was planning to submit a proposal for a similar one at one point. The API is not the same though, so I may release it as a separate lib since it has different tradeoffs. There are some API tweaks that could be useful in the current on in vueuse. If you like any of these changes, I could create PRs for them.

  1. Add option to avoid flush: 'sync'
    I think the default should be for it not to be 'sync'. We had several actions that were generating spurious history points because of this. An example could be to in a handler to change a size that is defined as {value,unit}, and you need to touch both. We could do this using pause/resume but it will be quite error prone in some apps.
  2. Rename history, redoHistory to prev, next
    This is the way it is in vue-composable useUndo. I think they are more in line with the rest of the API (undo, redo, clear) and it reads better when you use an object for the composable return:
const history = useRefHistory(aRef)
if( history.prev.length > 0 ) { ... } // instead of history.history
if( history.next.length > 0 ) { ... } // instead of history.redoHistory
  1. Expose batch(), commit() functions, that complements pause(), resume() (it can be discussed if we should have both pairs after adding batch and commit, IMO they both have different use cases)
    When doing real time changes, like dragging or playing with a slider, we want only one history point for the whole interaction. The code for this would be
history.batch()
// change state, across several user events (pointermove for example)

and when the interaction ends

history.commit()

If we want to do the same with pause(), resume(), we would need to add another set to the ref to trigger the history point after it is resumed.
I also think that batch(), commit() is better suited for this cases because we can add a cancel() function, that will go back to the last history point, finish the batch and resume history (it can also be called revert() if we want to follow a git analogy).
commit() can also let us build a manual history composable, with the same API, where the trigger is not automatic but the user is the one in charge of deciding when there is a history point. It also serves as a way to add a sync history point in case the user decides not to use flush: 'sync' but still needs it in a particular case.

I think the other differences with what I had in mind are more about extra features and configuration, and it is not clear to me that the gained flexibility will be enough to justify a more complex API in vueuse. This is why I think there could be space for another lib, with different tradeoffs (more options, but more time to learn it, and more verbose config). But the above proposals could be good for vueuse, and later if people migrate from vue-composable or to other libs, they would have a closer API.

"useEventSource" cannot actually close the connection

In my usecase,

 setup() {
    const amount = ref<number>(0);

    const { data, close, status } = useEventSource(
      "http://localhost:2222/cash"
    );

    watch(data, (data, _) => {
      amount.value = Number(data);
    });

    return { amount: computed(() => amount.value), close, status };
  }

I started the connection on setup and click to close the EventSource, but there is still "pending" on devtool even if the status turn into CLOSED.

Screenshot from 2020-10-14 14-44-31

In my own useEventSource code below, the connection can be closed correctly with status "canceled" on devtool.

Screenshot from 2020-10-14 14-54-00

export function useEventSource(url: string) {
  const state = ref<string>("");

  const source = new EventSource(url);

  source.onopen = e => {
    console.log("event source opened");
  };

  source.onmessage = function (e) {
    state.value = e.data;
  };

  source.onerror = function () {
    console.log("EventSource failed.");
    source.close();
  };

  const close = () => {
    source.close();
  };

  return {
    state: computed(() => state.value),
    close
  };
}

In my nodejs backend, the difference between useEventSource in the project and my useEventSource code is that my case can correctly print "client close the connection".

app.get("/cash", function (req, res) {
  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    Connection: "keep-alive"
  });
  res.connection.setTimeout(0);

  console.log("start casting coins");

  req.on("close", () => {
    console.log("client close the connection");
  });
});

I read the source code but I still don't know how to fix it and what's the difference they are.

Review of flush defaults

This is a review of the current usage of flush timing in vueuse. I think I understand better the reason the previous default for useRefHistory was 'sync' now. If we would have called this composable watchRefHistory, I think it will be easier to see why I pushed for 'pre'. If the name would be computedRefHistory, then 'sync' would be better. I wonder if using "watch" as prefix instead of "use" is not better, but maybe if the documentation is clear this is not a problem.

controlledComputed

controlledComputed is using flush: 'sync' and it is not configurable, I think this is correct because it is the way computed works.

syncRef, bySyncRef

syncRef defaults to 'sync', but in the docs it says the default is 'post'.
Because the name is syncRef, it is kind of hard to not use 'sync' as the default here. I think it also should behave like computed. Also, bySyncRef is not configurable and is using 'sync'
I can send a PR to change the default in the docs to 'sync'

useStorage

useStorage is using 'post' as its default and it is not configurable. Was 'post' used because there was a limitation about making flush configurable for this one?

when

when is using 'sync' as its default, but it looks more like a watcher to me. I think we could change its default to 'pre' to align it to the watch API

Adding addons with @vueuse/core dependency

Hi!

What's actually the recommend way to add composables from @vueuse/core to a @vueuse addon?

If I'm going to add for example an addon @vueuse/myaddon and using useLocalStorage from @vueuse/core
I see two options:

Option 1 - relative:
Via '../../composables/useLocalStorage' the useLocalStorage. Here the functions gets bundled in @vueuse/aws too
which is not necessarily wanted.

Option 2 - via package
'from @vueuse/core' which requires to add @vueuse/core to @vueuse/core as dependency including updating packages.json.

I would prefer first option 1 without bundling the function twice. Any ideas?

no createGlobalState export

Great Lib, Thanks a LOT ๏ผ
But it seems no createGlobalState in npm, while in the doc site. Please publish code in npm ?

useStorage("anyKey", true) defaults to false

Version: 2.0.26 (Vue 2)
Chrome: 81.0.4044.12 on OSX

const myBool = useStorage("anything", true);

watchEffect(() => {
  console.log(myBool.value); // prints false
});

I put a breakpoint in useStorage and in the read method, there seems to be a bug:

// rawValue is set to null if key is not in local storage
var rawValue = storage.getItem(key);

// check specifically looks for undefined but rawValue is null
if (rawValue === undefined && defaultValue) {

Due to the null/undefined mixup, the code enters the else clause and there seems to be an issue there too.

data.value = Serializers[type].read(rawValue, defaultValue);

If passes in two values to the serializer (rawValue=null, defaultValue=true), but the serializer's read method only takes one argument:

boolean: {
        read: function (v) { return v === 'true'; },
        write: function (v) { return String(v); },
    },

Since the first argument is null, it returns false.

bundle not ES5 compatible, breaking IE11

Yes, we still do support IE11. We hope to be able to drop it soon, but today we still do. We have quite some dependencies and all of them seem to ship ES5 compatible bundles except vueuse. Is this intentional?

API review, useRefHistory flush default

Hello!
Awesome to see the preparation for the first stable release https://github.com/antfu/vueuse/issues/166 ๐ŸŽ‰

We have been using useRefHistory for https://github.com/Leniolabs/layoutit-grid using the extended API and it has been working well. The only thing that I am still not sure of is the right API choice to freeze is the default flush:sync. I think we should still try to make it work with the same default, 'pre', as watch/watchEffect.

I had to import batch in several places to fix issues with the flush:sync. I could have placed them in the actions, but it is still easy to get spurious history points. There also seems to be an issue with array refs and splice. Looks like calling splice is generating two history points (maybe a bug in Vue.js itself?).

I have an idea to use two watchers that may enable us to offer pre/post (and also sync as an option), so we could choose pre as the default. I still have to see if it works, but if not, I still think we should try to find a solution.

@antfu should I create a PR against the new dev branch if I managed to get it right? What do you think?

yarn test ๆŠฅ้”™

FAIL packages/core/useTimeout/index.test.ts
โ— export

[vue-composition-api] must call Vue.use(plugin) before using any function.

  2 |
  3 | export function useTimeout(interval = 1000, startRightNow = true) {
> 4 |   const ready = ref(false)
    |                 ^
  5 |
  6 |   let timer: any = null

PASS packages/core/useCounter/index.test.ts
FAIL packages/core/useWindowSize/index.test.ts
โ— useWindowSize โ€บ should work

expect(received).toBe(expected) // Object.is equality

Expected: 1024
Received: undefined

  17 |     })
  18 |
> 19 |     expect(wrapper.vm.width).toBe(window.innerWidth)
     |                              ^
  20 |     expect(wrapper.vm.height).toBe(window.innerHeight)
  21 |   })

โ— useWindowSize โ€บ sets handler for window "resize" event

expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: "resize", Anything, undefined

Number of calls: 0

  29 |     })
  30 |
> 31 |     expect(windowAddEventListener).toHaveBeenCalledWith('resize', expect.anything(), undefined)
     |                                    ^
  32 |   })
  33 | })

useStorage

  let rawValue = storage.getItem(key)
  if (rawValue === undefined && defaultValue) {
    rawValue = Serializers[type].write(defaultValue)
    storage.setItem(key, rawValue)
  } else {
    data.value = Serializers[type].read(rawValue, defaultValue)
  }

localStorage.setItemๆ–นๆณ•ๅฟ…้กป็ฉฟไฟฉไธชๅ‚ๆ•ฐ๏ผŒไธไผšๅ‡บ็Žฐๆœ‰key๏ผŒๅ€ผๆ˜ฏundefined็š„ๆƒ…ๅ†ตๅง๏ผŸ่ฟ™ไธชๅˆคๆ–ญ็š„ๆ„ไน‰ๆ˜ฏ๏ผŸ

List of issues with current documentation

While this repo is currenly under heavy development, I though creating an Issue would be better than a PR.

useIntersectionObserver

  • API has changed but usage example on docs not updated yet.

useParallax

  • Remote source have SSL issues. Chrome forces to load images on https. You can't access that sources unless you manually visiting sources and ignoring ssl warning.
  • tilt and roll says .nan and demo not working.

useAsyncState

  • Demo not working.

useTimeoutFn, useTimeout, useAsyncState

  • Navigating to other pages from this pages says Maximum call stack size exceeded

i wanna add a @vueuse/rx addon

Hello i wanna add an addon to vue use to use rxjs like

import { useSubscription, from, fromEvent, toObserver } from "@vueuse/rx"
import { interval, Subject } from "rxjs"
import { takeUntil, mapTo } from "rxjs/operators"

...
const button = ref<HtmlButtonElement>(null)
// or
const button = new Subject()
const counter = ref<number>(0)
useSubscription(
  from(counter).subscribe(v => console.log(v))
)
useSubscription( // it allows auto unsubscribe
  interval(1000).pipe(
    takeUntil(fromEvent(button, 'click')),
//or
    takeUntil(button),
    mapTo(1),
  ).subscribe(toObserver(counter))
)
...
<button ref="button" />
or
<button @click="button.next" />

Typescript error on ResizeObserver

ERROR in .../node_modules/@vueuse/core/dist/index.d.ts(1,23):
1:23 Cannot find type definition file for 'resize-observer-browser'.
  > 1 | /// <reference types="resize-observer-browser" />
      |                       ^
    2 | import { Ref, WatchStopHandle, ComputedRef, WatchOptions } from 'vue-demi';
    3 | import { Ref as Ref$1, UnwrapRef, WatchStopHandle as WatchStopHandle$1, ComputedRef as ComputedRef$1 } from 'vue-demi';
    4 | export * from '@vueuse/shared';
ERROR in .../node_modules/@vueuse/core/dist/index.d.ts(377,87):
377:87 Cannot find name 'ResizeObserverCallback'.
    375 | declare function useRefHistory<Raw, Serialized = Raw>(current: Ref<Raw>, options?: UseRefHistoryOptions<Raw, Serialized>): UseRefHistoryReturn<Raw, Serialized>;
    376 | 
  > 377 | declare function useResizeObserver(el: Ref<HTMLElement | null | undefined>, callback: ResizeObserverCallback): {
        |                                                                                       ^
    378 |     stop: WatchStopHandle$1;
    379 | };
    380 | 
Version: typescript 4.0.3

'const' enums are not supported

Hi ๐Ÿ‘‹

I wish to contribute but unable to run yarn dev due to a syntax error in useWebWorkerFn:

'const' enums are not supported

what am I missing? ๐Ÿค”
Thanks!

Node v12.11.1
Yarn 1.22.10
MacOS 10.15.5

Feature: eventBus

Hi! In Vue3, vue instance no longer implement the event emitter interface.

So eventBus will no longer be available.

import Vue from 'vue';
const bus = new Vue();

bus.$on('xxx', '...');
bus.$emit('xxx', '...');

there's a way to implement this event emitter/pubsub feature by composition-api?

Proposal for creation of useIntersectionObserver

Currently useElementVisibility seems to make use of listening to the document scroll and tests if the element is visible each time it changes. I think it would also be good to have a composable that makes use of the intersection observer api. I have created a basic implementation myself here https://gist.github.com/jacobclevenger/86653ce2335073833cd13fb2b74b38ae and it works like this

<template>
    <div ref="self">Is Visible: {{isIntersecting}}</div>
</tempate>
<script lang="ts" setup>
import { ref } from 'vue'
import { useIntersectionObserver } from './useIntersectionObserver'

export const self = ref<HTMLElement | null>()
export const { onIntersected, onNotIntersected, isIntersecting } = useIntersectionObserver()

onIntersected(() => {
  console.log('Is Intersecting')
})

onNotIntersected(() => {
  console.log('Is Not Intersecting')
})
</script>

Not this implementation also allows you to pass in useIntersectionObserver(el, true) which will make the intersection observer fire once and then it will stop observing the element visibility.

I'm not sure if this fits with this project, but I have found this to be useful for myself so I thought I would propose it here as well.

useAxios - async chaining?

Hi there, is there any way how to utilize more useAxios hooks and put them in a chain? How to do that? Thank you!

vue2 useFirestore TS types error

Error:

139:44 No overload matches this call.
  Overload 1 of 2, '(docRef: DocumentReference<TaskList[]>, errorHandler?: ((err: Error) => void) | undefined): Ref<TaskList[] | null>', gave the following error.
    Argument of type 'CollectionReference<DocumentData>' is not assignable to parameter of type 'DocumentReference<TaskList[]>'.
      Type 'CollectionReference<DocumentData>' is missing the following properties from type 'DocumentReference<TaskList[]>': collection, set, update, delete
  Overload 2 of 2, '(docRef: Query<TaskList[]>, errorHandler?: ((err: Error) => void) | undefined): Ref<TaskList[][]>', gave the following error.
    Argument of type 'CollectionReference<DocumentData>' is not assignable to parameter of type 'Query<TaskList[]>'.
      The types returned by 'where(...)' are incompatible between these types.
        Type 'Query<DocumentData>' is not assignable to type 'Query<TaskList[]>'.
          Type 'DocumentData' is missing the following properties from type 'TaskList[]': length, pop, push, concat, and 28 more.

Code:

      type ID = string

      interface Task {
        id: ID
        title: string
        isDone: boolean
      }

      interface TaskList {
        id: ID
        title: string
        items: Task[]
      }
      const tasksCollection = db
        .collection('users')
        .doc(userId)
        .collection('tasks')

      const tasks = useFirestore<TaskList[]>(tasksCollection)

versions:

    "vue": "^2.6.11",
    "typescript": "^3.9.2",
    "firebase": "^7.14.4",
    "@vue/composition-api": "^0.3.4",
    "@vueuse/core": "^2.0.27",
    "@vueuse/firebase": "^2.0.27",

Run npm run dev, but failed for lack dependencies.

after install the dependcies, I run npm run dev to start the storybook but failed.
from the error stack I noticed that three dependcies cannot be found:

  • universal-cookie (in useCookie)
  • qrcode (in useQRCode)
  • @vueuse/shared (in some other dirs)

Should these three packages be added in the package.json ?

Usign useRefHistory and useStorage together

If I want to add support to save to local storage the app state, so the state will be preserved next time the app is reloaded

const state = ref({ ... })
function serializeState(state) { ... }
function parseState(state) { ... }

Right now I need to do something like this:

const { undo, redo, pause, resume, history } = useRefHistory(state,{
  dump: serializeState, // custom dump, to avoid double serialization 
  parse: parseState
})
const stateStorage = useStorage('app-state')
watch( history, () => { 
  // user needs to know that last history point is in history[0] and not at the end 
  stateStorage.value = history.value[0] // serialized because dump: serializeState
}, { deep: true }) // we need to watch deeply the history array

I want to watch the history instead of the current state ref because I am using pause and resume while the user is dragging stuff around (and I only want to generate one history point for the whole interaction).

I think this is a common case, and there are several details that people could get wrong. We could add a section to the docs to show how to use these two composables together, but maybe we could extend the API of useRefHistory to simplify this pattern.

Adding a last history ref

const { undo, redo, pause, resume, last } = useRefHistory(state,{
  dump: serializeState,
  parse: parseState
})
const stateStorage = useLocalStorage('app-state')
watch( last, () => { 
  stateStorage.value = last.value // serialized because dump: serializeState
})

This removes the need for { deep: true } and to know that history[0] is the last history point

New option for useStorage

const { undo, redo, pause, resume, last } = useRefHistory(state,{
  dump: serializeState,
  parse: parseState
})
const stateStorage = useLocalStorage('app-state',{ track: last })

I do not find a good name for the option, but the idea will be that everytime that the ref changes, stateStorage is actualized. We could also ask users to do this instead:

const stateStorage = useLocalStorage('app-state')
syncRef( last, stateStorage, { flush: 'pre' })

New composable

const { undo, redo, pause, resume, storage } = useStoredRefHistory(state,{
  dump: serializeState, // custom dump, to avoid double serialization 
  parse: parseState,
  storage: { key: 'app-state', ...otherStorageOptions }
})

I think that this use case may so common that it may justify this last option (name could also be useRefHistoryWithStorage)

What do you think? I am missing a better option?

Roll out from beta

Since Vue 3 has officially released for a while now. I think it's time for us to roll out from beta aim for a stable release.

Checklist

  • Review functions, frozen the APIs (consistency, flexibility, simplicity)
    • It should be our last chance (at this phrase) to introduce breaking changes to the existing functions. Breaking changes should be working on the dev branch.
    • Make global reference configurable #184
    • Docs should not contain JSX, @vue/composition-api, vue-demi, etc.
    • JSX docs #183
    • Filters system #192
  • Unit-tests for utilties as possible
    • It's ok for not having tests for simple web API wrappers.
  • Setup bundle size GitHub Actions via export-size
  • Demo rewrites working by @anteriovieira

Functions

  • useStorage: debounce
  • useShare: returns a function instead of call it immediately, #176

Docs

Preview: https://dev--vueuse.netlify.app/

  • Path redirecting, support short link like vueuse.js.org/useMouse
  • Write a doc about how to use the functions #191
    • reactive to unwrap the refs
    • configurable window, document
    • timing
    • filter system

Preview Opt-in (Nightly Builds)

npm package, powered by Nightly Build

To replace the package with nightly build:

via npm

npm i @vueuse/core@npm:@knightly/vueuse@dev

or edit your package.json

"dependencies": {
  "@vueuse/core": "npm:@knightly/vueuse@dev"
}

New Features

  • New @vueuse/router package

  • Event filter system

  • pausableWatch, debouncedWatch, thottledWatch, watchWithFilter

Migration Guide

BREAKING CHANGE

useTransition - named transition presets are removed. Import them from TransitionPresets intead. #190
import { useTransition } from '@vueuse/core'

useTransition(baseNumber, {
  duration: 1000,
  transition: 'easeInOutCubic',
})

Changed to

import { useTransition, TransitionPresets } from '@vueuse/core'

useTransition(baseNumber, {
  duration: 1000,
  transition: TransitionPresets.easeInOutCubic,
})
asyncComputed - evaluating state is now passed through arguments instead of returning tuple
import { asyncComputed } from '@vueuse/core'

const [state, evaluating] = asyncComputed(async () => {}, {})

Changed to

import { asyncComputed } from '@vueuse/core'

const evaluating = ref(false)
const state = asyncComputed(async () => {}, {}, evaluating)
useEventListener - event target moved from 4th argument to first
import { useEventListener } from '@vueuse/core'

useEventListener('click', handler, undefined, document)

Changed to

import { useEventListener } from '@vueuse/core'

useEventListener(document, 'click', handler)
useRefHistory - `flush` now default to `pre`, returned `current` renamed to `source`, hisotry point `value` renamed to `snapshot`
Refer to docs for more details.
useWebWorkerFn - `workerStatus` changed from enum to literal unions
import { useWebWorkerFn, WorkStatus } from '@vueuse/core'

const { workerStatus } = useWebWorkerFn(fn)

workerStatus.value === WorkStatus.running

Changed to

import { useWebWorkerFn } from '@vueuse/core'

const { workerStatus } = useWebWorkerFn(fn)

workerStatus.value === 'RUNNING'
useNow - `useNow` renamed to `useTimestamp` with API changes
import { useNow } from '@vueuse/core'

const now = useNow()

Changed to

import { useTimestamp } from '@vueuse/core'

const { timestamp: now, pause, resume } = useTimestamp()
useRaf - dropped in favor of `useTimestamp`
None
useTimeout / useInterval - returned `activated` renamed to `isActive`
None
useRafFn - `start` / `stop` renamed to `resume` / `pause`
None
useXXXObserver - API changes

Refer to docs and types for more details.

Review: Make global dependencies configurable

Global dependencies such as window, document, navigator should be configurable. #173

Checklist

This is a checklist of all the functions of VueUse. It's is useful for review or making changes the go through every function.

shared (21)

  • biSyncRef
  • controlledComputed
  • debouncedWatch
  • extendRef
  • makeDestructurable
  • pausableWatch
  • syncRef
  • throttledWatch
  • tryOnMounted
  • tryOnUnmounted
  • useDebounce
  • useDebounceFn
  • useInterval
  • useIntervalFn
  • useThrottle
  • useThrottleFn
  • useTimeout
  • useTimeoutFn
  • utils
  • watchWithFilter
  • when

core (51)

  • asyncComputed
  • createGlobalState
  • onStartTyping
  • useAsyncState
  • useBattery
  • useBrowserLocation
  • useClipboard
  • useCounter
  • useCssVar
  • useDeviceLight
  • useDeviceMotion
  • useDeviceOrientation
  • useDevicePixelRatio
  • useDocumentVisibility
  • useElementVisibility
  • useEventListener
  • useEventSource
  • useFavicon
  • useFullscreen
  • useGeolocation
  • useIdle
  • useIntersectionObserver
  • useLocalStorage
  • useMediaQuery
  • useMouse
  • useMouseInElement
  • useMutationObserver
  • useNetwork
  • useOnline
  • usePageLeave
  • useParallax
  • usePermission
  • usePreferredColorScheme
  • usePreferredDark
  • usePreferredLanguages
  • useRafFn
  • useRefHistory
  • useResizeObserver
  • useSessionStorage
  • useShare
  • useSpeechRecognition
  • useStorage
  • useTimestamp
  • useTitle
  • useTransition
  • useVModel
  • useWebSocket
  • useWebWorker
  • useWebWorkerFn
  • useWindowScroll
  • useWindowSize

router (2)

  • useRouteHash
  • useRouteQuery

integrations (3)

  • useAxios
  • useCookies
  • useQRCode

rxjs (4)

  • from
  • toObserver
  • useObservable
  • useSubscription

firebase (2)

  • useFirestore
  • useRTDB

Issue with createGlobalState

createGlobalState stops tracking changes after component that first used global state is disposed.

Tried it with vue@3 and can reproduce it there too, so it is not @vue/composition-api issue.

Added pull request with reproduction tests: #129

State easing

While I'm in here, would you mind if I added one more util to the library? This one would be for transitioning state along cubic bezier curves. Below is an example of what I'm proposing...

<template>
  <div>
    <input v-model.number="baseNumber" /> {{ number }}
  </div>
</template>

<script>
export default {
  setup() {
    const baseNumber = ref(0)

    const number = useStateTransition(baseNumber, {
      duration: 1000,
      steps: 30, // probably a reasonable default, but allows for custom framerates
      transition: [0.77, 0, 0.175, 1] // maybe have aliases like 'easeInOutQuart'?
    })

    return { baseNumber, number }
  }
}
</script>

Feature Request: New Hook useWorkerFunction

Hey, i would like to contribute a port of https://github.com/alewin/useworker.
Its a Hook to extract heavy operation right in your Component Code without writing extra files. It uses Object Url to create workers at runtime and represent workers as promises.
I really like it and i would like to use it in Vue. What do you think of it?

I've done some work already, but would like to get some Feedback first.

First thing i am struggleing with is babel. It converts the code i am extracting to the worker, which is fine but then uses babel helper functions in the extracted code, wich aren't available in the worker context. How can i solve that issue? Is there a way to tell babel, this is worker code dont use helpers? Or is this a thing the limits the ability of that hook?
Somehow i haven't had any issues with that in react

Incorrect type definition file for Vue 3 version of Vueuse.

The type definition file for the Vue 3 version of Vueuse attempts to import @vue/composition-api which causes errors at build time. I don't believe this package is needed for Vue 3 and installing it causes more errors as it depends on Vue 2

Relevant Packages:

"@vueuse/core": "^3.0.34",
"core-js": "^3.6.4",
"vue": "^3.0.0-beta.17"

Error Log:

ERROR  Failed to compile with 2 errors5:22:59 AM
1:22:59 AM:  error  in /opt/build/repo/node_modules/@vueuse/core/index.d.ts
1:22:59 AM: ERROR in /opt/build/repo/node_modules/@vueuse/core/index.d.ts(1,51):
1:22:59 AM: 1:51 Cannot find module '@vue/composition-api' or its corresponding type declarations.
1:22:59 AM:   > 1 | import { Ref, WatchStopHandle, ComputedRef } from '@vue/composition-api';
1:22:59 AM:       |                                                   ^
1:22:59 AM:     2 | import { Ref as Ref$1 } from '@vue/runtime-dom';
1:22:59 AM:     3 | 
1:22:59 AM:     4 | declare function createGlobalState<T extends object>(factory: () => T): () => T;
1:22:59 AM:  error  in /opt/build/repo/node_modules/@vueuse/core/index.d.ts
1:22:59 AM: ERROR in /opt/build/repo/node_modules/@vueuse/core/index.d.ts(7,23):
1:22:59 AM: 7:23 Cannot find module '@vue/composition-api' or its corresponding type declarations.
1:22:59 AM:      5 | 
1:22:59 AM:      6 | declare function useAsyncState<T>(promise: Promise<T>, defaultState: T, delay?: number, catchFn?: (e: Error) => void): {
1:22:59 AM:   >  7 |     state: Ref<import("@vue/composition-api").UnwrapRef<T>>;
1:22:59 AM:        |                       ^
1:22:59 AM:      8 |     ready: Ref<boolean>;
1:22:59 AM:      9 | };

Async Computed Values

I've been wanting something like vue-async-computed for Vue's composition API, but couldn't find anything so I created it myself. I made a gist with an explainer and an initial implementation here.

Because of its generic nature and broad use cases, the useAsyncComputed function may be a nice counterpart to the existing useAsyncState.

What do you think?

Page visibility util

Hi, sorry I know I've been spamming this repo a bit lately, but I've got just one more util if you're open to it. I'd like to add a util to detect if the window is active / minimized. This can be useful for things like auto-pausing media, updating the document title, etc...

// hidden and visibility would be reactive aliases of
// document.hidden and document.visibilityState

const { hidden, visibility } = usePageVisibility({
  onChange() {
    // ...
  },
  onHide() {
    // ...
  },
  onShow() {
    // ...
  }
});

Extended finite options or composability using filters (was debouncing option for useStorage)

I was looking into the debouncing option you raised for useStorage and I wanted to first see if the same can be achieved in a more flexible way.

Please take this as a dump of ideas and not a definite API. I thought about this while trying to design the API for other composables, and I want to share it in case it is useful in some way for vueuse.

The problem that I see with adding a denounce option is that we may also want to add a throttle one later (or pausable, or other ideas we may have later). We are adding complexity to the main composable, and users will need to pay for this even if they do not use it. There are other composables like useRefHistory where users may expect the same functionality.

So, what if the API lets the user define the filtering function to be used? I think you called it updater in the useDebounce implementation. I am using filter as the option name just because it is called like that in Rx, but I am not married with the name. The signature for filter is ( (fn) => void ) => void

const count = useStorage('counter', 0, { filter: debounceFilter(200) })
const count = useStorage('counter', 0, { filter: throttleFilter(300) })
const { filter, pause, resume } = pausableFilter() 
const count = useStorage('counter', 0, { filter })

debounceFilter could be implemented as:

export function debounceFilter(delay = 200) {
  return (fn) => useDebounceFn(() => fn(), delay)
}

The idea is that inside useStorage, instead of a direct watch(data, commit, options) we use watch(data, filter(commit), options)
So, the filter option gives users the possibility to decide which triggered values to accept from the watch.
Also, if we have these filters in the lib, we can also implement useDebounceRef, useThrotleRef, etc using a more general useFilteredRef

export function pausableFilter() {
  const tracking = ref(true)
  function pause() {
    tracking.value = false
  } 
  function resume() {
    tracking.value = true
  }
  function filter(fn) {
    return () => {
      if( tracking.value ) {
        fn()
      }
  }
  return { tracking, pause, resume, filter }
}

The filters are composable also, allowing users to create pausable throttled storage for example

const { filter, pause, resume } = pausableFilter() 
const count = useStorage('counter', 0, { filter: filter(throttleFilter(300)) })

And they can actually create their own filters, pausing or delaying according to their app needs (using other app refs, etc)

I also wonder if we could simplify useRefHistory by removing the pausable part out of the main composable, and letting users choose if they want that functionality

const data = ref(0)
const { filter, pause, resume } = pausableFilter() 
const { undo, redo } = useRefHistory(data, { filter })

It is also good that we are not adding an extra watch for every filter. Another possible API for composables that are watching an input ref is to expect the user to give us a filtered ref, something like:

const data = ref(0)
const { pausableRef, pause, resume } = usePausableRef(data)
const { undo, redo } = useRefHistory(pausableRef)

This only works with API that are tracking an input ref (so we can not use it in useStorage), but we could offer this possibility also.

I think there are other possible APIs we could explore. I thought about letting the user give us the watch function to be used, but then you may need to use the same options (flush, deep) in several places.
For common cases, we can also bundle filters for convenience like:

const data = ref(0)
const { undo, redo, pause, resume } = usePausableRefHistory(data)

implemented as

export function usePausableRefHistory(ref, options) {
  const { filter, pause, resume } = pausableFilter() 
  return { ...useRefHistory(data, { filter }), pause, resume }
}

So we can still offer the general composable and specialized ones, and users will only pay for what they use. Take the pausable filter extraction as an example to extrapolate to other cases, because the current API allows users to commit using resume(true). There may be a better API to also support external triggers. Or the filter may also receive the value, so you can implement validation filters, remove values if they are negative, etc. Or that maybe another option orthogonal to this one.

What do you think? Is something like a filter option worth exploring so we do not need to implement debounce/throttle/pausable in each composable?

Disclaimer: I do not know if I can actually do this myself but looks interesting, so at least I wanted to share it ๐Ÿ˜ƒ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.