Skip to content

Commit

Permalink
feat: add visibilityState (#88)
Browse files Browse the repository at this point in the history
* feat: add visibilityState

* visibility add tests and add hidden

* rename visibilityState to pageVisibility

* added documentation
  • Loading branch information
pikax committed Jan 18, 2020
1 parent c47b7e7 commit 3b86c6b
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]

---

### Added

- [Online](<[composable/web](https://pikax.me/vue-composable/composable/web)/online>) - reactive `navigator.onLine` wrapper
- [PageVisibility](https://pikax.me/vue-composable/composable/web/pageVisibility) - reactive `Page Visibility API`

## 1.0.0-dev.4

Expand Down
36 changes: 36 additions & 0 deletions docs/.vuepress/components/PageVisibilityExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<div>
<h4>
Hidden: <b>{{ hidden }}</b>
</h4>
<h4>
State: <b>{{ visibility }}</b>
</h4>
<p>You can change the state by switching tab - Check console</p>
<p>
<a
href="https://sqa.stackexchange.com/a/32355"
target="_blank"
rel="noopener noreferrer"
>Check this link</a
>
</p>
</div>
</template>

<script>
import { usePageVisibility, unwrap } from "vue-composable";
import { watch, reactive } from "@vue/composition-api";
export default {
setup() {
const { visibility, hidden } = usePageVisibility();
watch(visibility, () => {
console.log("visibility changed", {
visibility: visibility.value,
hidden: hidden.value
});
});
return { visibility, hidden };
}
};
</script>
3 changes: 2 additions & 1 deletion docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ module.exports = {
["composable/web/webSocket", "webSocket"],
["composable/web/intersectionObserver", "IntersectionObserver"],
["composable/web/networkInformation", "NetworkInformation"],
["composable/web/online", "Navigator.onLine"]
["composable/web/online", "Navigator.onLine"],
["composable/web/pageVisibility", "PageVisibilityAPI"]
]
},
{
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Check out the [examples folder](examples) or start hacking on [codesandbox](http
- [IntersectionObserver](composable/web/intersectionObserver) - reactive `IntersectionObserver`
- [NetworkInformation](composable/web/networkInformation) - reactive `NetworkInformation` wrapper
- [Online](composable/web/online) - reactive `navigator.onLine` wrapper
- [PageVisibility](composable/web/pageVisibility) - reactive `Page Visibility API`

### External

Expand Down
65 changes: 65 additions & 0 deletions docs/composable/web/pageVisibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Page Visibility

> [Page Visibility API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API).
## State

The `usePageVisibility` function exposes the following reactive state:

```js
import { usePageVisibility } from "vue-composable";

const { visibility, hidden } = usePageVisibility();
```

| State | Type | Description |
| ---------- | ---------------------- | --------------------------------- |
| visibility | `Ref(VisibilityState)` | Current document visibility state |
| hidden | `Ref(Boolean)` | `document.hidden` |

## Example

<ClientOnly>
<page-visibility-example/>
</ClientOnly>

### Code

```vue
<template>
<div>
<h4>
Hidden: <b>{{ hidden }}</b>
</h4>
<h4>
State: <b>{{ visibility }}</b>
</h4>
<p>You can change the state by switching tab - Check console</p>
<p>
<a
href="https://sqa.stackexchange.com/a/32355"
target="_blank"
rel="noopener noreferrer"
>Check this link</a
>
</p>
</div>
</template>
<script>
import { usePageVisibility, unwrap } from "vue-composable";
import { watch, reactive } from "@vue/composition-api";
export default {
setup() {
const { visibility, hidden } = usePageVisibility();
watch(visibility, () => {
console.log("visibility changed", {
visibility: visibility.value,
hidden: hidden.value
});
});
return { visibility, hidden };
}
};
</script>
```
1 change: 1 addition & 0 deletions packages/vue-composable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Check our [documentation](https://pikax.me/vue-composable/)
- [IntersectionObserver](https://pikax.me/vue-composable/composable/web/intersectionObserver) - reactive `IntersectionObserver`
- [NetworkInformation](https://pikax.me/vue-composable/composable/web/networkInformation) - reactive `NetworkInformation` wrapper
- [Online](<[composable/web](https://pikax.me/vue-composable/composable/web)/online>) - reactive `navigator.onLine` wrapper
- [PageVisibility](https://pikax.me/vue-composable/composable/web/pageVisibility) - reactive `Page Visibility API`

### External

Expand Down
3 changes: 2 additions & 1 deletion packages/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ Check our [documentation](https://pikax.me/vue-composable/)
- [IntersectionObserver](https://pikax.me/vue-composable/composable/web/intersectionObserver) - reactive `IntersectionObserver`
- [NetworkInformation](https://pikax.me/vue-composable/composable/web/networkInformation) - reactive `NetworkInformation` wrapper
- [Online](<[composable/web](https://pikax.me/vue-composable/composable/web)/online>) - reactive `navigator.onLine` wrapper

- [PageVisibility](https://pikax.me/vue-composable/composable/web/pageVisibility) - reactive `Page Visibility API`
-
## Contributing

1. Fork it!
Expand Down
52 changes: 52 additions & 0 deletions packages/web/__tests__/web/pageVisibility.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { usePageVisibility } from "../../src";

describe("pageVisibility", () => {
const documentEventSpy = jest.fn();
const documentEvent = document.addEventListener;

const raiseVisibilityChange = () => documentEventSpy.mock.calls[0][1]();

const visibilityGetter = jest.spyOn(document, 'visibilityState', 'get');
const hiddenGetter = jest.spyOn(document, 'hidden', 'get');

const updateVisibility = (v: VisibilityState, hidden: boolean) => {
visibilityGetter.mockImplementation(() => v);
hiddenGetter.mockImplementation(() => hidden);

raiseVisibilityChange();
}

beforeAll(() => {
document.addEventListener = documentEventSpy;
})
afterAll(() => {
document.addEventListener = documentEvent;
})

it('should only add event listener once', () => {
expect(documentEventSpy).not.toHaveBeenCalled();

usePageVisibility();
usePageVisibility();

expect(documentEventSpy).toHaveBeenCalled();
expect(documentEventSpy).toHaveBeenCalledTimes(1);

expect(documentEventSpy).toHaveBeenCalledWith('visibilitychange', expect.anything(), expect.objectContaining({ passive: true }))
})

it('should update visibilityState and hidden', () => {
const { visibility, hidden } = usePageVisibility();

expect(visibility.value).toBe(document.visibilityState);
expect(hidden.value).toBe(document.hidden);

updateVisibility('hidden', true);
expect(visibility.value).toBe('hidden');
expect(hidden.value).toBe(true);

updateVisibility('visible', false);
expect(visibility.value).toBe('visible');
expect(hidden.value).toBe(false);
})
})
1 change: 1 addition & 0 deletions packages/web/src/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./webSocket";
export * from "./intersectionObserver";
export * from "./networkInformation";
export * from "./online";
export * from "./pageVisibility";
26 changes: 26 additions & 0 deletions packages/web/src/web/pageVisibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ref, Ref } from "@vue/composition-api";

let visibility: Ref<VisibilityState> | undefined = undefined;
let hidden: Ref<boolean> | undefined = undefined;

export function usePageVisibility() {
if (!hidden) {
hidden = ref(document.hidden);
}
if (!visibility) {
visibility = ref(document.visibilityState);
document.addEventListener(
"visibilitychange",
() => {
visibility!.value = document.visibilityState
hidden!.value = document.hidden;
},
{ passive: true }
// true
);
}
return {
visibility,
hidden
};
}

0 comments on commit 3b86c6b

Please sign in to comment.