@code-coaching/vuetiful 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-coaching/vuetiful",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "onchange 'src/**/*.vue' 'src/**/*.ts' 'src/**/*.css' -- npm run build",
@@ -0,0 +1,44 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, test, vi, expect } from 'vitest'
3
+ import { vClickOutsideGroup } from '.';
4
+
5
+ interface HTMLElementWithClickOutsideHandler extends HTMLElement {
6
+ _clickOutsideHandler?: (event: MouseEvent) => void;
7
+ }
8
+
9
+ describe('vClickOutsideGroup Directive', () => {
10
+ test("should call the callback when clicking outside the element", async () => {
11
+ const callback = vi.fn();
12
+
13
+ const innerElement = document.createElement('div');
14
+ const outerElement = document.createElement('div');
15
+ outerElement.id = 'outer';
16
+ document.body.appendChild(outerElement);
17
+ document.body.appendChild(innerElement);
18
+
19
+ const directiveBinding = { value: {
20
+ elementsInGroup: ['#outer'],
21
+ callback
22
+ } } as any;
23
+ vClickOutsideGroup.mounted(innerElement, directiveBinding);
24
+
25
+ innerElement.click();
26
+ expect(callback).not.toHaveBeenCalled();
27
+ outerElement.click();
28
+ expect(callback).not.toHaveBeenCalled();
29
+ document.body.click();
30
+ expect(callback).toHaveBeenCalled();
31
+ })
32
+
33
+ test("should remove _clickOutsideHandler when unmounted", async () => {
34
+ const callback = vi.fn();
35
+ const directiveBinding = { value: callback } as any;
36
+ const innerElement = document.createElement('div') as HTMLElementWithClickOutsideHandler;
37
+ document.body.appendChild(innerElement);
38
+ vClickOutsideGroup.mounted(innerElement, directiveBinding);
39
+
40
+ expect(innerElement._clickOutsideHandler).toBeDefined();
41
+ vClickOutsideGroup.beforeUnmount(innerElement);
42
+ expect(innerElement._clickOutsideHandler).toBeUndefined();
43
+ })
44
+ });
@@ -0,0 +1,39 @@
1
+ import { DirectiveBinding } from 'vue';
2
+
3
+ interface HTMLElementWithClickOutsideHandler extends HTMLElement {
4
+ _clickOutsideHandler?: (event: MouseEvent) => void;
5
+ }
6
+
7
+ const clickOutsideGroup = {
8
+ mounted(el: HTMLElementWithClickOutsideHandler, binding: DirectiveBinding) {
9
+ const { elementsInGroup = [], callback } = binding.value;
10
+
11
+ const elementsToIgnore = elementsInGroup.map((selector: string) => {
12
+ const allElements = document.querySelectorAll(selector);
13
+ const elements = Array.from(allElements) as HTMLElement[];
14
+ return elements;
15
+ });
16
+
17
+ const allElementsToIgnore = elementsToIgnore.flat();
18
+
19
+ const clickOutsideHandler = (event: MouseEvent) => {
20
+ const clickedIgnoreElement = allElementsToIgnore.some((el: HTMLElement) => el?.contains(event.target as Node));
21
+ if (!el.contains(event.target as Node) && !clickedIgnoreElement) {
22
+ callback();
23
+ }
24
+ };
25
+
26
+ document.addEventListener('click', clickOutsideHandler);
27
+
28
+ el._clickOutsideHandler = clickOutsideHandler;
29
+ },
30
+
31
+ beforeUnmount(el: HTMLElementWithClickOutsideHandler) {
32
+ if (el._clickOutsideHandler) {
33
+ document.removeEventListener('click', el._clickOutsideHandler);
34
+ delete el._clickOutsideHandler;
35
+ }
36
+ },
37
+ };
38
+
39
+ export default clickOutsideGroup;
@@ -0,0 +1,38 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, test, vi, expect } from 'vitest'
3
+ import { vClickOutside } from '.';
4
+
5
+ interface HTMLElementWithClickOutsideHandler extends HTMLElement {
6
+ _clickOutsideHandler?: (event: MouseEvent) => void;
7
+ }
8
+
9
+ describe('vClickOutside Directive', () => {
10
+ test("should call the callback when clicking outside the element", async () => {
11
+ const callback = vi.fn();
12
+
13
+ const innerElement = document.createElement('div');
14
+ document.body.appendChild(innerElement);
15
+
16
+ const directiveBinding = { value: callback } as any;
17
+ vClickOutside.mounted(innerElement, directiveBinding);
18
+
19
+ innerElement.click();
20
+ expect(callback).not.toHaveBeenCalled();
21
+ document.body.click();
22
+ expect(callback).toHaveBeenCalled();
23
+ })
24
+
25
+ test("should remove _clickOutsideHandler when unmounted", async () => {
26
+ const callback = vi.fn();
27
+
28
+ const innerElement = document.createElement('div') as HTMLElementWithClickOutsideHandler;
29
+ document.body.appendChild(innerElement);
30
+
31
+ const directiveBinding = { value: callback } as any;
32
+ vClickOutside.mounted(innerElement, directiveBinding);
33
+
34
+ expect(innerElement._clickOutsideHandler).toBeDefined();
35
+ vClickOutside.beforeUnmount(innerElement);
36
+ expect(innerElement._clickOutsideHandler).toBeUndefined();
37
+ })
38
+ });
@@ -0,0 +1,28 @@
1
+ import { DirectiveBinding } from 'vue';
2
+
3
+ interface HTMLElementWithClickOutsideHandler extends HTMLElement {
4
+ _clickOutsideHandler?: (event: MouseEvent) => void;
5
+ }
6
+
7
+ const clickOutside = {
8
+ mounted(el: HTMLElementWithClickOutsideHandler, binding: DirectiveBinding) {
9
+ const clickOutsideHandler = (event: MouseEvent) => {
10
+ if (!el.contains(event.target as Node)) {
11
+ binding.value();
12
+ }
13
+ };
14
+
15
+ document.addEventListener('click', clickOutsideHandler);
16
+
17
+ el._clickOutsideHandler = clickOutsideHandler;
18
+ },
19
+
20
+ beforeUnmount(el: HTMLElementWithClickOutsideHandler) {
21
+ if (el._clickOutsideHandler) {
22
+ document.removeEventListener('click', el._clickOutsideHandler);
23
+ delete el._clickOutsideHandler;
24
+ }
25
+ },
26
+ };
27
+
28
+ export default clickOutside;
@@ -1,3 +1,5 @@
1
+ import vClickOutside from './click-outside';
2
+ import vClickOutsideGroup from './click-outside-group';
1
3
  import vClipboard from './clipboard';
2
4
 
3
- export { vClipboard };
5
+ export { vClickOutside, vClickOutsideGroup, vClipboard };
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { CssClasses, useTheme, VButton, VLightSwitch } from '@/index';
2
+ import { CssClasses, VButton, VLightSwitch, useTheme, vClickOutsideGroup } from '@/index';
3
3
  import { ref } from 'vue';
4
4
 
5
5
  defineProps({
@@ -48,6 +48,10 @@ const showPopup = ref(false);
48
48
 
49
49
  <div
50
50
  v-if="showPopup"
51
+ v-click-outside-group="{
52
+ elementsInGroup: ['.vuetiful-theme-switcher__button'],
53
+ callback: () => (showPopup = false),
54
+ }"
51
55
  class="vuetiful-theme-switcher__popup absolute z-10 mt-1 space-y-4 p-4 shadow-xl rounded-container-token"
52
56
  :class="`${background} ${text} ${widthPopup} ${classList}`"
53
57
  >