@aquera/nile-elements 0.1.35-beta-1.2 → 0.1.35

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.
Files changed (174) hide show
  1. package/README.md +10 -28
  2. package/demo/index.css +4 -7
  3. package/demo/index.html +36 -20
  4. package/demo/variables.css +0 -13
  5. package/demo/variables_v2.css +0 -13
  6. package/dist/{fixture-d5b55278.cjs.js → fixture-161dee0b.cjs.js} +3 -3
  7. package/dist/fixture-161dee0b.cjs.js.map +1 -0
  8. package/dist/{fixture-df8b52d7.esm.js → fixture-372df3b0.esm.js} +1 -1
  9. package/dist/index.cjs.js +1 -1
  10. package/dist/index.esm.js +1 -1
  11. package/dist/internal/animate.cjs.js +1 -1
  12. package/dist/internal/animate.cjs.js.map +1 -1
  13. package/dist/internal/animate.esm.js +1 -1
  14. package/dist/nile-accordion/nile-accordian.test.cjs.js +1 -1
  15. package/dist/nile-accordion/nile-accordian.test.esm.js +1 -1
  16. package/dist/nile-auto-complete/nile-auto-complete.test.cjs.js +1 -1
  17. package/dist/nile-auto-complete/nile-auto-complete.test.esm.js +1 -1
  18. package/dist/nile-avatar/nile-avatar.test.cjs.js +1 -1
  19. package/dist/nile-avatar/nile-avatar.test.esm.js +1 -1
  20. package/dist/nile-badge/nile-badge.test.cjs.js +1 -1
  21. package/dist/nile-badge/nile-badge.test.esm.js +1 -1
  22. package/dist/nile-button/nile-button.test.cjs.js +1 -1
  23. package/dist/nile-button/nile-button.test.esm.js +1 -1
  24. package/dist/nile-button-toggle-group/nile-button-toggle-group.test.cjs.js +1 -1
  25. package/dist/nile-button-toggle-group/nile-button-toggle-group.test.esm.js +1 -1
  26. package/dist/nile-calendar/nile-calendar.test.cjs.js +1 -1
  27. package/dist/nile-calendar/nile-calendar.test.esm.js +1 -1
  28. package/dist/nile-card/nile-card.test.cjs.js +1 -1
  29. package/dist/nile-card/nile-card.test.esm.js +1 -1
  30. package/dist/nile-checkbox/nile-checkbox.test.cjs.js +1 -1
  31. package/dist/nile-checkbox/nile-checkbox.test.esm.js +1 -1
  32. package/dist/nile-chip/nile-chip.test.cjs.js +1 -1
  33. package/dist/nile-chip/nile-chip.test.esm.js +1 -1
  34. package/dist/nile-dialog/nile-dialog.test.cjs.js +1 -1
  35. package/dist/nile-dialog/nile-dialog.test.esm.js +1 -1
  36. package/dist/nile-drawer/nile-drawer.test.cjs.js +1 -1
  37. package/dist/nile-drawer/nile-drawer.test.esm.js +1 -1
  38. package/dist/nile-dropdown/nile-dropdown.test.cjs.js +1 -1
  39. package/dist/nile-dropdown/nile-dropdown.test.esm.js +1 -1
  40. package/dist/nile-empty-state/nile-empty-state.test.cjs.js +1 -1
  41. package/dist/nile-empty-state/nile-empty-state.test.esm.js +1 -1
  42. package/dist/nile-error-message/nile-error-message.cjs.js +1 -1
  43. package/dist/nile-error-message/nile-error-message.cjs.js.map +1 -1
  44. package/dist/nile-error-message/nile-error-message.css.cjs.js +1 -1
  45. package/dist/nile-error-message/nile-error-message.css.cjs.js.map +1 -1
  46. package/dist/nile-error-message/nile-error-message.css.esm.js +4 -6
  47. package/dist/nile-error-message/nile-error-message.esm.js +4 -4
  48. package/dist/nile-error-message/nile-error-message.test.cjs.js +1 -1
  49. package/dist/nile-error-message/nile-error-message.test.esm.js +1 -1
  50. package/dist/nile-error-notification/nile-error-notification.css.cjs.js +1 -1
  51. package/dist/nile-error-notification/nile-error-notification.css.cjs.js.map +1 -1
  52. package/dist/nile-error-notification/nile-error-notification.css.esm.js +1 -1
  53. package/dist/nile-form-group/nile-form-group.test.cjs.js +1 -1
  54. package/dist/nile-form-group/nile-form-group.test.esm.js +1 -1
  55. package/dist/nile-form-help-text/nile-form-help-text.test.cjs.js +1 -1
  56. package/dist/nile-form-help-text/nile-form-help-text.test.esm.js +1 -1
  57. package/dist/nile-hero/nile-hero.test.cjs.js +1 -1
  58. package/dist/nile-hero/nile-hero.test.esm.js +1 -1
  59. package/dist/nile-icon/nile-icon.test.cjs.js +1 -1
  60. package/dist/nile-icon/nile-icon.test.esm.js +1 -1
  61. package/dist/nile-input/nile-input.test.cjs.js +1 -1
  62. package/dist/nile-input/nile-input.test.esm.js +1 -1
  63. package/dist/nile-link/nile-link.test.cjs.js +1 -1
  64. package/dist/nile-link/nile-link.test.esm.js +1 -1
  65. package/dist/nile-loader/nile-loader.test.cjs.js +1 -1
  66. package/dist/nile-loader/nile-loader.test.esm.js +1 -1
  67. package/dist/nile-popover/nile-popover.test.cjs.js +1 -1
  68. package/dist/nile-popover/nile-popover.test.esm.js +1 -1
  69. package/dist/nile-popup/nile-popup.test.cjs.js +1 -1
  70. package/dist/nile-popup/nile-popup.test.esm.js +1 -1
  71. package/dist/nile-progress-bar/nile-progress-bar.css.cjs.js +1 -1
  72. package/dist/nile-progress-bar/nile-progress-bar.css.cjs.js.map +1 -1
  73. package/dist/nile-progress-bar/nile-progress-bar.css.esm.js +0 -1
  74. package/dist/nile-progress-bar/nile-progress-bar.test.cjs.js +1 -1
  75. package/dist/nile-progress-bar/nile-progress-bar.test.esm.js +1 -1
  76. package/dist/nile-radio/nile-radio.test.cjs.js +1 -1
  77. package/dist/nile-radio/nile-radio.test.esm.js +1 -1
  78. package/dist/nile-radio-group/nile-radio-group.test.cjs.js +1 -1
  79. package/dist/nile-radio-group/nile-radio-group.test.esm.js +1 -1
  80. package/dist/nile-select/nile-select.cjs.js +1 -1
  81. package/dist/nile-select/nile-select.cjs.js.map +1 -1
  82. package/dist/nile-select/nile-select.esm.js +1 -1
  83. package/dist/nile-select/nile-select.test.cjs.js +1 -1
  84. package/dist/nile-select/nile-select.test.esm.js +1 -1
  85. package/dist/nile-slide-toggle/nile-slide-toggle.test.cjs.js +1 -1
  86. package/dist/nile-slide-toggle/nile-slide-toggle.test.esm.js +1 -1
  87. package/dist/nile-tab-group/nile-tab-group.test.cjs.js +1 -1
  88. package/dist/nile-tab-group/nile-tab-group.test.esm.js +1 -1
  89. package/dist/nile-table/nile-table.cjs.js.map +1 -1
  90. package/dist/nile-textarea/nile-textarea.test.cjs.js +1 -1
  91. package/dist/nile-textarea/nile-textarea.test.esm.js +1 -1
  92. package/dist/nile-tooltip/index.cjs.js +1 -1
  93. package/dist/nile-tooltip/index.esm.js +1 -1
  94. package/dist/nile-tooltip/nile-tooltip.cjs.js +1 -1
  95. package/dist/nile-tooltip/nile-tooltip.cjs.js.map +1 -1
  96. package/dist/nile-tooltip/nile-tooltip.css.cjs.js +1 -1
  97. package/dist/nile-tooltip/nile-tooltip.css.cjs.js.map +1 -1
  98. package/dist/nile-tooltip/nile-tooltip.css.esm.js +45 -78
  99. package/dist/nile-tooltip/nile-tooltip.esm.js +28 -23
  100. package/dist/src/index.d.ts +0 -1
  101. package/dist/src/index.js +0 -1
  102. package/dist/src/index.js.map +1 -1
  103. package/dist/src/nile-error-message/nile-error-message.css.js +4 -6
  104. package/dist/src/nile-error-message/nile-error-message.css.js.map +1 -1
  105. package/dist/src/nile-error-message/nile-error-message.d.ts +0 -4
  106. package/dist/src/nile-error-message/nile-error-message.js +0 -20
  107. package/dist/src/nile-error-message/nile-error-message.js.map +1 -1
  108. package/dist/src/nile-error-notification/nile-error-notification.css.js +1 -1
  109. package/dist/src/nile-error-notification/nile-error-notification.css.js.map +1 -1
  110. package/dist/src/nile-progress-bar/nile-progress-bar.css.js +0 -1
  111. package/dist/src/nile-progress-bar/nile-progress-bar.css.js.map +1 -1
  112. package/dist/src/nile-select/nile-select.js +1 -1
  113. package/dist/src/nile-select/nile-select.js.map +1 -1
  114. package/dist/src/nile-table/nile-table.js.map +1 -1
  115. package/dist/src/nile-tooltip/nile-tooltip.css.js +43 -76
  116. package/dist/src/nile-tooltip/nile-tooltip.css.js.map +1 -1
  117. package/dist/src/nile-tooltip/nile-tooltip.d.ts +46 -24
  118. package/dist/src/nile-tooltip/nile-tooltip.js +232 -235
  119. package/dist/src/nile-tooltip/nile-tooltip.js.map +1 -1
  120. package/dist/tsconfig.tsbuildinfo +1 -1
  121. package/package.json +2 -2
  122. package/src/index.ts +1 -2
  123. package/src/nile-error-message/nile-error-message.css.ts +4 -6
  124. package/src/nile-error-message/nile-error-message.ts +0 -18
  125. package/src/nile-error-notification/nile-error-notification.css.ts +1 -1
  126. package/src/nile-progress-bar/nile-progress-bar.css.ts +0 -1
  127. package/src/nile-select/nile-select.ts +1 -1
  128. package/src/nile-table/nile-table.ts +2 -2
  129. package/src/nile-tooltip/nile-tooltip.css.ts +44 -77
  130. package/src/nile-tooltip/nile-tooltip.ts +230 -268
  131. package/vscode-html-custom-data.json +95 -139
  132. package/dist/fixture-d5b55278.cjs.js.map +0 -1
  133. package/dist/nile-filter-chip/index.cjs.js +0 -2
  134. package/dist/nile-filter-chip/index.cjs.js.map +0 -1
  135. package/dist/nile-filter-chip/index.esm.js +0 -1
  136. package/dist/nile-filter-chip/nile-filter-chip.cjs.js +0 -2
  137. package/dist/nile-filter-chip/nile-filter-chip.cjs.js.map +0 -1
  138. package/dist/nile-filter-chip/nile-filter-chip.css.cjs.js +0 -2
  139. package/dist/nile-filter-chip/nile-filter-chip.css.cjs.js.map +0 -1
  140. package/dist/nile-filter-chip/nile-filter-chip.css.esm.js +0 -98
  141. package/dist/nile-filter-chip/nile-filter-chip.esm.js +0 -34
  142. package/dist/nile-filter-chip/nile-filter-chip.test.cjs.js +0 -2
  143. package/dist/nile-filter-chip/nile-filter-chip.test.cjs.js.map +0 -1
  144. package/dist/nile-filter-chip/nile-filter-chip.test.esm.js +0 -20
  145. package/dist/nile-tooltip/nile-tooltip-utils.cjs.js +0 -2
  146. package/dist/nile-tooltip/nile-tooltip-utils.cjs.js.map +0 -1
  147. package/dist/nile-tooltip/nile-tooltip-utils.esm.js +0 -1
  148. package/dist/nile-tooltip/nile-tooltip.test.cjs.js +0 -2
  149. package/dist/nile-tooltip/nile-tooltip.test.cjs.js.map +0 -1
  150. package/dist/nile-tooltip/nile-tooltip.test.esm.js +0 -47
  151. package/dist/src/nile-filter-chip/index.d.ts +0 -1
  152. package/dist/src/nile-filter-chip/index.js +0 -2
  153. package/dist/src/nile-filter-chip/index.js.map +0 -1
  154. package/dist/src/nile-filter-chip/nile-filter-chip.css.d.ts +0 -12
  155. package/dist/src/nile-filter-chip/nile-filter-chip.css.js +0 -110
  156. package/dist/src/nile-filter-chip/nile-filter-chip.css.js.map +0 -1
  157. package/dist/src/nile-filter-chip/nile-filter-chip.d.ts +0 -35
  158. package/dist/src/nile-filter-chip/nile-filter-chip.js +0 -128
  159. package/dist/src/nile-filter-chip/nile-filter-chip.js.map +0 -1
  160. package/dist/src/nile-filter-chip/nile-filter-chip.test.d.ts +0 -1
  161. package/dist/src/nile-filter-chip/nile-filter-chip.test.js +0 -80
  162. package/dist/src/nile-filter-chip/nile-filter-chip.test.js.map +0 -1
  163. package/dist/src/nile-tooltip/nile-tooltip-utils.d.ts +0 -18
  164. package/dist/src/nile-tooltip/nile-tooltip-utils.js +0 -216
  165. package/dist/src/nile-tooltip/nile-tooltip-utils.js.map +0 -1
  166. package/dist/src/nile-tooltip/nile-tooltip.test.d.ts +0 -1
  167. package/dist/src/nile-tooltip/nile-tooltip.test.js +0 -148
  168. package/dist/src/nile-tooltip/nile-tooltip.test.js.map +0 -1
  169. package/src/nile-filter-chip/index.ts +0 -1
  170. package/src/nile-filter-chip/nile-filter-chip.css.ts +0 -115
  171. package/src/nile-filter-chip/nile-filter-chip.test.ts +0 -92
  172. package/src/nile-filter-chip/nile-filter-chip.ts +0 -125
  173. package/src/nile-tooltip/nile-tooltip-utils.ts +0 -271
  174. package/src/nile-tooltip/nile-tooltip.test.ts +0 -168
@@ -1,28 +1,61 @@
1
-
2
1
  /**
3
2
  * Copyright Aquera Inc 2023
4
3
  *
5
4
  * This source code is licensed under the BSD-3-Clause license found in the
6
5
  * LICENSE file in the root directory of this source tree.
7
6
  */
8
- import { LitElement, html, css, CSSResultArray } from 'lit';
9
- import { customElement, property, query } from 'lit/decorators.js';
10
- import { classMap } from 'lit/directives/class-map.js';
7
+
8
+ import { LitElement, CSSResultArray, TemplateResult } from 'lit';
11
9
  import { styles } from './nile-tooltip.css';
10
+ import '../nile-popup/nile-popup';
11
+ import { animateTo, parseDuration, stopAnimations } from '../internal/animate';
12
+ import { classMap } from 'lit/directives/class-map.js';
13
+ import { customElement, property, query } from 'lit/decorators.js';
14
+ import {
15
+ getAnimation,
16
+ setDefaultAnimation,
17
+ } from '../utilities/animation-registry';
18
+ import { html } from 'lit';
19
+ // import { LocalizeController } from '../utilities/localize';
20
+ import { waitForEvent } from '../internal/event';
21
+ import { watch } from '../internal/watch';
12
22
  import NileElement from '../internal/nile-element';
13
- import { isInViewport, getValidTooltipPosition, getCaretPosition } from './nile-tooltip-utils';
14
-
23
+ import type { CSSResultGroup } from 'lit';
24
+ import type NilePopup from '../nile-popup/nile-popup';
15
25
  /**
16
- * Nile tooltip component.
26
+ * Nile icon component.
17
27
  *
18
28
  * @tag nile-tooltip
19
29
  *
20
30
  */
21
31
  @customElement('nile-tooltip')
22
32
  export class NileTooltip extends NileElement {
23
- @property({ type: String }) content = '';
24
- @property({ type: String })
25
- placement:
33
+ /**
34
+ * The styles for Tooltip
35
+ * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]`
36
+ */
37
+ public static get styles(): CSSResultArray {
38
+ return [styles];
39
+ }
40
+
41
+ private hoverTimeout: number;
42
+ // private readonly localize = new LocalizeController(this);
43
+
44
+ @query('slot:not([name])') defaultSlot: HTMLSlotElement;
45
+ @query('.tooltip__body') body: HTMLElement;
46
+ @query('nile-popup') popup: NilePopup;
47
+
48
+ /** The tooltip's content. If you need to display HTML, use the `content` slot instead. */
49
+ @property({ type: String, reflect: true }) content = '';
50
+
51
+ /** Size Property to decide the tool tip size */
52
+ @property({ reflect: true }) size: 'small' | 'large' = 'small';
53
+
54
+ /**
55
+ * The preferred placement of the tooltip. Note that the actual placement may vary as needed to keep the tooltip
56
+ * inside of the viewport.
57
+ */
58
+ @property() placement:
26
59
  | 'top'
27
60
  | 'top-start'
28
61
  | 'top-end'
@@ -35,326 +68,255 @@ export class NileTooltip extends NileElement {
35
68
  | 'left'
36
69
  | 'left-start'
37
70
  | 'left-end' = 'top';
71
+
72
+ /** Disables the tooltip so it won't show when triggered. */
38
73
  @property({ type: Boolean, reflect: true }) disabled = false;
74
+
75
+ /** The distance in pixels from which to offset the tooltip away from its target. */
76
+ @property({ type: Number }) distance = 8;
77
+
78
+ /** Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods. */
39
79
  @property({ type: Boolean, reflect: true }) open = false;
80
+
81
+ /** The distance in pixels from which to offset the tooltip along its target. */
82
+ @property({ type: Number }) skidding = 0;
83
+
40
84
  /**
41
85
  * Controls how the tooltip is activated. Possible options include `click`, `hover`, `focus`, and `manual`. Multiple
42
86
  * options can be passed by separating them with a space. When manual is used, the tooltip must be activated
43
87
  * programmatically.
44
88
  */
45
89
  @property() trigger = 'hover focus';
46
- @property({ type: Number }) distance = 8;
47
- private readonly SHIFT_OFFSET = 16;
48
- /** The distance in pixels from which to offset the tooltip along its target. */
49
- @property({ type: Number }) skidding = 0;
50
- @property({ type: Boolean, reflect: true }) hoist = false;
51
-
52
- @query('.tooltip') tooltip!: HTMLElement;
53
- @query('.trigger-container') triggerContainer!: HTMLElement;
54
- @query('.tooltip-caret') caret!: HTMLElement;
55
- @query('slot[name="content"]') tooltipSlot!: HTMLSlotElement;
56
90
 
57
- private hasTooltipSlot = false;
58
- private hoverTimeout: number = 0;
59
- private caretSize = 6;
60
- private originalPlacement: string = this.placement;
61
-
62
- public static get styles(): CSSResultArray {
63
- return [styles];
64
- }
91
+ /**
92
+ * Enable this option to prevent the tooltip from being clipped when the component is placed inside a container with
93
+ * `overflow: auto|hidden|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all,
94
+ * scenarios.
95
+ */
96
+ @property({ type: Boolean }) hoist = false;
65
97
 
66
98
  connectedCallback() {
67
99
  super.connectedCallback();
68
- this.originalPlacement = this.placement;
69
- window.addEventListener('resize', this.updateTooltipPosition);
70
- window.addEventListener('scroll', this.updateTooltipPosition, true);
100
+ this.handleBlur = this.handleBlur.bind(this);
101
+ this.handleClick = this.handleClick.bind(this);
102
+ this.handleFocus = this.handleFocus.bind(this);
103
+ this.handleKeyDown = this.handleKeyDown.bind(this);
104
+ this.handleMouseOver = this.handleMouseOver.bind(this);
105
+ this.handleMouseOut = this.handleMouseOut.bind(this);
106
+
107
+ this.updateComplete.then(() => {
108
+ this.addEventListener('blur', this.handleBlur, true);
109
+ this.addEventListener('focus', this.handleFocus, true);
110
+ this.addEventListener('click', this.handleClick);
111
+ this.addEventListener('keydown', this.handleKeyDown);
112
+ this.addEventListener('mouseover', this.handleMouseOver);
113
+ this.addEventListener('mouseout', this.handleMouseOut);
114
+ });
71
115
  }
72
116
 
73
- updated(changedProps: Map<string, unknown>) {
74
- super.updated?.(changedProps);
75
-
76
- const validPlacements = [
77
- 'top', 'top-start', 'top-end',
78
- 'right', 'right-start', 'right-end',
79
- 'bottom', 'bottom-start', 'bottom-end',
80
- 'left', 'left-start', 'left-end'
81
- ];
82
-
83
- if (!validPlacements.includes(this.placement)) {
84
- console.warn(`[nile-tooltip] Invalid placement "${this.placement}", defaulting to "bottom".`);
85
- this.placement = 'top';
86
- }
117
+ firstUpdated() {
118
+ this.body.hidden = !this.open;
87
119
 
88
- if (!validPlacements.includes(this.originalPlacement)) {
89
- this.originalPlacement = 'top';
90
- }
91
-
92
- if (changedProps.has('open') && this.open) {
93
- this.updateComplete.then(() => {
94
- requestAnimationFrame(() => {
95
- this.updateTooltipPosition();
96
- });
97
- });
120
+ // If the tooltip is visible on init, update its position
121
+ if (this.open) {
122
+ this.popup.active = true;
123
+ this.popup.reposition();
98
124
  }
99
125
  }
100
126
 
101
127
  disconnectedCallback() {
102
128
  super.disconnectedCallback();
103
- window.removeEventListener('resize', this.updateTooltipPosition);
104
- window.removeEventListener('scroll', this.updateTooltipPosition, true);
129
+ this.removeEventListener('blur', this.handleBlur, true);
130
+ this.removeEventListener('focus', this.handleFocus, true);
131
+ this.removeEventListener('click', this.handleClick);
132
+ this.removeEventListener('keydown', this.handleKeyDown);
133
+ this.removeEventListener('mouseover', this.handleMouseOver);
134
+ this.removeEventListener('mouseout', this.handleMouseOut);
105
135
  }
106
136
 
107
- private handleTooltipSlotChange() {
108
- const nodes = this.tooltipSlot.assignedNodes({ flatten: true });
109
- this.hasTooltipSlot = nodes.length > 0;
110
- this.requestUpdate();
137
+ private handleBlur() {
138
+ if (this.hasTrigger('focus')) {
139
+ this.hide();
140
+ }
111
141
  }
112
142
 
113
- private updateTooltipPosition = () => {
114
- if (!isInViewport(this.triggerContainer)) {
115
- this.open = false;
116
- return;
143
+ private handleClick() {
144
+ if (this.hasTrigger('click')) {
145
+ if (this.open) {
146
+ this.hide();
147
+ } else {
148
+ this.show();
149
+ }
117
150
  }
151
+ }
118
152
 
119
- const triggerRect = this.triggerContainer.getBoundingClientRect();
120
- const tooltipRect = this.tooltip.getBoundingClientRect();
121
- const viewportWidth = window.innerWidth;
122
- const viewportHeight = window.innerHeight;
123
-
124
-
125
- let { top, left, placement } = getValidTooltipPosition(
126
- triggerRect,
127
- tooltipRect,
128
- this.originalPlacement,
129
- this.distance,
130
- this.skidding,
131
- this.caretSize,
132
- viewportWidth,
133
- viewportHeight
134
- );
135
-
136
- // FallBack Positions
137
-
138
- // Bottom
139
- if (this.originalPlacement.startsWith('bottom')) {
140
- const availableSpaceBelow = viewportHeight - triggerRect.bottom;
141
- if (availableSpaceBelow < tooltipRect.height + this.distance) {
142
- let newPlacement: typeof this.originalPlacement = 'top';
143
- if (this.originalPlacement === 'bottom-start') {
144
- newPlacement = 'top';
145
- } else if (this.originalPlacement === 'bottom-end') {
146
- newPlacement = 'top';
147
- }
148
-
149
- const newPosition = getValidTooltipPosition(
150
- triggerRect,
151
- tooltipRect,
152
- newPlacement,
153
- this.distance,
154
- this.skidding,
155
- this.caretSize,
156
- viewportWidth,
157
- viewportHeight
158
- );
159
- top = newPosition.top;
160
- left = newPosition.left;
161
- placement = newPosition.placement;
162
- }
153
+ private handleFocus() {
154
+ if (this.hasTrigger('focus')) {
155
+ this.show();
163
156
  }
164
- // Top
165
- if (this.originalPlacement.startsWith('top')) {
166
- const availableSpaceAbove = triggerRect.top;
167
- const availableSpaceBelow = viewportHeight - triggerRect.bottom;
168
- if (availableSpaceAbove < tooltipRect.height + this.distance && availableSpaceBelow >= tooltipRect.height + this.distance) {
169
- let newPlacement: typeof this.originalPlacement = 'bottom';
170
- if (this.originalPlacement === 'top-start') {
171
- newPlacement = 'bottom-start';
172
- } else if (this.originalPlacement === 'top-end') {
173
- newPlacement = 'bottom-end';
174
- }
175
-
176
- const newPosition = getValidTooltipPosition(
177
- triggerRect,
178
- tooltipRect,
179
- newPlacement,
180
- this.distance,
181
- this.skidding,
182
- this.caretSize,
183
- viewportWidth,
184
- viewportHeight
185
- );
186
- top = newPosition.top;
187
- left = newPosition.left;
188
- placement = newPosition.placement;
157
+ }
158
+
159
+ private handleKeyDown(event: KeyboardEvent) {
160
+ // Pressing escape when the target element has focus should dismiss the tooltip
161
+ if (this.open && event.key === 'Escape') {
162
+ event.stopPropagation();
163
+ this.hide();
189
164
  }
190
165
  }
191
166
 
192
- // Left
193
- if (this.originalPlacement.startsWith('left')) {
194
- const availableSpaceLeft = triggerRect.left;
195
- const availableSpaceRight = viewportWidth - triggerRect.right;
196
- if (availableSpaceLeft < tooltipRect.width + this.distance && availableSpaceRight >= tooltipRect.width + this.distance) {
197
- let newPlacement: typeof this.originalPlacement = 'right';
198
- if (this.originalPlacement === 'left-start') {
199
- newPlacement = 'right-start';
200
- } else if (this.originalPlacement === 'left-end') {
201
- newPlacement = 'right-end';
202
- }
203
-
204
- const newPosition = getValidTooltipPosition(
205
- triggerRect,
206
- tooltipRect,
207
- newPlacement,
208
- this.distance,
209
- this.skidding,
210
- this.caretSize,
211
- viewportWidth,
212
- viewportHeight
167
+ private handleMouseOver() {
168
+ if (this.hasTrigger('hover')) {
169
+ const delay = parseDuration(
170
+ getComputedStyle(this).getPropertyValue('--show-delay')
213
171
  );
214
- top = newPosition.top;
215
- left = newPosition.left;
216
- placement = newPosition.placement;
172
+ clearTimeout(this.hoverTimeout);
173
+ this.hoverTimeout = window.setTimeout(() => this.show(), delay);
217
174
  }
218
175
  }
219
176
 
220
- // Right
221
- if (this.originalPlacement.startsWith('right')) {
222
- const availableSpaceRight = viewportWidth - triggerRect.right;
223
- const availableSpaceLeft = triggerRect.left;
224
- if (availableSpaceRight < tooltipRect.width + this.distance && availableSpaceLeft >= tooltipRect.width + this.distance) {
225
- let newPlacement: typeof this.originalPlacement = 'left';
226
- if (this.originalPlacement === 'right-start') {
227
- newPlacement = 'left-start';
228
- } else if (this.originalPlacement === 'right-end') {
229
- newPlacement = 'left-end';
230
- }
231
-
232
- const newPosition = getValidTooltipPosition(
233
- triggerRect,
234
- tooltipRect,
235
- newPlacement,
236
- this.distance,
237
- this.skidding,
238
- this.caretSize,
239
- viewportWidth,
240
- viewportHeight
177
+ private handleMouseOut() {
178
+ if (this.hasTrigger('hover')) {
179
+ const delay = parseDuration(
180
+ getComputedStyle(this).getPropertyValue('--hide-delay')
241
181
  );
242
- top = newPosition.top;
243
- left = newPosition.left;
244
- placement = newPosition.placement;
182
+ clearTimeout(this.hoverTimeout);
183
+ this.hoverTimeout = window.setTimeout(() => this.hide(), delay);
245
184
  }
246
185
  }
247
186
 
248
- this.setAttribute('placement', placement);
249
- this.tooltip.style.top = `${top}px`;
250
- this.tooltip.style.left = `${left}px`;
251
-
252
- const { caretLeft, caretTop } = getCaretPosition({
253
- placement,
254
- tooltipRect,
255
- triggerRect,
256
- caretSize: this.caretSize,
257
- left,
258
- top
259
- });
187
+ private hasTrigger(triggerType: string) {
188
+ const triggers = this.trigger.split(' ');
189
+ return triggers.includes(triggerType);
190
+ }
260
191
 
261
- this.caret.style.left = `${caretLeft}px`;
262
- this.caret.style.top = `${caretTop}px`;
263
- };
192
+ @watch('open', { waitUntilFirstUpdate: true })
193
+ async handleOpenChange() {
194
+ if (this.open) {
195
+ if (this.disabled) {
196
+ return;
197
+ }
264
198
 
265
- private showTooltip = () => {
266
- const trimmedContent = this.content.trim();
267
- if (!trimmedContent && !this.hasTooltipSlot) {
268
- return;
269
- }
270
- if (!this.disabled && isInViewport(this.triggerContainer)) {
199
+ // Show
271
200
  this.emit('nile-show');
272
- this.open = true;
273
- this.updateComplete.then(() => {
274
- requestAnimationFrame(() => {
275
- this.updateTooltipPosition();
276
- this.emit('nile-after-show');
277
- });
201
+
202
+ await stopAnimations(this.body);
203
+ this.body.hidden = false;
204
+ this.popup.active = true;
205
+ const { keyframes, options } = getAnimation(this, 'tooltip.show', {
206
+ dir: '',
278
207
  });
208
+ await animateTo(this.popup.popup, keyframes, options);
209
+
210
+ this.emit('nile-after-show');
279
211
  } else {
280
- this.open = false;
281
- }
282
- };
212
+ // Hide
213
+ this.emit('nile-hide');
283
214
 
284
- private hideTooltip = () => {
285
- this.emit('nile-hide');
286
- this.open = false;
287
- setTimeout(() => {
288
- this.emit('nile-after-hide');
289
- }, 200);
290
- };
215
+ await stopAnimations(this.body);
216
+ const { keyframes, options } = getAnimation(this, 'tooltip.hide', {
217
+ dir: '',
218
+ });
219
+ await animateTo(this.popup.popup, keyframes, options);
220
+ this.popup.active = false;
221
+ this.body.hidden = true;
291
222
 
292
- private handleMouseOver = () => {
293
- if (this.trigger.includes('hover')) {
294
- clearTimeout(this.hoverTimeout);
295
- this.hoverTimeout = window.setTimeout(() => this.showTooltip(), 300);
223
+ this.emit('nile-after-hide');
296
224
  }
297
- };
225
+ }
298
226
 
299
- private handleMouseOut = () => {
300
- if (this.trigger.includes('hover')) {
301
- clearTimeout(this.hoverTimeout);
302
- this.hoverTimeout = window.setTimeout(() => this.hideTooltip(), 150);
227
+ @watch(['content', 'distance', 'hoist', 'placement', 'skidding'])
228
+ async handleOptionsChange() {
229
+ if (this.hasUpdated) {
230
+ await this.updateComplete;
231
+ this.popup.reposition();
303
232
  }
304
- };
233
+ }
305
234
 
306
- private handleClick = () => {
307
- if (this.trigger.includes('click')) {
308
- if (!this.open && isInViewport(this.triggerContainer)) {
309
- this.showTooltip();
310
- } else {
311
- this.hideTooltip();
312
- }
235
+ @watch('disabled')
236
+ handleDisabledChange() {
237
+ if (this.disabled && this.open) {
238
+ this.hide();
313
239
  }
314
- };
240
+ }
315
241
 
316
- private handleFocus = () => {
317
- if (this.trigger.includes('focus')) {
318
- this.showTooltip();
242
+ /** Shows the tooltip. */
243
+ async show() {
244
+ if (this.open || !this.content?.trim().length) {
245
+ return undefined;
319
246
  }
320
- };
321
-
322
247
 
323
- private handleBlur = () => {
324
- if (this.trigger.includes('focus')) {
325
- this.hideTooltip();
248
+ this.open = true;
249
+ return waitForEvent(this, 'nile-after-show');
250
+ }
251
+
252
+ /** Hides the tooltip */
253
+ async hide() {
254
+ if (!this.open) {
255
+ return undefined;
326
256
  }
327
- };
257
+
258
+ this.open = false;
259
+ return waitForEvent(this, 'nile-after-hide');
260
+ }
328
261
 
329
262
  render() {
330
263
  return html`
331
- <div
332
- class="tooltip"
333
- id="tooltip"
264
+ <nile-popup
265
+ part="base"
266
+ exportparts="
267
+ popup:base__popup,
268
+ arrow:base__arrow
269
+ "
270
+ class=${classMap({
271
+ tooltip: true,
272
+ 'tooltip--open': this.open,
273
+ })}
274
+ placement=${this.placement}
275
+ distance=${this.distance}
276
+ skidding=${this.skidding}
277
+ strategy=${this.hoist ? 'fixed' : 'absolute'}
278
+ flip
279
+ shift
280
+ arrow
334
281
  >
335
- <div class="tooltip-content" part="content">
336
- <slot name="content" @slotchange=${this.handleTooltipSlotChange}></slot>
337
- ${!this.hasTooltipSlot ? html`${this.content}` : null}
338
- </div>
339
- <div class="tooltip-caret" style="--caret-size: ${this.caretSize}px;"></div>
340
- </div>
341
-
342
- <div
343
- class="trigger-container"
344
- tabindex="0"
345
- @mouseover=${this.handleMouseOver}
346
- @mouseout=${this.handleMouseOut}
347
- @click=${this.handleClick}
348
- @focusin=${this.handleFocus}
349
- @focusout=${this.handleBlur}
350
- aria-describedby="tooltip"
351
- >
352
- <slot></slot>
353
- </div>
282
+ <slot slot="anchor" aria-describedby="tooltip"></slot>
283
+
284
+ <slot
285
+ name="content"
286
+ part="body"
287
+ id="tooltip"
288
+ class=${classMap({
289
+ tooltip__body: true,
290
+ 'tooltip__body--large': this.size === 'large',
291
+ })}
292
+ role="tooltip"
293
+ aria-live=${this.open ? 'polite' : 'off'}
294
+ >
295
+ ${this.content}
296
+ </slot>
297
+ </nile-popup>
354
298
  `;
355
299
  }
356
300
  }
357
301
 
302
+ setDefaultAnimation('tooltip.show', {
303
+ keyframes: [
304
+ { opacity: 0, scale: 0.8 },
305
+ { opacity: 1, scale: 1 },
306
+ ],
307
+ options: { duration: 150, easing: 'ease' },
308
+ });
309
+
310
+ setDefaultAnimation('tooltip.hide', {
311
+ keyframes: [
312
+ { opacity: 1, scale: 1 },
313
+ { opacity: 0, scale: 0.8 },
314
+ ],
315
+ options: { duration: 150, easing: 'ease' },
316
+ });
317
+
318
+ export default NileTooltip;
319
+
358
320
  declare global {
359
321
  interface HTMLElementTagNameMap {
360
322
  'nile-tooltip': NileTooltip;