@exmg/exm-tooltip 1.1.9 → 1.1.10-alpha.26
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/.rollup.cache/root/repo/packages/exm-tooltip/dist/exm-tooltip-base.d.ts +56 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/exm-tooltip-base.js +268 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/exm-tooltip.d.ts +33 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/exm-tooltip.js +36 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/index.d.ts +3 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/index.js +4 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/styles/exm-tooltip-styles-css.d.ts +1 -0
- package/.rollup.cache/root/repo/packages/exm-tooltip/dist/styles/exm-tooltip-styles-css.js +35 -0
- package/dist/exm-tooltip-base.d.ts +21 -13
- package/dist/exm-tooltip-base.js +108 -53
- package/dist/exm-tooltip.js +4 -2
- package/dist/index.js +1 -1
- package/dist/styles/exm-tooltip-styles-css.js +7 -2
- package/package.json +6 -8
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ExmgElement } from '@exmg/lit-base/index.js';
|
|
2
|
+
type TooltipPositions = 'top' | 'right' | 'bottom' | 'left' | 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left';
|
|
3
|
+
export declare class ExmTooltipBase extends ExmgElement {
|
|
4
|
+
/**
|
|
5
|
+
* The id of the element that the tooltip is anchored to. This element
|
|
6
|
+
* must be a sibling of the tooltip.
|
|
7
|
+
*/
|
|
8
|
+
for?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Positions the tooltip to the top, right, bottom, left of its content.
|
|
11
|
+
*/
|
|
12
|
+
position: TooltipPositions;
|
|
13
|
+
/**
|
|
14
|
+
* If true, no parts of the tooltip will ever be shown offscreen.
|
|
15
|
+
*/
|
|
16
|
+
fitToVisibleBounds: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* X axis offset from the parent's center
|
|
19
|
+
*/
|
|
20
|
+
xOffset: number;
|
|
21
|
+
/**
|
|
22
|
+
* Y axis offset from the parent's center
|
|
23
|
+
*/
|
|
24
|
+
yOffset: number;
|
|
25
|
+
private showing;
|
|
26
|
+
tooltip?: HTMLElement;
|
|
27
|
+
private _target?;
|
|
28
|
+
private _parent?;
|
|
29
|
+
private boundShow;
|
|
30
|
+
private boundHide;
|
|
31
|
+
private boundMouseMove;
|
|
32
|
+
private boundMouseLeave;
|
|
33
|
+
/**
|
|
34
|
+
* Returns the target element that this tooltip is anchored to. It is
|
|
35
|
+
* either the element given by the `for` attribute, or the immediate parent
|
|
36
|
+
* of the tooltip.
|
|
37
|
+
*/
|
|
38
|
+
get target(): any;
|
|
39
|
+
connectedCallback(): void;
|
|
40
|
+
disconnectedCallback(): void;
|
|
41
|
+
protected firstUpdated(): void;
|
|
42
|
+
private handleMousemove;
|
|
43
|
+
private handleMouseleave;
|
|
44
|
+
private show;
|
|
45
|
+
/**
|
|
46
|
+
* Toggles a CSS class on or off.
|
|
47
|
+
*/
|
|
48
|
+
private toggleClass;
|
|
49
|
+
private hide;
|
|
50
|
+
private updatePosition;
|
|
51
|
+
private addListeners;
|
|
52
|
+
private findTarget;
|
|
53
|
+
private removeListeners;
|
|
54
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import { property } from 'lit/decorators/property.js';
|
|
4
|
+
import { state } from 'lit/decorators.js';
|
|
5
|
+
import { query } from 'lit/decorators/query.js';
|
|
6
|
+
import { ExmgElement, observer } from '@exmg/lit-base/index.js';
|
|
7
|
+
export class ExmTooltipBase extends ExmgElement {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
/**
|
|
11
|
+
* Positions the tooltip to the top, right, bottom, left of its content.
|
|
12
|
+
*/
|
|
13
|
+
this.position = 'bottom';
|
|
14
|
+
/**
|
|
15
|
+
* If true, no parts of the tooltip will ever be shown offscreen.
|
|
16
|
+
*/
|
|
17
|
+
this.fitToVisibleBounds = false;
|
|
18
|
+
/**
|
|
19
|
+
* X axis offset from the parent's center
|
|
20
|
+
*/
|
|
21
|
+
this.xOffset = 0;
|
|
22
|
+
/**
|
|
23
|
+
* Y axis offset from the parent's center
|
|
24
|
+
*/
|
|
25
|
+
this.yOffset = 0;
|
|
26
|
+
this.showing = false;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Returns the target element that this tooltip is anchored to. It is
|
|
30
|
+
* either the element given by the `for` attribute, or the immediate parent
|
|
31
|
+
* of the tooltip.
|
|
32
|
+
*/
|
|
33
|
+
get target() {
|
|
34
|
+
const parentNode = this.parentNode;
|
|
35
|
+
// If the parentNode is a document fragment, then we need to use the host.
|
|
36
|
+
const ownerRoot = parentNode.getRootNode();
|
|
37
|
+
if (this.for) {
|
|
38
|
+
return ownerRoot.querySelector('#' + this.for);
|
|
39
|
+
}
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
return parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? ownerRoot.host : parentNode;
|
|
42
|
+
}
|
|
43
|
+
connectedCallback() {
|
|
44
|
+
super.connectedCallback();
|
|
45
|
+
this.boundShow = this.show.bind(this);
|
|
46
|
+
this.boundHide = this.hide.bind(this);
|
|
47
|
+
this.boundMouseMove = this.handleMousemove.bind(this);
|
|
48
|
+
this.boundMouseLeave = this.handleMouseleave.bind(this);
|
|
49
|
+
this.setAttribute('role', 'tooltip');
|
|
50
|
+
this.setAttribute('tabindex', '-1');
|
|
51
|
+
this.findTarget();
|
|
52
|
+
}
|
|
53
|
+
disconnectedCallback() {
|
|
54
|
+
this.removeListeners();
|
|
55
|
+
super.disconnectedCallback();
|
|
56
|
+
}
|
|
57
|
+
firstUpdated() {
|
|
58
|
+
this.findTarget();
|
|
59
|
+
this.updatePosition();
|
|
60
|
+
}
|
|
61
|
+
handleMousemove(event) {
|
|
62
|
+
if (!this._target || !this._parent) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const mousePosition = {
|
|
66
|
+
x: event.clientX,
|
|
67
|
+
y: event.clientY,
|
|
68
|
+
};
|
|
69
|
+
const targetRect = this._target.getBoundingClientRect();
|
|
70
|
+
if (mousePosition.x < targetRect.left - 1 || mousePosition.x > targetRect.right + 1) {
|
|
71
|
+
this._parent.removeEventListener('mousemove', this.boundMouseMove);
|
|
72
|
+
this.hide();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (mousePosition.y < targetRect.top - 1 || mousePosition.y > targetRect.bottom + 1) {
|
|
76
|
+
this._parent.removeEventListener('mousemove', this.boundMouseMove);
|
|
77
|
+
this.hide();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
handleMouseleave() {
|
|
82
|
+
if (!this._target || !this._parent) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.hide();
|
|
86
|
+
this._parent.removeEventListener('mouseout', this.boundMouseLeave);
|
|
87
|
+
this._parent.removeEventListener('mousemove', this.boundMouseMove);
|
|
88
|
+
}
|
|
89
|
+
show(event) {
|
|
90
|
+
event.stopPropagation();
|
|
91
|
+
// If the tooltip is already showing, there's nothing to do.
|
|
92
|
+
if (this.showing || !this._parent) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
this._parent.addEventListener('mousemove', this.boundMouseMove);
|
|
96
|
+
this._parent.addEventListener('mouseout', this.boundMouseLeave);
|
|
97
|
+
if (this.textContent.trim() === '') {
|
|
98
|
+
// Check if effective children are also empty
|
|
99
|
+
let allChildrenEmpty = true;
|
|
100
|
+
const effectiveChildren = this.childNodes;
|
|
101
|
+
for (const child of effectiveChildren) {
|
|
102
|
+
if (child.textContent.trim() !== '') {
|
|
103
|
+
allChildrenEmpty = false;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (allChildrenEmpty) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
this.showing = true;
|
|
112
|
+
this.toggleClass('hidden', false, this.tooltip);
|
|
113
|
+
this.updatePosition();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Toggles a CSS class on or off.
|
|
117
|
+
*/
|
|
118
|
+
toggleClass(name, bool, node) {
|
|
119
|
+
node = /** @type {Element} */ node || this;
|
|
120
|
+
if (arguments.length == 1) {
|
|
121
|
+
bool = !node.classList.contains(name);
|
|
122
|
+
}
|
|
123
|
+
if (bool) {
|
|
124
|
+
node.classList.add(name);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
node.classList.remove(name);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
hide() {
|
|
131
|
+
// If the tooltip is already hidden, there's nothing to do.
|
|
132
|
+
if (!this.showing) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.showing = false;
|
|
136
|
+
this.toggleClass('hidden', true, this.tooltip);
|
|
137
|
+
}
|
|
138
|
+
updatePosition() {
|
|
139
|
+
if (!this._target || !this.offsetParent || !this.tooltip) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const parentRect = this.offsetParent.getBoundingClientRect();
|
|
143
|
+
const targetRect = this._target.getBoundingClientRect();
|
|
144
|
+
const thisRect = this.tooltip.getBoundingClientRect();
|
|
145
|
+
const horizontalCenterOffset = (targetRect.width - thisRect.width) / 2;
|
|
146
|
+
const verticalCenterOffset = (targetRect.height - thisRect.height) / 2;
|
|
147
|
+
const targetLeft = targetRect.left - parentRect.left;
|
|
148
|
+
const targetTop = targetRect.top - parentRect.top;
|
|
149
|
+
let tooltipLeft = 0;
|
|
150
|
+
let tooltipTop = 0;
|
|
151
|
+
switch (this.position) {
|
|
152
|
+
case 'top':
|
|
153
|
+
tooltipLeft = targetLeft + horizontalCenterOffset;
|
|
154
|
+
tooltipTop = targetTop - thisRect.height;
|
|
155
|
+
break;
|
|
156
|
+
case 'bottom':
|
|
157
|
+
tooltipLeft = targetLeft + horizontalCenterOffset;
|
|
158
|
+
tooltipTop = targetTop + targetRect.height;
|
|
159
|
+
break;
|
|
160
|
+
case 'left':
|
|
161
|
+
tooltipLeft = targetLeft - thisRect.width;
|
|
162
|
+
tooltipTop = targetTop + verticalCenterOffset;
|
|
163
|
+
break;
|
|
164
|
+
case 'right':
|
|
165
|
+
tooltipLeft = targetLeft + targetRect.width;
|
|
166
|
+
tooltipTop = targetTop + verticalCenterOffset;
|
|
167
|
+
break;
|
|
168
|
+
case 'top-left':
|
|
169
|
+
tooltipLeft = targetLeft;
|
|
170
|
+
tooltipTop = targetTop - thisRect.height;
|
|
171
|
+
break;
|
|
172
|
+
case 'bottom-left':
|
|
173
|
+
tooltipLeft = targetLeft;
|
|
174
|
+
tooltipTop = targetTop + targetRect.height;
|
|
175
|
+
break;
|
|
176
|
+
case 'top-right':
|
|
177
|
+
tooltipLeft = targetLeft - thisRect.width + targetRect.width;
|
|
178
|
+
tooltipTop = targetTop - thisRect.height;
|
|
179
|
+
break;
|
|
180
|
+
case 'bottom-right':
|
|
181
|
+
tooltipLeft = targetLeft - thisRect.width + targetRect.width;
|
|
182
|
+
tooltipTop = targetTop + targetRect.height;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
tooltipLeft += this.xOffset;
|
|
186
|
+
tooltipTop += this.yOffset;
|
|
187
|
+
if (this.fitToVisibleBounds) {
|
|
188
|
+
// Clip the left/right side
|
|
189
|
+
if (parentRect.left + tooltipLeft + thisRect.width > window.innerWidth) {
|
|
190
|
+
this.style.right = '0px';
|
|
191
|
+
this.style.left = 'auto';
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
this.style.left = Math.max(0, tooltipLeft) + 'px';
|
|
195
|
+
this.style.right = 'auto';
|
|
196
|
+
}
|
|
197
|
+
// Clip the top/bottom side.
|
|
198
|
+
if (parentRect.top + tooltipTop + thisRect.height > window.innerHeight) {
|
|
199
|
+
this.style.bottom = parentRect.height + 'px';
|
|
200
|
+
this.style.top = 'auto';
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
this.style.top = Math.max(-parentRect.top, tooltipTop) + 'px';
|
|
204
|
+
this.style.bottom = 'auto';
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this.style.left = tooltipLeft + 'px';
|
|
209
|
+
this.style.top = tooltipTop + 'px';
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
addListeners() {
|
|
213
|
+
if (this._target) {
|
|
214
|
+
this._target.addEventListener('mouseenter', this.boundShow);
|
|
215
|
+
this._target.addEventListener('focus', this.boundShow);
|
|
216
|
+
this._target.addEventListener('blur', this.boundHide);
|
|
217
|
+
this._target.addEventListener('tap', this.boundHide);
|
|
218
|
+
}
|
|
219
|
+
this.addEventListener('mouseenter', this.boundShow);
|
|
220
|
+
}
|
|
221
|
+
findTarget() {
|
|
222
|
+
this.removeListeners();
|
|
223
|
+
this._target = this.target;
|
|
224
|
+
this._parent = this.parentNode;
|
|
225
|
+
this.addListeners();
|
|
226
|
+
}
|
|
227
|
+
removeListeners() {
|
|
228
|
+
if (this._target) {
|
|
229
|
+
this._target.removeEventListener('mouseenter', this.boundShow);
|
|
230
|
+
this._target.removeEventListener('focus', this.boundShow);
|
|
231
|
+
this._target.removeEventListener('blur', this.boundHide);
|
|
232
|
+
this._target.removeEventListener('tap', this.boundHide);
|
|
233
|
+
}
|
|
234
|
+
this.removeEventListener('mouseenter', this.boundShow);
|
|
235
|
+
}
|
|
236
|
+
render() {
|
|
237
|
+
return html `
|
|
238
|
+
<section id="tooltip" class="hidden">
|
|
239
|
+
<slot></slot>
|
|
240
|
+
</section>
|
|
241
|
+
`;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
__decorate([
|
|
245
|
+
property({ type: String }),
|
|
246
|
+
observer(function () {
|
|
247
|
+
this.findTarget();
|
|
248
|
+
})
|
|
249
|
+
], ExmTooltipBase.prototype, "for", void 0);
|
|
250
|
+
__decorate([
|
|
251
|
+
property()
|
|
252
|
+
], ExmTooltipBase.prototype, "position", void 0);
|
|
253
|
+
__decorate([
|
|
254
|
+
property({ type: Boolean })
|
|
255
|
+
], ExmTooltipBase.prototype, "fitToVisibleBounds", void 0);
|
|
256
|
+
__decorate([
|
|
257
|
+
property({ type: Number })
|
|
258
|
+
], ExmTooltipBase.prototype, "xOffset", void 0);
|
|
259
|
+
__decorate([
|
|
260
|
+
property({ type: Number })
|
|
261
|
+
], ExmTooltipBase.prototype, "yOffset", void 0);
|
|
262
|
+
__decorate([
|
|
263
|
+
state()
|
|
264
|
+
], ExmTooltipBase.prototype, "showing", void 0);
|
|
265
|
+
__decorate([
|
|
266
|
+
query('#tooltip')
|
|
267
|
+
], ExmTooltipBase.prototype, "tooltip", void 0);
|
|
268
|
+
//# sourceMappingURL=exm-tooltip-base.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ExmTooltipBase } from './exm-tooltip-base.js';
|
|
2
|
+
/**
|
|
3
|
+
* `exm-tooltip`
|
|
4
|
+
* Example:
|
|
5
|
+
* ```html
|
|
6
|
+
* <div style="position:relative;">
|
|
7
|
+
* <button id="styledBtn">Test</button>
|
|
8
|
+
* <exm-tooltip for="styledBtn">the name means "different lizard"</exm-tooltip>
|
|
9
|
+
* </div>
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* ### Styling
|
|
13
|
+
* The following custom properties and mixins are available for styling:
|
|
14
|
+
*
|
|
15
|
+
* Custom property | Description | Default
|
|
16
|
+
* ----------------|-------------|----------
|
|
17
|
+
* `--exm-tooltip-font-size` | Font size of tooltip text | 10px
|
|
18
|
+
* `--exm-tooltip-line-height` | Text line height | 1
|
|
19
|
+
* `--exm-tooltip-background` | Background color | #616161
|
|
20
|
+
* `--exm-tooltip-opacity` | Tooltip opacity | 0.9
|
|
21
|
+
* `--exm-tooltip-text-color` | Font color | white
|
|
22
|
+
* `--exm-tooltip-padding` | Container padding | 8px
|
|
23
|
+
* `--exm-tooltip-border-radius` | Container border radius | 2px
|
|
24
|
+
* `--exm-tooltip-min-width` | Breadcrumb container background color | initial
|
|
25
|
+
*/
|
|
26
|
+
export declare class ExmTooltip extends ExmTooltipBase {
|
|
27
|
+
static styles: import("lit").CSSResult;
|
|
28
|
+
}
|
|
29
|
+
declare global {
|
|
30
|
+
interface HTMLElementTagNameMap {
|
|
31
|
+
'exm-tooltip': ExmTooltip;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement } from 'lit/decorators/custom-element.js';
|
|
3
|
+
import { style } from './styles/exm-tooltip-styles-css.js';
|
|
4
|
+
import { ExmTooltipBase } from './exm-tooltip-base.js';
|
|
5
|
+
/**
|
|
6
|
+
* `exm-tooltip`
|
|
7
|
+
* Example:
|
|
8
|
+
* ```html
|
|
9
|
+
* <div style="position:relative;">
|
|
10
|
+
* <button id="styledBtn">Test</button>
|
|
11
|
+
* <exm-tooltip for="styledBtn">the name means "different lizard"</exm-tooltip>
|
|
12
|
+
* </div>
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* ### Styling
|
|
16
|
+
* The following custom properties and mixins are available for styling:
|
|
17
|
+
*
|
|
18
|
+
* Custom property | Description | Default
|
|
19
|
+
* ----------------|-------------|----------
|
|
20
|
+
* `--exm-tooltip-font-size` | Font size of tooltip text | 10px
|
|
21
|
+
* `--exm-tooltip-line-height` | Text line height | 1
|
|
22
|
+
* `--exm-tooltip-background` | Background color | #616161
|
|
23
|
+
* `--exm-tooltip-opacity` | Tooltip opacity | 0.9
|
|
24
|
+
* `--exm-tooltip-text-color` | Font color | white
|
|
25
|
+
* `--exm-tooltip-padding` | Container padding | 8px
|
|
26
|
+
* `--exm-tooltip-border-radius` | Container border radius | 2px
|
|
27
|
+
* `--exm-tooltip-min-width` | Breadcrumb container background color | initial
|
|
28
|
+
*/
|
|
29
|
+
let ExmTooltip = class ExmTooltip extends ExmTooltipBase {
|
|
30
|
+
};
|
|
31
|
+
ExmTooltip.styles = style;
|
|
32
|
+
ExmTooltip = __decorate([
|
|
33
|
+
customElement('exm-tooltip')
|
|
34
|
+
], ExmTooltip);
|
|
35
|
+
export { ExmTooltip };
|
|
36
|
+
//# sourceMappingURL=exm-tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const style: import("lit").CSSResult;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export const style = css `
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
position: absolute;
|
|
6
|
+
outline: none;
|
|
7
|
+
z-index: var(--exm-tooltip-z-index, 1002);
|
|
8
|
+
-moz-user-select: none;
|
|
9
|
+
-ms-user-select: none;
|
|
10
|
+
-webkit-user-select: none;
|
|
11
|
+
user-select: none;
|
|
12
|
+
cursor: default;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#tooltip {
|
|
16
|
+
display: block;
|
|
17
|
+
outline: none;
|
|
18
|
+
font-size: var(--exm-tooltip-font-size, 12px);
|
|
19
|
+
line-height: var(--exm-tooltip-line-height, 14px);
|
|
20
|
+
background-color: var(--exm-tooltip-background-color, var(--md-sys-color-inverse-surface, #333));
|
|
21
|
+
color: var(--exm-tooltip-color, var(--md-sys-color-inverse-on-surface, white));
|
|
22
|
+
padding: var(--exm-tooltip-padding, 8px);
|
|
23
|
+
border-radius: var(--exm-tooltip-border-radius, 2px);
|
|
24
|
+
min-width: var(--exm-tooltip-min-width, initial);
|
|
25
|
+
width: max-content;
|
|
26
|
+
transition: opacity 0.5s;
|
|
27
|
+
z-index: 10;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#tooltip.hidden {
|
|
31
|
+
opacity: 0;
|
|
32
|
+
display: none;
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
//# sourceMappingURL=exm-tooltip-styles-css.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ExmgElement } from '@exmg/lit-base/index.js';
|
|
2
|
+
type TooltipPositions = 'top' | 'right' | 'bottom' | 'left' | 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left';
|
|
2
3
|
export declare class ExmTooltipBase extends ExmgElement {
|
|
3
4
|
/**
|
|
4
5
|
* The id of the element that the tooltip is anchored to. This element
|
|
@@ -8,7 +9,7 @@ export declare class ExmTooltipBase extends ExmgElement {
|
|
|
8
9
|
/**
|
|
9
10
|
* Positions the tooltip to the top, right, bottom, left of its content.
|
|
10
11
|
*/
|
|
11
|
-
position:
|
|
12
|
+
position: TooltipPositions;
|
|
12
13
|
/**
|
|
13
14
|
* If true, no parts of the tooltip will ever be shown offscreen.
|
|
14
15
|
*/
|
|
@@ -16,16 +17,19 @@ export declare class ExmTooltipBase extends ExmgElement {
|
|
|
16
17
|
/**
|
|
17
18
|
* X axis offset from the parent's center
|
|
18
19
|
*/
|
|
19
|
-
xOffset
|
|
20
|
+
xOffset: number;
|
|
20
21
|
/**
|
|
21
22
|
* Y axis offset from the parent's center
|
|
22
23
|
*/
|
|
23
|
-
yOffset
|
|
24
|
-
|
|
24
|
+
yOffset: number;
|
|
25
|
+
private showing;
|
|
25
26
|
tooltip?: HTMLElement;
|
|
26
27
|
private _target?;
|
|
27
|
-
private
|
|
28
|
-
private
|
|
28
|
+
private _parent?;
|
|
29
|
+
private boundShow;
|
|
30
|
+
private boundHide;
|
|
31
|
+
private boundMouseMove;
|
|
32
|
+
private boundMouseLeave;
|
|
29
33
|
/**
|
|
30
34
|
* Returns the target element that this tooltip is anchored to. It is
|
|
31
35
|
* either the element given by the `for` attribute, or the immediate parent
|
|
@@ -34,15 +38,19 @@ export declare class ExmTooltipBase extends ExmgElement {
|
|
|
34
38
|
get target(): any;
|
|
35
39
|
connectedCallback(): void;
|
|
36
40
|
disconnectedCallback(): void;
|
|
37
|
-
|
|
41
|
+
protected firstUpdated(): void;
|
|
42
|
+
private handleMousemove;
|
|
43
|
+
private handleMouseleave;
|
|
44
|
+
private show;
|
|
38
45
|
/**
|
|
39
46
|
* Toggles a CSS class on or off.
|
|
40
47
|
*/
|
|
41
|
-
toggleClass
|
|
42
|
-
hide
|
|
43
|
-
updatePosition
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
private toggleClass;
|
|
49
|
+
private hide;
|
|
50
|
+
private updatePosition;
|
|
51
|
+
private addListeners;
|
|
52
|
+
private findTarget;
|
|
53
|
+
private removeListeners;
|
|
47
54
|
protected render(): import("lit-html").TemplateResult<1>;
|
|
48
55
|
}
|
|
56
|
+
export {};
|
package/dist/exm-tooltip-base.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { __decorate } from
|
|
1
|
+
import { __decorate } from 'tslib';
|
|
2
2
|
import { html } from 'lit';
|
|
3
3
|
import { property } from 'lit/decorators/property.js';
|
|
4
4
|
import { state } from 'lit/decorators.js';
|
|
5
5
|
import { query } from 'lit/decorators/query.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { observer, ExmgElement } from '@exmg/lit-base/index.js';
|
|
7
|
+
|
|
8
|
+
class ExmTooltipBase extends ExmgElement {
|
|
8
9
|
constructor() {
|
|
9
10
|
super(...arguments);
|
|
10
11
|
/**
|
|
@@ -15,7 +16,15 @@ export class ExmTooltipBase extends ExmgElement {
|
|
|
15
16
|
* If true, no parts of the tooltip will ever be shown offscreen.
|
|
16
17
|
*/
|
|
17
18
|
this.fitToVisibleBounds = false;
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* X axis offset from the parent's center
|
|
21
|
+
*/
|
|
22
|
+
this.xOffset = 0;
|
|
23
|
+
/**
|
|
24
|
+
* Y axis offset from the parent's center
|
|
25
|
+
*/
|
|
26
|
+
this.yOffset = 0;
|
|
27
|
+
this.showing = false;
|
|
19
28
|
}
|
|
20
29
|
/**
|
|
21
30
|
* Returns the target element that this tooltip is anchored to. It is
|
|
@@ -26,39 +35,72 @@ export class ExmTooltipBase extends ExmgElement {
|
|
|
26
35
|
const parentNode = this.parentNode;
|
|
27
36
|
// If the parentNode is a document fragment, then we need to use the host.
|
|
28
37
|
const ownerRoot = parentNode.getRootNode();
|
|
29
|
-
let target;
|
|
30
38
|
if (this.for) {
|
|
31
|
-
|
|
39
|
+
return ownerRoot.querySelector('#' + this.for);
|
|
32
40
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
target = parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? ownerRoot.host : parentNode;
|
|
36
|
-
}
|
|
37
|
-
return target;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
return parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? ownerRoot.host : parentNode;
|
|
38
43
|
}
|
|
39
44
|
connectedCallback() {
|
|
40
45
|
super.connectedCallback();
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
46
|
+
this.boundShow = this.show.bind(this);
|
|
47
|
+
this.boundHide = this.hide.bind(this);
|
|
48
|
+
this.boundMouseMove = this.handleMousemove.bind(this);
|
|
49
|
+
this.boundMouseLeave = this.handleMouseleave.bind(this);
|
|
43
50
|
this.setAttribute('role', 'tooltip');
|
|
44
51
|
this.setAttribute('tabindex', '-1');
|
|
45
|
-
this.
|
|
52
|
+
this.findTarget();
|
|
46
53
|
}
|
|
47
54
|
disconnectedCallback() {
|
|
48
|
-
this.
|
|
55
|
+
this.removeListeners();
|
|
49
56
|
super.disconnectedCallback();
|
|
50
57
|
}
|
|
51
|
-
|
|
58
|
+
firstUpdated() {
|
|
59
|
+
this.findTarget();
|
|
60
|
+
this.updatePosition();
|
|
61
|
+
}
|
|
62
|
+
handleMousemove(event) {
|
|
63
|
+
if (!this._target || !this._parent) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const mousePosition = {
|
|
67
|
+
x: event.clientX,
|
|
68
|
+
y: event.clientY,
|
|
69
|
+
};
|
|
70
|
+
const targetRect = this._target.getBoundingClientRect();
|
|
71
|
+
if (mousePosition.x < targetRect.left - 1 || mousePosition.x > targetRect.right + 1) {
|
|
72
|
+
this._parent.removeEventListener('mousemove', this.boundMouseMove);
|
|
73
|
+
this.hide();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (mousePosition.y < targetRect.top - 1 || mousePosition.y > targetRect.bottom + 1) {
|
|
77
|
+
this._parent.removeEventListener('mousemove', this.boundMouseMove);
|
|
78
|
+
this.hide();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
handleMouseleave() {
|
|
83
|
+
if (!this._target || !this._parent) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.hide();
|
|
87
|
+
this._parent.removeEventListener('mouseout', this.boundMouseLeave);
|
|
88
|
+
this._parent.removeEventListener('mousemove', this.boundMouseMove);
|
|
89
|
+
}
|
|
90
|
+
show(event) {
|
|
91
|
+
event.stopPropagation();
|
|
52
92
|
// If the tooltip is already showing, there's nothing to do.
|
|
53
|
-
if (this.
|
|
93
|
+
if (this.showing || !this._parent) {
|
|
54
94
|
return;
|
|
55
95
|
}
|
|
96
|
+
this._parent.addEventListener('mousemove', this.boundMouseMove);
|
|
97
|
+
this._parent.addEventListener('mouseout', this.boundMouseLeave);
|
|
56
98
|
if (this.textContent.trim() === '') {
|
|
57
99
|
// Check if effective children are also empty
|
|
58
100
|
let allChildrenEmpty = true;
|
|
59
101
|
const effectiveChildren = this.childNodes;
|
|
60
|
-
for (
|
|
61
|
-
if (
|
|
102
|
+
for (const child of effectiveChildren) {
|
|
103
|
+
if (child.textContent.trim() !== '') {
|
|
62
104
|
allChildrenEmpty = false;
|
|
63
105
|
break;
|
|
64
106
|
}
|
|
@@ -67,7 +109,7 @@ export class ExmTooltipBase extends ExmgElement {
|
|
|
67
109
|
return;
|
|
68
110
|
}
|
|
69
111
|
}
|
|
70
|
-
this.
|
|
112
|
+
this.showing = true;
|
|
71
113
|
this.toggleClass('hidden', false, this.tooltip);
|
|
72
114
|
this.updatePosition();
|
|
73
115
|
}
|
|
@@ -88,19 +130,19 @@ export class ExmTooltipBase extends ExmgElement {
|
|
|
88
130
|
}
|
|
89
131
|
hide() {
|
|
90
132
|
// If the tooltip is already hidden, there's nothing to do.
|
|
91
|
-
if (!this.
|
|
133
|
+
if (!this.showing) {
|
|
92
134
|
return;
|
|
93
135
|
}
|
|
94
|
-
this.
|
|
136
|
+
this.showing = false;
|
|
95
137
|
this.toggleClass('hidden', true, this.tooltip);
|
|
96
138
|
}
|
|
97
139
|
updatePosition() {
|
|
98
|
-
if (!this._target || !this.offsetParent) {
|
|
140
|
+
if (!this._target || !this.offsetParent || !this.tooltip) {
|
|
99
141
|
return;
|
|
100
142
|
}
|
|
101
143
|
const parentRect = this.offsetParent.getBoundingClientRect();
|
|
102
144
|
const targetRect = this._target.getBoundingClientRect();
|
|
103
|
-
const thisRect = this.getBoundingClientRect();
|
|
145
|
+
const thisRect = this.tooltip.getBoundingClientRect();
|
|
104
146
|
const horizontalCenterOffset = (targetRect.width - thisRect.width) / 2;
|
|
105
147
|
const verticalCenterOffset = (targetRect.height - thisRect.height) / 2;
|
|
106
148
|
const targetLeft = targetRect.left - parentRect.left;
|
|
@@ -124,13 +166,25 @@ export class ExmTooltipBase extends ExmgElement {
|
|
|
124
166
|
tooltipLeft = targetLeft + targetRect.width;
|
|
125
167
|
tooltipTop = targetTop + verticalCenterOffset;
|
|
126
168
|
break;
|
|
169
|
+
case 'top-left':
|
|
170
|
+
tooltipLeft = targetLeft;
|
|
171
|
+
tooltipTop = targetTop - thisRect.height;
|
|
172
|
+
break;
|
|
173
|
+
case 'bottom-left':
|
|
174
|
+
tooltipLeft = targetLeft;
|
|
175
|
+
tooltipTop = targetTop + targetRect.height;
|
|
176
|
+
break;
|
|
177
|
+
case 'top-right':
|
|
178
|
+
tooltipLeft = targetLeft - thisRect.width + targetRect.width;
|
|
179
|
+
tooltipTop = targetTop - thisRect.height;
|
|
180
|
+
break;
|
|
181
|
+
case 'bottom-right':
|
|
182
|
+
tooltipLeft = targetLeft - thisRect.width + targetRect.width;
|
|
183
|
+
tooltipTop = targetTop + targetRect.height;
|
|
184
|
+
break;
|
|
127
185
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
if (this.yOffset !== undefined) {
|
|
132
|
-
tooltipTop += this.yOffset;
|
|
133
|
-
}
|
|
186
|
+
tooltipLeft += this.xOffset;
|
|
187
|
+
tooltipTop += this.yOffset;
|
|
134
188
|
if (this.fitToVisibleBounds) {
|
|
135
189
|
// Clip the left/right side
|
|
136
190
|
if (parentRect.left + tooltipLeft + thisRect.width > window.innerWidth) {
|
|
@@ -156,47 +210,46 @@ export class ExmTooltipBase extends ExmgElement {
|
|
|
156
210
|
this.style.top = tooltipTop + 'px';
|
|
157
211
|
}
|
|
158
212
|
}
|
|
159
|
-
|
|
213
|
+
addListeners() {
|
|
160
214
|
if (this._target) {
|
|
161
|
-
this._target.addEventListener('mouseenter', this.
|
|
162
|
-
this._target.addEventListener('focus', this.
|
|
163
|
-
this._target.addEventListener('
|
|
164
|
-
this._target.addEventListener('
|
|
165
|
-
this._target.addEventListener('tap', this._boundHide);
|
|
215
|
+
this._target.addEventListener('mouseenter', this.boundShow);
|
|
216
|
+
this._target.addEventListener('focus', this.boundShow);
|
|
217
|
+
this._target.addEventListener('blur', this.boundHide);
|
|
218
|
+
this._target.addEventListener('tap', this.boundHide);
|
|
166
219
|
}
|
|
167
|
-
this.addEventListener('mouseenter', this.
|
|
220
|
+
this.addEventListener('mouseenter', this.boundShow);
|
|
168
221
|
}
|
|
169
|
-
|
|
170
|
-
this.
|
|
222
|
+
findTarget() {
|
|
223
|
+
this.removeListeners();
|
|
171
224
|
this._target = this.target;
|
|
172
|
-
this.
|
|
225
|
+
this._parent = this.parentNode;
|
|
226
|
+
this.addListeners();
|
|
173
227
|
}
|
|
174
|
-
|
|
228
|
+
removeListeners() {
|
|
175
229
|
if (this._target) {
|
|
176
|
-
this._target.removeEventListener('mouseenter', this.
|
|
177
|
-
this._target.removeEventListener('focus', this.
|
|
178
|
-
this._target.removeEventListener('
|
|
179
|
-
this._target.removeEventListener('
|
|
180
|
-
this._target.removeEventListener('tap', this._boundHide);
|
|
230
|
+
this._target.removeEventListener('mouseenter', this.boundShow);
|
|
231
|
+
this._target.removeEventListener('focus', this.boundShow);
|
|
232
|
+
this._target.removeEventListener('blur', this.boundHide);
|
|
233
|
+
this._target.removeEventListener('tap', this.boundHide);
|
|
181
234
|
}
|
|
182
|
-
this.removeEventListener('mouseenter', this.
|
|
235
|
+
this.removeEventListener('mouseenter', this.boundShow);
|
|
183
236
|
}
|
|
184
237
|
render() {
|
|
185
238
|
return html `
|
|
186
|
-
<
|
|
239
|
+
<section id="tooltip" class="hidden">
|
|
187
240
|
<slot></slot>
|
|
188
|
-
</
|
|
241
|
+
</section>
|
|
189
242
|
`;
|
|
190
243
|
}
|
|
191
244
|
}
|
|
192
245
|
__decorate([
|
|
193
246
|
property({ type: String }),
|
|
194
247
|
observer(function () {
|
|
195
|
-
this.
|
|
248
|
+
this.findTarget();
|
|
196
249
|
})
|
|
197
250
|
], ExmTooltipBase.prototype, "for", void 0);
|
|
198
251
|
__decorate([
|
|
199
|
-
property(
|
|
252
|
+
property()
|
|
200
253
|
], ExmTooltipBase.prototype, "position", void 0);
|
|
201
254
|
__decorate([
|
|
202
255
|
property({ type: Boolean })
|
|
@@ -209,8 +262,10 @@ __decorate([
|
|
|
209
262
|
], ExmTooltipBase.prototype, "yOffset", void 0);
|
|
210
263
|
__decorate([
|
|
211
264
|
state()
|
|
212
|
-
], ExmTooltipBase.prototype, "
|
|
265
|
+
], ExmTooltipBase.prototype, "showing", void 0);
|
|
213
266
|
__decorate([
|
|
214
267
|
query('#tooltip')
|
|
215
268
|
], ExmTooltipBase.prototype, "tooltip", void 0);
|
|
216
|
-
|
|
269
|
+
|
|
270
|
+
export { ExmTooltipBase };
|
|
271
|
+
//# sourceMappingURL=exm-tooltip-base.js.map
|
package/dist/exm-tooltip.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { __decorate } from
|
|
1
|
+
import { __decorate } from 'tslib';
|
|
2
2
|
import { customElement } from 'lit/decorators/custom-element.js';
|
|
3
3
|
import { style } from './styles/exm-tooltip-styles-css.js';
|
|
4
4
|
import { ExmTooltipBase } from './exm-tooltip-base.js';
|
|
5
|
+
|
|
5
6
|
/**
|
|
6
7
|
* `exm-tooltip`
|
|
7
8
|
* Example:
|
|
@@ -32,5 +33,6 @@ ExmTooltip.styles = style;
|
|
|
32
33
|
ExmTooltip = __decorate([
|
|
33
34
|
customElement('exm-tooltip')
|
|
34
35
|
], ExmTooltip);
|
|
36
|
+
|
|
35
37
|
export { ExmTooltip };
|
|
36
|
-
//# sourceMappingURL=exm-tooltip.js.map
|
|
38
|
+
//# sourceMappingURL=exm-tooltip.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
const style = css `
|
|
3
4
|
:host {
|
|
4
5
|
display: block;
|
|
5
6
|
position: absolute;
|
|
@@ -22,7 +23,9 @@ export const style = css `
|
|
|
22
23
|
padding: var(--exm-tooltip-padding, 8px);
|
|
23
24
|
border-radius: var(--exm-tooltip-border-radius, 2px);
|
|
24
25
|
min-width: var(--exm-tooltip-min-width, initial);
|
|
26
|
+
width: max-content;
|
|
25
27
|
transition: opacity 0.5s;
|
|
28
|
+
z-index: 10;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
#tooltip.hidden {
|
|
@@ -30,4 +33,6 @@ export const style = css `
|
|
|
30
33
|
display: none;
|
|
31
34
|
}
|
|
32
35
|
`;
|
|
33
|
-
|
|
36
|
+
|
|
37
|
+
export { style };
|
|
38
|
+
//# sourceMappingURL=exm-tooltip-styles-css.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exmg/exm-tooltip",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.10-alpha.26+dffd4ec",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
".": "./dist/index.js",
|
|
10
10
|
"./exm-tooltip.js": "./dist/exm-tooltip.js"
|
|
11
11
|
},
|
|
12
|
-
"
|
|
13
|
-
"@exmg/lit-base": "^3.0.
|
|
14
|
-
"
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"@exmg/lit-base": "^3.0.3",
|
|
14
|
+
"@material/web": "^2.2.0",
|
|
15
|
+
"lit": "^3.2.1",
|
|
15
16
|
"tslib": "^2.6.2"
|
|
16
17
|
},
|
|
17
18
|
"files": [
|
|
@@ -31,12 +32,9 @@
|
|
|
31
32
|
"directory": "packages/exm-tooltip"
|
|
32
33
|
},
|
|
33
34
|
"license": "MIT",
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@exmg/lit-cli": "1.1.13"
|
|
36
|
-
},
|
|
37
35
|
"scripts": {},
|
|
38
36
|
"publishConfig": {
|
|
39
37
|
"access": "public"
|
|
40
38
|
},
|
|
41
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "dffd4ecb68fdeb061f4e8ad585af221bfb0f8e8b"
|
|
42
40
|
}
|