Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/.vuepress/components/OnOutsidePressExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<div>
<div ref="elref" style="background: red;width:100px">
Click Outside or inside
</div>
<p>check the console</p>
</div>
</template>

<script>
import { reactive, ref } from "@vue/composition-api";
import { useOnOutsidePress } from "vue-composable";

export default {
name: "on-mouse-move-example",
setup(_) {
const elref = ref(null);

useOnOutsidePress(elref, () => console.log("clicked outside"));

return { elref };
}
};
</script>
3 changes: 2 additions & 1 deletion docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ module.exports = {
["composable/event/event", "event"],
["composable/event/onMouseMove", "onMouseMove"],
["composable/event/onResize", "onResize"],
["composable/event/onScroll", "onScroll"]
["composable/event/onScroll", "onScroll"],
["composable/event/onOutsidePress", "onOutsidePress"]
]
},
{
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Check out the [examples folder](examples) or start hacking on [codesandbox](http
- [Mouse Move](composable/event/onMouseMove) - Attach `mousemove` listener to a DOM element
- [Resize](composable/event/onResize) - Attach `resize` listener to a DOM element
- [Scroll](composable/event/onScroll) - Attach `scroll` listener to a DOM element
- [onOutsidePress](composable/event/onOutsidePress) - Execute callback when click is outside of element

### Date

Expand Down
38 changes: 38 additions & 0 deletions docs/api/vue-composable.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,14 @@ export function useDebounce<T extends Procedure>(
options?: Options
): T;

// @public (undocumented)
export function useEvent<K extends keyof DocumentEventMap>(
el: RefTyped<Document>,
name: K,
listener: (this: Document, ev: DocumentEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): RemoveEventFunction;

// @public (undocumented)
export function useEvent<
T extends {
Expand Down Expand Up @@ -1608,6 +1616,36 @@ export function useOnMouseMove(
wait?: number
): MouseMoveResult;

// @public (undocumented)
export function useOnOutsidePress(
el: RefTyped<Window>,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

// @public (undocumented)
export function useOnOutsidePress(
el: RefElement,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

// @public (undocumented)
export function useOnOutsidePress<T extends Element>(
el: Ref<T> | Ref<T | null>,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

// @public (undocumented)
export function useOnOutsidePress<T extends Element>(
el: Ref<T | null>,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

// @public (undocumented)
export function useOnOutsidePress(
el: RefElement,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

// @public (undocumented)
export function useOnResize(el: RefTyped<Window>, wait: number): ResizeResult;

Expand Down
63 changes: 63 additions & 0 deletions docs/composable/event/onOutsidePress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# useOnOutsidePress

> Execute callback when click is outside of element

## Parameters

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

useOnOutsidePress(element, callback);
```

| Parameters | Type | Required | Default | Description |
| ---------- | ------------------------- | -------- | ------- | ---------------------------------------- |
| element | `Ref<Element>` | `true` | | Element to keep track if clicked outside |
| callback | `(e: MouseEvent) => void` | `true` | | Callback when clicked outside |

## Methods

The `useOnOutsidePress` function exposes the following methods:

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

const remove = useOnOutsidePress();
```

| Signature | Description |
| --------- | ----------------------------------- |
| `remove` | Manually removes the event listener |

## Example

<on-outside-press-example/>

### Code

```vue
<template>
<div>
<div ref="elref" style="background: red;width:100px">
Click Outside or inside
</div>
<p>check the console</p>
</div>
</template>

<script>
import { reactive, ref } from "@vue/composition-api";
import { useOnOutsidePress } from "vue-composable";

export default {
name: "on-mouse-move-example",
setup(_) {
const elref = ref(null);

useOnOutsidePress(elref, () => console.log("clicked outside"));

return { elref };
}
};
</script>
```
1 change: 1 addition & 0 deletions packages/vue-composable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Check our [documentation](https://pikax.me/vue-composable/)
- [Mouse Move](https://pikax.me/vue-composable/composable/event/onMouseMove) - Attach `mousemove` listener to a DOM element
- [Resize](https://pikax.me/vue-composable/composable/event/onResize) - Attach `resize` listener to a DOM element
- [Scroll](https://pikax.me/vue-composable/composable/event/onScroll) - Attach `scroll` listener to a DOM element
- [onOutsidePress](https://pikax.me/vue-composable/composable/event/onOutsidePress) - Execute callback when click is outside of element

### Date

Expand Down
101 changes: 101 additions & 0 deletions packages/vue-composable/__tests__/event/onOutsidePress.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { createVue } from "../utils";
import { useOnOutsidePress } from "../../src";

describe("onOutsidePress", () => {
const addEventListenerMock = jest.fn();
let addEventListener: any;
beforeAll(() => {
addEventListener = document.addEventListener;
document.addEventListener = addEventListenerMock;
});

beforeEach(() => {
addEventListenerMock.mockClear();
});

afterAll(() => {
document.addEventListener = addEventListener;
});

test("should work mousedown", () => {
const element = document.createElement("div");
let handler: (a: any) => void = {} as any;

addEventListenerMock.mockImplementation((_, h) => {
handler = h;
});

let callback = jest.fn();
const { mount } = createVue({
template: "<div></div>",
setup() {
useOnOutsidePress(element, callback);
}
});
mount();

expect(callback).not.toHaveBeenCalled();

expect(addEventListenerMock).toHaveBeenLastCalledWith(
"mousedown",
expect.any(Function),
{ passive: true }
);

// inside
handler({
target: element
});
expect(callback).not.toHaveBeenCalled();

// outside
handler({
target: document.createElement("div")
});
expect(callback).toHaveBeenCalledTimes(1);
});

// test("should work touchstart", () => {
// const element = document.createElement("div");
// let handler: (a: any) => void = {} as any;

// addEventListenerMock.mockImplementation((_, h) => {
// handler = h;
// });

// // remove mousedown
// const onmousedown = document.documentElement.onmousedown;
// document.documentElement.onmousedown

// let callback = jest.fn();
// const { mount } = createVue({
// template: "<div></div>",
// setup() {
// useOnOutsidePress(element, callback);
// },
// });
// mount();

// expect(callback).not.toHaveBeenCalled();

// expect(addEventListenerMock).toHaveBeenLastCalledWith(
// "touchstart",
// expect.any(Function),
// { passive: true }
// );

// // inside
// handler({
// target: element,
// });
// expect(callback).not.toHaveBeenCalled();

// // outside
// handler({
// target: document.createElement("div"),
// });
// expect(callback).toHaveBeenCalledTimes(1);

// document.documentElement.onmousedown = onmousedown;
// });
});
9 changes: 9 additions & 0 deletions packages/vue-composable/src/event/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { RefTyped, NO_OP, wrap } from "../utils";

export type RemoveEventFunction = () => void;

export function useEvent<K extends keyof DocumentEventMap>(
el: RefTyped<Document>,
name: K,
listener: (this: Document, ev: DocumentEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): RemoveEventFunction;

export function useEvent<
T extends {
addEventListener: (
Expand Down Expand Up @@ -41,12 +48,14 @@ export function useEvent<K extends keyof WindowEventMap>(
listener: (this: Document, ev: WindowEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): RemoveEventFunction;

export function useEvent<K extends keyof DocumentEventMap>(
el: Element | Ref<Element | undefined>,
name: K,
listener: (this: Document, ev: DocumentEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): RemoveEventFunction;

export function useEvent(
el: Element | Ref<Element | undefined> | RefTyped<Window> | RefTyped<any>,
name: string,
Expand Down
1 change: 1 addition & 0 deletions packages/vue-composable/src/event/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./event";
export * from "./onMouseMove";
export * from "./onResize";
export * from "./onScroll";
export * from "./onOutsidePress";
46 changes: 46 additions & 0 deletions packages/vue-composable/src/event/onOutsidePress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Ref } from "../api";
import { RemoveEventFunction, useEvent } from "./event";
import { RefTyped, RefElement, wrap, isClient } from "../utils";

const events: Array<keyof DocumentEventMap> = ["mousedown", "touchstart"];

export function useOnOutsidePress(
el: RefTyped<Window>,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

export function useOnOutsidePress(
el: RefElement,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

export function useOnOutsidePress<T extends Element>(
el: Ref<T> | Ref<T | null>,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

export function useOnOutsidePress<T extends Element>(
el: Ref<T | null>,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;

export function useOnOutsidePress(
el: RefElement,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction;
export function useOnOutsidePress(
el: any,
onOutsidePressCallback: (ev: MouseEvent) => void
): RemoveEventFunction {
if (!isClient) {
return () => {};
}
const element: Ref<Element | null> = wrap(el);
const handler = (e: MouseEvent) =>
element.value &&
!element.value.contains(e.target as Node) &&
onOutsidePressCallback(e);

const event = events.find(x => `on${x}` in document.documentElement)!;
return useEvent(document, event, handler, { passive: true });
}
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Check our [documentation](https://pikax.me/vue-composable/)
- [Mouse Move](https://pikax.me/vue-composable/composable/event/onMouseMove) - Attach `mousemove` listener to a DOM element
- [Resize](https://pikax.me/vue-composable/composable/event/onResize) - Attach `resize` listener to a DOM element
- [Scroll](https://pikax.me/vue-composable/composable/event/onScroll) - Attach `scroll` listener to a DOM element
- [onOutsidePress](https://pikax.me/vue-composable/composable/event/onOutsidePress) - Execute callback when click is outside of element

### Date

Expand Down