UNPKG

9.05 kBJavaScriptView Raw
1import {
2 tooltip_styles_default
3} from "./chunk.Z2LMV65O.js";
4import {
5 D,
6 N,
7 T,
8 b,
9 m,
10 z
11} from "./chunk.4D66J43X.js";
12import {
13 animateTo,
14 parseDuration,
15 stopAnimations
16} from "./chunk.63W3F5G5.js";
17import {
18 getAnimation,
19 setDefaultAnimation
20} from "./chunk.EFXMZY2Q.js";
21import {
22 LocalizeController
23} from "./chunk.6WMYSCDC.js";
24import {
25 o
26} from "./chunk.IAELDRGJ.js";
27import {
28 watch
29} from "./chunk.W6MGCO4G.js";
30import {
31 emit,
32 waitForEvent
33} from "./chunk.UY5AQKHP.js";
34import {
35 e,
36 i,
37 n
38} from "./chunk.VKNZYXSO.js";
39import {
40 $,
41 s
42} from "./chunk.WWAD5WF4.js";
43import {
44 __decorateClass
45} from "./chunk.K2NRSETB.js";
46
47// src/components/tooltip/tooltip.ts
48var SlTooltip = class extends s {
49 constructor() {
50 super(...arguments);
51 this.localize = new LocalizeController(this);
52 this.content = "";
53 this.placement = "top";
54 this.disabled = false;
55 this.distance = 10;
56 this.open = false;
57 this.skidding = 0;
58 this.trigger = "hover focus";
59 this.hoist = false;
60 }
61 connectedCallback() {
62 super.connectedCallback();
63 this.handleBlur = this.handleBlur.bind(this);
64 this.handleClick = this.handleClick.bind(this);
65 this.handleFocus = this.handleFocus.bind(this);
66 this.handleKeyDown = this.handleKeyDown.bind(this);
67 this.handleMouseOver = this.handleMouseOver.bind(this);
68 this.handleMouseOut = this.handleMouseOut.bind(this);
69 this.updateComplete.then(() => {
70 this.addEventListener("blur", this.handleBlur, true);
71 this.addEventListener("focus", this.handleFocus, true);
72 this.addEventListener("click", this.handleClick);
73 this.addEventListener("keydown", this.handleKeyDown);
74 this.addEventListener("mouseover", this.handleMouseOver);
75 this.addEventListener("mouseout", this.handleMouseOut);
76 this.target = this.getTarget();
77 });
78 }
79 async firstUpdated() {
80 this.tooltip.hidden = !this.open;
81 if (this.open) {
82 await this.updateComplete;
83 this.updatePositioner();
84 }
85 }
86 disconnectedCallback() {
87 super.disconnectedCallback();
88 this.removeEventListener("blur", this.handleBlur, true);
89 this.removeEventListener("focus", this.handleFocus, true);
90 this.removeEventListener("click", this.handleClick);
91 this.removeEventListener("keydown", this.handleKeyDown);
92 this.removeEventListener("mouseover", this.handleMouseOver);
93 this.removeEventListener("mouseout", this.handleMouseOut);
94 this.stopPositioner();
95 }
96 async show() {
97 if (this.open) {
98 return void 0;
99 }
100 this.open = true;
101 return waitForEvent(this, "sl-after-show");
102 }
103 async hide() {
104 if (!this.open) {
105 return void 0;
106 }
107 this.open = false;
108 return waitForEvent(this, "sl-after-hide");
109 }
110 getTarget() {
111 const target = [...this.children].find((el) => el.tagName.toLowerCase() !== "style" && el.getAttribute("slot") !== "content");
112 if (!target) {
113 throw new Error("Invalid tooltip target: no child element was found.");
114 }
115 return target;
116 }
117 handleBlur() {
118 if (this.hasTrigger("focus")) {
119 this.hide();
120 }
121 }
122 handleClick() {
123 if (this.hasTrigger("click")) {
124 if (this.open) {
125 this.hide();
126 } else {
127 this.show();
128 }
129 }
130 }
131 handleFocus() {
132 if (this.hasTrigger("focus")) {
133 this.show();
134 }
135 }
136 handleKeyDown(event) {
137 if (this.open && event.key === "Escape") {
138 event.stopPropagation();
139 this.hide();
140 }
141 }
142 handleMouseOver() {
143 if (this.hasTrigger("hover")) {
144 const delay = parseDuration(getComputedStyle(this).getPropertyValue("--show-delay"));
145 clearTimeout(this.hoverTimeout);
146 this.hoverTimeout = window.setTimeout(() => void this.show(), delay);
147 }
148 }
149 handleMouseOut() {
150 if (this.hasTrigger("hover")) {
151 const delay = parseDuration(getComputedStyle(this).getPropertyValue("--hide-delay"));
152 clearTimeout(this.hoverTimeout);
153 this.hoverTimeout = window.setTimeout(() => void this.hide(), delay);
154 }
155 }
156 async handleOpenChange() {
157 if (this.open) {
158 if (this.disabled) {
159 return;
160 }
161 emit(this, "sl-show");
162 await stopAnimations(this.tooltip);
163 this.startPositioner();
164 this.tooltip.hidden = false;
165 const { keyframes, options } = getAnimation(this, "tooltip.show", { dir: this.localize.dir() });
166 await animateTo(this.tooltip, keyframes, options);
167 emit(this, "sl-after-show");
168 } else {
169 emit(this, "sl-hide");
170 await stopAnimations(this.tooltip);
171 const { keyframes, options } = getAnimation(this, "tooltip.hide", { dir: this.localize.dir() });
172 await animateTo(this.tooltip, keyframes, options);
173 this.tooltip.hidden = true;
174 this.stopPositioner();
175 emit(this, "sl-after-hide");
176 }
177 }
178 handleOptionsChange() {
179 this.updatePositioner();
180 }
181 handleDisabledChange() {
182 if (this.disabled && this.open) {
183 this.hide();
184 }
185 }
186 hasTrigger(triggerType) {
187 const triggers = this.trigger.split(" ");
188 return triggers.includes(triggerType);
189 }
190 startPositioner() {
191 this.stopPositioner();
192 this.updatePositioner();
193 this.positionerCleanup = N(this.target, this.positioner, this.updatePositioner.bind(this));
194 }
195 updatePositioner() {
196 if (!this.open || !this.target || !this.positioner) {
197 return;
198 }
199 z(this.target, this.positioner, {
200 placement: this.placement,
201 middleware: [
202 T({ mainAxis: this.distance, crossAxis: this.skidding }),
203 b(),
204 D(),
205 m({
206 element: this.arrow,
207 padding: 10
208 })
209 ],
210 strategy: this.hoist ? "fixed" : "absolute"
211 }).then(({ x, y, middlewareData, placement }) => {
212 const arrowX = middlewareData.arrow.x;
213 const arrowY = middlewareData.arrow.y;
214 const staticSide = { top: "bottom", right: "left", bottom: "top", left: "right" }[placement.split("-")[0]];
215 this.positioner.setAttribute("data-placement", placement);
216 Object.assign(this.positioner.style, {
217 position: this.hoist ? "fixed" : "absolute",
218 left: `${x}px`,
219 top: `${y}px`
220 });
221 Object.assign(this.arrow.style, {
222 left: typeof arrowX === "number" ? `${arrowX}px` : "",
223 top: typeof arrowY === "number" ? `${arrowY}px` : "",
224 right: "",
225 bottom: "",
226 [staticSide]: "calc(var(--sl-tooltip-arrow-size) * -1)"
227 });
228 });
229 }
230 stopPositioner() {
231 if (this.positionerCleanup) {
232 this.positionerCleanup();
233 this.positionerCleanup = void 0;
234 this.positioner.removeAttribute("data-placement");
235 }
236 }
237 render() {
238 return $`
239 <div class="tooltip-target" aria-describedby="tooltip">
240 <slot></slot>
241 </div>
242
243 <div class="tooltip-positioner">
244 <div
245 part="base"
246 id="tooltip"
247 class=${o({
248 tooltip: true,
249 "tooltip--open": this.open
250 })}
251 role="tooltip"
252 aria-hidden=${this.open ? "false" : "true"}
253 >
254 <div class="tooltip__arrow"></div>
255 <div class="tooltip__content" aria-live=${this.open ? "polite" : "off"}>
256 <slot name="content"> ${this.content} </slot>
257 </div>
258 </div>
259 </div>
260 `;
261 }
262};
263SlTooltip.styles = tooltip_styles_default;
264__decorateClass([
265 i(".tooltip-positioner")
266], SlTooltip.prototype, "positioner", 2);
267__decorateClass([
268 i(".tooltip")
269], SlTooltip.prototype, "tooltip", 2);
270__decorateClass([
271 i(".tooltip__arrow")
272], SlTooltip.prototype, "arrow", 2);
273__decorateClass([
274 e()
275], SlTooltip.prototype, "content", 2);
276__decorateClass([
277 e()
278], SlTooltip.prototype, "placement", 2);
279__decorateClass([
280 e({ type: Boolean, reflect: true })
281], SlTooltip.prototype, "disabled", 2);
282__decorateClass([
283 e({ type: Number })
284], SlTooltip.prototype, "distance", 2);
285__decorateClass([
286 e({ type: Boolean, reflect: true })
287], SlTooltip.prototype, "open", 2);
288__decorateClass([
289 e({ type: Number })
290], SlTooltip.prototype, "skidding", 2);
291__decorateClass([
292 e()
293], SlTooltip.prototype, "trigger", 2);
294__decorateClass([
295 e({ type: Boolean })
296], SlTooltip.prototype, "hoist", 2);
297__decorateClass([
298 watch("open", { waitUntilFirstUpdate: true })
299], SlTooltip.prototype, "handleOpenChange", 1);
300__decorateClass([
301 watch("content"),
302 watch("distance"),
303 watch("hoist"),
304 watch("placement"),
305 watch("skidding")
306], SlTooltip.prototype, "handleOptionsChange", 1);
307__decorateClass([
308 watch("disabled")
309], SlTooltip.prototype, "handleDisabledChange", 1);
310SlTooltip = __decorateClass([
311 n("sl-tooltip")
312], SlTooltip);
313setDefaultAnimation("tooltip.show", {
314 keyframes: [
315 { opacity: 0, transform: "scale(0.8)" },
316 { opacity: 1, transform: "scale(1)" }
317 ],
318 options: { duration: 150, easing: "ease" }
319});
320setDefaultAnimation("tooltip.hide", {
321 keyframes: [
322 { opacity: 1, transform: "scale(1)" },
323 { opacity: 0, transform: "scale(0.8)" }
324 ],
325 options: { duration: 150, easing: "ease" }
326});
327
328export {
329 SlTooltip
330};