@exmg/exm-tooltip 1.0.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/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # `<exm-tooltip>` [![Published on npm](https://img.shields.io/npm/v/@exmg/exm-tooltip.svg)](https://www.npmjs.com/package/@exmg/exm-tooltip)
2
+
3
+ # @exmg/exm-tooltip
4
+
5
+ Tooltip element to display small amounts of information bound to an element.
6
+
7
+ [Demo](https://exmg.github.io/exmachina-web-components/demo/?el=exm-tooltip)
8
+
9
+ ## Installation
10
+
11
+ ```sh
12
+ npm install @exmg/exm-tooltip
13
+ ```
14
+
15
+ ## Example Usage
16
+
17
+ ### Standard
18
+
19
+ ```html
20
+ <div style="position:relative;">
21
+ <button id="styledBtn">Test</button>
22
+ <exm-tooltip for="styledBtn">the name means "different lizard"</exm-tooltip>
23
+ </div>
24
+ ```
25
+
26
+ ## API
27
+
28
+ ### Slots
29
+
30
+ | Name | Description |
31
+ | --------- | ---------------------------------- |
32
+ | _default_ | Button to handle copy to clipboard |
33
+
34
+ ### Properties/Attributes
35
+
36
+ | Name | Type | Default | Description |
37
+ | -------------------- | --------- | ---------- | ----------------------------------------------------------------------------------------------------- |
38
+ | `for` | `string` | _None_ | The id of the element that the tooltip is anchored to. This element must be a sibling of the tooltip. |
39
+ | `position` | `string` | _`bottom`_ | Positions the tooltip to the top, right, bottom, left of its content. |
40
+ | `fitToVisibleBounds` | `boolean` | _None_ | The id of the element that the tooltip is anchored to. This element must be a sibling of the tooltip. |
41
+ | `xOffset` | `number` | _None_ | X axis offset from the parent's center. |
42
+ | `yOffset` | `number` | _None_ | Y axis offset from the parent's center. |
43
+
44
+ ### Methods
45
+
46
+ _None_
47
+
48
+ ### Events
49
+
50
+ _None_
51
+
52
+ ### CSS Custom Properties
53
+
54
+ | Name | Default | Description |
55
+ | ----------------------------- | --------- | ------------------------- |
56
+ | `--exm-tooltip-font-size` | `10px` | Font size of tooltip text |
57
+ | `--exm-tooltip-line-height` | `1` | Text line height |
58
+ | `--exm-tooltip-background` | `#616161` | Background color |
59
+ | `--exm-tooltip-opacity` | `0.9` | Tooltip opacity |
60
+ | `--exm-tooltip-text-color` | `white` | Font color |
61
+ | `--exm-tooltip-padding` | `8px` | Container padding |
62
+ | `--exm-tooltip-border-radius` | `2px` | Container border radius |
63
+ | `--exm-tooltip-min-width` | `initial` | Min width of the tooltip |
64
+
65
+ ## Additional references
66
+
67
+ - [Additional Documentation](https://exmg.github.io/exmachina-web-components/ExmgTooltip.html)
68
+
69
+ - [Demo](https://exmg.github.io/exmachina-web-components/demo/?el=exm-tooltip)
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { ExmgTooltip } from './src/exm-tooltip.js';
2
+ export { ExmgTooltipBase } from './src/exm-tooltip-base.js';
3
+ export { style as tooltipStyles } from './src/styles/exm-tooltip-styles-css.js';
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { ExmgTooltip } from './src/exm-tooltip.js';
2
+ export { ExmgTooltipBase } from './src/exm-tooltip-base.js';
3
+ export { style as tooltipStyles } from './src/styles/exm-tooltip-styles-css.js';
4
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@exmg/exm-tooltip",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "index.js",
6
+ "module": "index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./exm-tooltip.js": "./src/exm-tooltip.js"
10
+ },
11
+ "dependencies": {
12
+ "@exmg/lit-base": "^2.0.1",
13
+ "lit": "^3.0.0",
14
+ "tslib": "^2.6.2"
15
+ },
16
+ "files": [
17
+ "**/*.scss",
18
+ "**/*.js",
19
+ "**/*.d.ts"
20
+ ],
21
+ "keywords": [
22
+ "web-components",
23
+ "lit-element",
24
+ "tooltip"
25
+ ],
26
+ "homepage": "https://github.com/exmg/exmachina-web-components",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git@github.com:exmg/exm-web-components.git",
30
+ "directory": "packages/exm-tooltip"
31
+ },
32
+ "license": "MIT",
33
+ "devDependencies": {
34
+ "@exmg/lit-cli": "1.1.13"
35
+ },
36
+ "scripts": {
37
+ "build:styles": "exmg-lit-cli sass -f \"./**/*.scss\""
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "gitHead": "0907b55c89325d59902b98a64c352bf6e1fc81ff"
43
+ }
@@ -0,0 +1,48 @@
1
+ import { ExmgElement } from '@exmg/lit-base/index.js';
2
+ export declare class ExmgTooltipBase extends ExmgElement {
3
+ /**
4
+ * The id of the element that the tooltip is anchored to. This element
5
+ * must be a sibling of the tooltip.
6
+ */
7
+ for?: string;
8
+ /**
9
+ * Positions the tooltip to the top, right, bottom, left of its content.
10
+ */
11
+ position: string;
12
+ /**
13
+ * If true, no parts of the tooltip will ever be shown offscreen.
14
+ */
15
+ fitToVisibleBounds: boolean;
16
+ /**
17
+ * X axis offset from the parent's center
18
+ */
19
+ xOffset?: number;
20
+ /**
21
+ * Y axis offset from the parent's center
22
+ */
23
+ yOffset?: number;
24
+ _showing: boolean;
25
+ tooltip?: HTMLElement;
26
+ private _target?;
27
+ private _boundShow;
28
+ private _boundHide;
29
+ /**
30
+ * Returns the target element that this tooltip is anchored to. It is
31
+ * either the element given by the `for` attribute, or the immediate parent
32
+ * of the tooltip.
33
+ */
34
+ get target(): any;
35
+ connectedCallback(): void;
36
+ disconnectedCallback(): void;
37
+ show(): void;
38
+ /**
39
+ * Toggles a CSS class on or off.
40
+ */
41
+ toggleClass(name: string, bool: boolean, node: HTMLElement): void;
42
+ hide(): void;
43
+ updatePosition(): void;
44
+ _addListeners(): void;
45
+ _findTarget(): void;
46
+ _removeListeners(): void;
47
+ protected render(): import("lit-html").TemplateResult<1>;
48
+ }
@@ -0,0 +1,216 @@
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 ExmgTooltipBase 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
+ this._showing = false;
19
+ }
20
+ /**
21
+ * Returns the target element that this tooltip is anchored to. It is
22
+ * either the element given by the `for` attribute, or the immediate parent
23
+ * of the tooltip.
24
+ */
25
+ get target() {
26
+ const parentNode = this.parentNode;
27
+ // If the parentNode is a document fragment, then we need to use the host.
28
+ const ownerRoot = parentNode.getRootNode();
29
+ let target;
30
+ if (this.for) {
31
+ target = ownerRoot.querySelector('#' + this.for);
32
+ }
33
+ else {
34
+ // @ts-ignore
35
+ target = parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? ownerRoot.host : parentNode;
36
+ }
37
+ return target;
38
+ }
39
+ connectedCallback() {
40
+ super.connectedCallback();
41
+ this._boundShow = this.show.bind(this);
42
+ this._boundHide = this.hide.bind(this);
43
+ this.setAttribute('role', 'tooltip');
44
+ this.setAttribute('tabindex', '-1');
45
+ this._findTarget();
46
+ }
47
+ disconnectedCallback() {
48
+ this._removeListeners();
49
+ super.disconnectedCallback();
50
+ }
51
+ show() {
52
+ // If the tooltip is already showing, there's nothing to do.
53
+ if (this._showing) {
54
+ return;
55
+ }
56
+ if (this.textContent.trim() === '') {
57
+ // Check if effective children are also empty
58
+ let allChildrenEmpty = true;
59
+ const effectiveChildren = this.childNodes;
60
+ for (let i = 0; i < effectiveChildren.length; i++) {
61
+ if (effectiveChildren[i].textContent.trim() !== '') {
62
+ allChildrenEmpty = false;
63
+ break;
64
+ }
65
+ }
66
+ if (allChildrenEmpty) {
67
+ return;
68
+ }
69
+ }
70
+ this._showing = true;
71
+ this.toggleClass('hidden', false, this.tooltip);
72
+ this.updatePosition();
73
+ }
74
+ /**
75
+ * Toggles a CSS class on or off.
76
+ */
77
+ toggleClass(name, bool, node) {
78
+ node = /** @type {Element} */ node || this;
79
+ if (arguments.length == 1) {
80
+ bool = !node.classList.contains(name);
81
+ }
82
+ if (bool) {
83
+ node.classList.add(name);
84
+ }
85
+ else {
86
+ node.classList.remove(name);
87
+ }
88
+ }
89
+ hide() {
90
+ // If the tooltip is already hidden, there's nothing to do.
91
+ if (!this._showing) {
92
+ return;
93
+ }
94
+ this._showing = false;
95
+ this.toggleClass('hidden', true, this.tooltip);
96
+ }
97
+ updatePosition() {
98
+ if (!this._target || !this.offsetParent) {
99
+ return;
100
+ }
101
+ const parentRect = this.offsetParent.getBoundingClientRect();
102
+ const targetRect = this._target.getBoundingClientRect();
103
+ const thisRect = this.getBoundingClientRect();
104
+ const horizontalCenterOffset = (targetRect.width - thisRect.width) / 2;
105
+ const verticalCenterOffset = (targetRect.height - thisRect.height) / 2;
106
+ const targetLeft = targetRect.left - parentRect.left;
107
+ const targetTop = targetRect.top - parentRect.top;
108
+ let tooltipLeft = 0;
109
+ let tooltipTop = 0;
110
+ switch (this.position) {
111
+ case 'top':
112
+ tooltipLeft = targetLeft + horizontalCenterOffset;
113
+ tooltipTop = targetTop - thisRect.height;
114
+ break;
115
+ case 'bottom':
116
+ tooltipLeft = targetLeft + horizontalCenterOffset;
117
+ tooltipTop = targetTop + targetRect.height;
118
+ break;
119
+ case 'left':
120
+ tooltipLeft = targetLeft - thisRect.width;
121
+ tooltipTop = targetTop + verticalCenterOffset;
122
+ break;
123
+ case 'right':
124
+ tooltipLeft = targetLeft + targetRect.width;
125
+ tooltipTop = targetTop + verticalCenterOffset;
126
+ break;
127
+ }
128
+ if (this.xOffset !== undefined) {
129
+ tooltipLeft += this.xOffset;
130
+ }
131
+ if (this.yOffset !== undefined) {
132
+ tooltipTop += this.yOffset;
133
+ }
134
+ if (this.fitToVisibleBounds) {
135
+ // Clip the left/right side
136
+ if (parentRect.left + tooltipLeft + thisRect.width > window.innerWidth) {
137
+ this.style.right = '0px';
138
+ this.style.left = 'auto';
139
+ }
140
+ else {
141
+ this.style.left = Math.max(0, tooltipLeft) + 'px';
142
+ this.style.right = 'auto';
143
+ }
144
+ // Clip the top/bottom side.
145
+ if (parentRect.top + tooltipTop + thisRect.height > window.innerHeight) {
146
+ this.style.bottom = parentRect.height + 'px';
147
+ this.style.top = 'auto';
148
+ }
149
+ else {
150
+ this.style.top = Math.max(-parentRect.top, tooltipTop) + 'px';
151
+ this.style.bottom = 'auto';
152
+ }
153
+ }
154
+ else {
155
+ this.style.left = tooltipLeft + 'px';
156
+ this.style.top = tooltipTop + 'px';
157
+ }
158
+ }
159
+ _addListeners() {
160
+ if (this._target) {
161
+ this._target.addEventListener('mouseenter', this._boundShow);
162
+ this._target.addEventListener('focus', this._boundShow);
163
+ this._target.addEventListener('mouseleave', this._boundHide);
164
+ this._target.addEventListener('blur', this._boundHide);
165
+ this._target.addEventListener('tap', this._boundHide);
166
+ }
167
+ this.addEventListener('mouseenter', this._boundHide);
168
+ }
169
+ _findTarget() {
170
+ this._removeListeners();
171
+ this._target = this.target;
172
+ this._addListeners();
173
+ }
174
+ _removeListeners() {
175
+ if (this._target) {
176
+ this._target.removeEventListener('mouseenter', this._boundShow);
177
+ this._target.removeEventListener('focus', this._boundShow);
178
+ this._target.removeEventListener('mouseleave', this._boundHide);
179
+ this._target.removeEventListener('blur', this._boundHide);
180
+ this._target.removeEventListener('tap', this._boundHide);
181
+ }
182
+ this.removeEventListener('mouseenter', this._boundHide);
183
+ }
184
+ render() {
185
+ return html `
186
+ <div id="tooltip" class="hidden">
187
+ <slot></slot>
188
+ </div>
189
+ `;
190
+ }
191
+ }
192
+ __decorate([
193
+ property({ type: String }),
194
+ observer(function () {
195
+ this._findTarget();
196
+ })
197
+ ], ExmgTooltipBase.prototype, "for", void 0);
198
+ __decorate([
199
+ property({ type: String })
200
+ ], ExmgTooltipBase.prototype, "position", void 0);
201
+ __decorate([
202
+ property({ type: Boolean })
203
+ ], ExmgTooltipBase.prototype, "fitToVisibleBounds", void 0);
204
+ __decorate([
205
+ property({ type: Number })
206
+ ], ExmgTooltipBase.prototype, "xOffset", void 0);
207
+ __decorate([
208
+ property({ type: Number })
209
+ ], ExmgTooltipBase.prototype, "yOffset", void 0);
210
+ __decorate([
211
+ state()
212
+ ], ExmgTooltipBase.prototype, "_showing", void 0);
213
+ __decorate([
214
+ query('#tooltip')
215
+ ], ExmgTooltipBase.prototype, "tooltip", void 0);
216
+ //# sourceMappingURL=exm-tooltip-base.js.map
@@ -0,0 +1,33 @@
1
+ import { ExmgTooltipBase } 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 ExmgTooltip extends ExmgTooltipBase {
27
+ static styles: import("lit").CSSResult;
28
+ }
29
+ declare global {
30
+ interface HTMLElementTagNameMap {
31
+ 'exm-tooltip': ExmgTooltip;
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 { ExmgTooltipBase } 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 ExmgTooltip = class ExmgTooltip extends ExmgTooltipBase {
30
+ };
31
+ ExmgTooltip.styles = style;
32
+ ExmgTooltip = __decorate([
33
+ customElement('exm-tooltip')
34
+ ], ExmgTooltip);
35
+ export { ExmgTooltip };
36
+ //# sourceMappingURL=exm-tooltip.js.map
@@ -0,0 +1,2 @@
1
+ export declare const style: import("lit").CSSResult;
2
+ export default style;
@@ -0,0 +1,4 @@
1
+ import { css } from 'lit';
2
+ export const style = css `:host{display:block;position:absolute;outline:none;z-index:var(--exm-tooltip-z-index, 1002);-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;cursor:default}#tooltip{display:block;outline:none;font-size:var(--exm-tooltip-font-size, 12px);line-height:var(--exm-tooltip-line-height, 14px);background-color:var(--exm-tooltip-background-color, var(--md-sys-color-inverse-surface, #333));color:var(--exm-tooltip-color, var(--md-sys-color-inverse-on-surface, white));padding:var(--exm-tooltip-padding, 8px);border-radius:var(--exm-tooltip-border-radius, 2px);min-width:var(--exm-tooltip-min-width, initial);transition:opacity .5s}#tooltip.hidden{opacity:0;display:none}`;
3
+ export default style;
4
+ //# sourceMappingURL=exm-tooltip-styles-css.js.map
@@ -0,0 +1,29 @@
1
+ :host {
2
+ display: block;
3
+ position: absolute;
4
+ outline: none;
5
+ z-index: var(--exm-tooltip-z-index, 1002);
6
+ -moz-user-select: none;
7
+ -ms-user-select: none;
8
+ -webkit-user-select: none;
9
+ user-select: none;
10
+ cursor: default;
11
+ }
12
+
13
+ #tooltip {
14
+ display: block;
15
+ outline: none;
16
+ font-size: var(--exm-tooltip-font-size, 12px);
17
+ line-height: var(--exm-tooltip-line-height, 14px);
18
+ background-color: var(--exm-tooltip-background-color, var(--md-sys-color-inverse-surface, #333));
19
+ color: var(--exm-tooltip-color, var(--md-sys-color-inverse-on-surface, white));
20
+ padding: var(--exm-tooltip-padding, 8px);
21
+ border-radius: var(--exm-tooltip-border-radius, 2px);
22
+ min-width: var(--exm-tooltip-min-width, initial);
23
+ transition: opacity 0.5s;
24
+ }
25
+
26
+ #tooltip.hidden {
27
+ opacity: 0;
28
+ display: none;
29
+ }