@vue-interface/tooltip 1.0.0-beta.2 → 1.0.0-beta.4

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.
@@ -1,29 +1,42 @@
1
- import type { App, VNode } from 'vue';
1
+ import type { App } from 'vue';
2
2
  import { h, render } from 'vue';
3
3
  import Tooltip from './Tooltip.vue';
4
4
 
5
- export default function(app: App, options = {
6
- delay: undefined,
7
- prefix: 'data-tooltip',
5
+ type TooltipPluginOptions = {
6
+ delay?: number,
7
+ prefix: string,
8
8
  triggers: {
9
- open: ['mouseover:750', 'focus'],
10
- close: ['mouseout:1000', 'blur'],
9
+ open: string[],
10
+ close: string[],
11
11
  }
12
- }) {
12
+ }
13
+
14
+ export default function (app: App, opts: Partial<TooltipPluginOptions> = {}) {
15
+ const tooltips: Map<string,Function> = new Map;
16
+
17
+ const options: TooltipPluginOptions = Object.assign({
18
+ delay: undefined,
19
+ prefix: 'data-tooltip',
20
+ triggers: {
21
+ open: ['mouseover:350'],
22
+ close: ['mouseout:100'],
23
+ }
24
+ }, opts);
25
+
13
26
  const prefix = options.prefix.replace(/[-]+$/, '');
14
27
  const prefixRegExp = new RegExp(`^${prefix}\-`);
15
28
 
16
29
  function getAttributes(el: Element): Record<string,any> {
17
30
  return Array.from(el.attributes)
18
- .map(a => [a.name, a.value])
19
- .filter(([key]) => key === 'title' || key.match(prefixRegExp))
20
- .map(([key, value]) => [key.replace(new RegExp(prefixRegExp), ''), value])
21
- .reduce((carry, attr) => Object.assign(carry, {[attr[0]]: attr[1]}), {})
31
+ .map(a => [a.name, a.value])
32
+ .filter(([key]) => key === 'title' || key.match(prefixRegExp))
33
+ .map(([key, value]) => [key.replace(new RegExp(prefixRegExp), ''), value])
34
+ .reduce((carry, attr) => Object.assign(carry, { [attr[0]]: attr[1] }), {});
22
35
  }
23
36
 
24
- function createTooltip(target: Element, props: Record<string,any> = {}): Function {
37
+ function createTooltip(target: Element, props: Record<string,any> = {}, hash: string): Function {
25
38
  const container = document.createElement('template');
26
-
39
+
27
40
  const vnode = h(Tooltip, Object.assign({
28
41
  target,
29
42
  show: true
@@ -36,6 +49,8 @@ export default function(app: App, options = {
36
49
  document.body.append(el);
37
50
 
38
51
  return () => {
52
+ tooltips.delete(hash);
53
+
39
54
  // @ts-ignore
40
55
  vnode.component?.ctx.close();
41
56
 
@@ -71,7 +86,13 @@ export default function(app: App, options = {
71
86
 
72
87
  if(!tooltip) {
73
88
  timer = setTimeout(() => {
74
- tooltip = createTooltip(target, properties);
89
+ // Do a check before creating the tooltip to ensure the dom
90
+ // element still exists. Its possible for the element to
91
+ // be removed after the timeout delay runs.
92
+ if(document.contains(target)) {
93
+ tooltip = createTooltip(target, properties, hash);
94
+ tooltips.set(hash, tooltip);
95
+ }
75
96
  }, delay);
76
97
  }
77
98
  }
@@ -90,11 +111,11 @@ export default function(app: App, options = {
90
111
  function addEventListener(trigger: string, fn: Function) {
91
112
  const [ event, delayString ] = trigger.split(':');
92
113
 
93
- target.addEventListener(event, () => fn(Number(delayString || 0)))
114
+ target.addEventListener(event, () => fn(Number(delayString || 0)));
94
115
  }
95
-
96
- options.triggers.open.map(trigger => addEventListener(trigger, open));
97
- options.triggers.close.map(trigger => addEventListener(trigger, close));
116
+
117
+ (target.getAttribute(`${prefix}-trigger-open`)?.split(',') || options.triggers.open).map(trigger => addEventListener(trigger, open));
118
+ (target.getAttribute(`${prefix}-trigger-close`)?.split(',') || options.triggers.close).map(trigger => addEventListener(trigger, close));
98
119
  }
99
120
 
100
121
  app.mixin({
@@ -118,20 +139,46 @@ export default function(app: App, options = {
118
139
  return NodeFilter.FILTER_REJECT;
119
140
  }
120
141
 
121
- return NodeFilter.FILTER_ACCEPT
142
+ return NodeFilter.FILTER_ACCEPT;
122
143
  }
123
144
  );
124
145
 
125
146
  // Step through and alert all child nodes
126
- while (walker.nextNode()) {
147
+ while(walker.nextNode()) {
127
148
  if(walker.currentNode instanceof Element) {
128
149
  init(<Element> walker.currentNode);
129
150
  }
130
151
  }
152
+
153
+ const observer = new MutationObserver((changes) => {
154
+ for(const { removedNodes } of changes) {
155
+ for(const node of removedNodes) {
156
+ for(const el of (node as Element).querySelectorAll(`[${prefix}-id]`)) {
157
+ const tooltip = tooltips.get(
158
+ el.getAttribute(`${prefix}-id`) as string
159
+ );
160
+
161
+ tooltip && tooltip();
162
+ }
163
+ }
164
+ }
165
+ });
166
+
167
+ observer.observe(el, { childList: true });
131
168
  }
132
169
  });
133
170
 
134
- app.directive('tooltip', (target, binding) => init(
135
- target, Object.assign({}, binding.modifiers, binding.value)
136
- ));
171
+ app.directive('tooltip', {
172
+ created(target, binding) {
173
+ init(target, Object.assign({}, binding.modifiers, binding.value));
174
+ },
175
+ beforeUnmount(target) {
176
+ const id = target.getAttribute(`${prefix}-id`);
177
+ const tooltip = tooltips.get(id);
178
+
179
+ console.log('beforeUnmount');
180
+
181
+ tooltip && tooltip();
182
+ }
183
+ });
137
184
  }
@@ -8,11 +8,11 @@ module.exports = plugin(function({ addComponents, theme }) {
8
8
  },
9
9
 
10
10
  '.bs-tooltip-top .tooltip-arrow': {
11
- bottom: 0,
11
+ bottom: '1px',
12
12
  },
13
13
 
14
14
  '.bs-tooltip-top .tooltip-arrow::before': {
15
- bottom: 0,
15
+ bottom: '1px',
16
16
  borderWidth: `${theme('tooltip.arrow.height')} calc(${theme('tooltip.arrow.width')} / 2) 0`,
17
17
  borderTopColor: theme('tooltip.arrow.color'),
18
18
  }
@@ -24,11 +24,11 @@ module.exports = plugin(function({ addComponents, theme }) {
24
24
  },
25
25
 
26
26
  '.bs-tooltip-bottom .tooltip-arrow': {
27
- top: 0
27
+ top: '1px'
28
28
  },
29
29
 
30
30
  '.bs-tooltip-bottom .tooltip-arrow::before': {
31
- top: 0,
31
+ top: '1px',
32
32
  borderWidth: `0 calc(${theme('tooltip.arrow.width')} / 2) ${theme('tooltip.arrow.height')}`,
33
33
  borderBottomColor: theme('tooltip.arrow.color'),
34
34
  },
@@ -40,13 +40,13 @@ module.exports = plugin(function({ addComponents, theme }) {
40
40
  },
41
41
 
42
42
  '.bs-tooltip-left .tooltip-arrow': {
43
- right: 0,
43
+ right: '1px',
44
44
  width: theme('tooltip.arrow.height'),
45
45
  height: theme('tooltip.arrow.width')
46
46
  },
47
47
 
48
48
  '.bs-tooltip-left .tooltip-arrow::before': {
49
- right: 0,
49
+ right: '1px',
50
50
  borderWidth: `calc(${theme('tooltip.arrow.width')} / 2) 0 calc(${theme('tooltip.arrow.width')} / 2) ${theme('tooltip.arrow.height')}`,
51
51
  borderLeftColor: theme('tooltip.arrow.color')
52
52
  }
@@ -58,13 +58,13 @@ module.exports = plugin(function({ addComponents, theme }) {
58
58
  },
59
59
 
60
60
  '.bs-tooltip-right .tooltip-arrow': {
61
- left: 0,
61
+ left: '1px',
62
62
  width: theme('tooltip.arrow.height'),
63
63
  height: theme('tooltip.arrow.width'),
64
64
  },
65
65
 
66
66
  '.bs-tooltip-right .tooltip-arrow::before': {
67
- left: 0,
67
+ left: '1px',
68
68
  borderWidth: `calc(${theme('tooltip.arrow.width')} / 2) ${theme('tooltip.arrow.height')} calc(${theme('tooltip.arrow.width')} / 2) 0`,
69
69
  borderRightColor: theme('tooltip.arrow.color'),
70
70
  }
@@ -1,4 +0,0 @@
1
- declare const _sfc_main: {
2
- mixins: any[];
3
- };
4
- export default _sfc_main;
@@ -1,9 +0,0 @@
1
- import type { App } from 'vue';
2
- export default function (app: App, options?: {
3
- delay: undefined;
4
- prefix: string;
5
- triggers: {
6
- open: string[];
7
- close: string[];
8
- };
9
- }): void;