| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  | import * as colors from './00colors.js'; | 
					
						
							|  |  |  | import * as plugins from './00plugins.js'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import { demoFunc } from './dees-speechbubble.demo.js'; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  | import { | 
					
						
							|  |  |  |   customElement, | 
					
						
							|  |  |  |   html, | 
					
						
							|  |  |  |   DeesElement, | 
					
						
							|  |  |  |   property, | 
					
						
							| 
									
										
										
										
											2023-08-07 20:02:18 +02:00
										 |  |  |   type TemplateResult, | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |   cssManager, | 
					
						
							|  |  |  |   css, | 
					
						
							| 
									
										
										
										
											2023-08-07 20:02:18 +02:00
										 |  |  |   type CSSResult, | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |   unsafeCSS, | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   domtools, | 
					
						
							|  |  |  |   directives, | 
					
						
							|  |  |  |   unsafeHTML, | 
					
						
							| 
									
										
										
										
											2023-08-07 19:13:29 +02:00
										 |  |  | } from '@design.estate/dees-element'; | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  | import { DeesWindowLayer } from './dees-windowlayer.js'; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | declare global { | 
					
						
							|  |  |  |   interface HTMLElementTagNameMap { | 
					
						
							|  |  |  |     'dees-speechbubble': DeesSpeechbubble; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @customElement('dees-speechbubble') | 
					
						
							|  |  |  | export class DeesSpeechbubble extends DeesElement { | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   public static demo = demoFunc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // STATIC
 | 
					
						
							|  |  |  |   public static async createAndShow(refElement: HTMLElement, textArg: string) { | 
					
						
							|  |  |  |     const windowLayer = await DeesWindowLayer.createAndShow({ | 
					
						
							|  |  |  |       blur: false, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const speechbubble = document.createElement('dees-speechbubble'); | 
					
						
							|  |  |  |     speechbubble.windowLayer = windowLayer; | 
					
						
							|  |  |  |     speechbubble.reffedElement = refElement; | 
					
						
							|  |  |  |     speechbubble.text = textArg; | 
					
						
							|  |  |  |     speechbubble.manifested = true; | 
					
						
							|  |  |  |     windowLayer.appendChild(speechbubble); | 
					
						
							|  |  |  |     windowLayer.style.pointerEvents = 'none'; | 
					
						
							|  |  |  |     (windowLayer.shadowRoot.querySelector('.windowOverlay') as HTMLElement).style.pointerEvents = 'none'; | 
					
						
							|  |  |  |     return speechbubble; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   // INSTANCE
 | 
					
						
							|  |  |  |   @property({ | 
					
						
							|  |  |  |     type: Object, | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  |   reffedElement: HTMLElement; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ | 
					
						
							|  |  |  |     type: String, | 
					
						
							|  |  |  |     reflect: true, | 
					
						
							|  |  |  |   }) | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |   public text: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ | 
					
						
							|  |  |  |     type: Boolean, | 
					
						
							|  |  |  |   }) | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   public wave: boolean = false; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @property({ | 
					
						
							|  |  |  |     type: Boolean, | 
					
						
							|  |  |  |   }) | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   public manifested = false; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @property({ | 
					
						
							|  |  |  |     type: String, | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  |   public status: 'normal' | 'pending' | 'success' | 'error' = 'normal'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   public windowLayer: DeesWindowLayer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |   constructor() { | 
					
						
							|  |  |  |     super(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public static styles = [ | 
					
						
							|  |  |  |     cssManager.defaultStyles, | 
					
						
							|  |  |  |     css`
 | 
					
						
							|  |  |  |       :host { | 
					
						
							|  |  |  |         box-sizing: border-box; | 
					
						
							| 
									
										
										
										
											2022-05-20 19:43:16 +02:00
										 |  |  |         color: ${cssManager.bdTheme('#333', '#fff')}; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |         user-select: none; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 21:04:59 +02:00
										 |  |  |       .maincontainer { | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |         position: relative; | 
					
						
							| 
									
										
										
										
											2022-05-24 09:13:15 +02:00
										 |  |  |         will-change: transform; | 
					
						
							|  |  |  |         transition: transform 0.2s; | 
					
						
							|  |  |  |         transform: translateX(0px); | 
					
						
							| 
									
										
										
										
											2022-05-20 21:04:59 +02:00
										 |  |  |         transition: all 0.2s; | 
					
						
							|  |  |  |         margin-left: 0px; | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |         filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, 0.2)); | 
					
						
							|  |  |  |         pointer-events: none; | 
					
						
							|  |  |  |         opacity: 0; | 
					
						
							|  |  |  |         transition: all 0.2s; | 
					
						
							| 
									
										
										
										
											2022-05-20 21:04:59 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |       .arrow { | 
					
						
							|  |  |  |         position: absolute; | 
					
						
							|  |  |  |         transform: rotate(45deg); | 
					
						
							| 
									
										
										
										
											2022-05-20 19:43:16 +02:00
										 |  |  |         background: ${cssManager.bdTheme('#fff', '#333')}; | 
					
						
							| 
									
										
										
										
											2022-05-20 19:48:48 +02:00
										 |  |  |         height: 15px; | 
					
						
							|  |  |  |         width: 15px; | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |         left: 2px; | 
					
						
							|  |  |  |         top: 12px; | 
					
						
							|  |  |  |         border-radius: 3px; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 21:04:59 +02:00
										 |  |  |       .speechbubble { | 
					
						
							| 
									
										
										
										
											2022-05-20 19:43:16 +02:00
										 |  |  |         background: ${cssManager.bdTheme('#fff', '#333')}; | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |         padding: 0px 16px; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |         border-radius: 3px; | 
					
						
							|  |  |  |         position: absolute; | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |         min-width: 240px; | 
					
						
							| 
									
										
										
										
											2022-05-20 19:48:48 +02:00
										 |  |  |         font-size: 12px; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |         top: 0px; | 
					
						
							|  |  |  |         left: 8px; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .wave { | 
					
						
							|  |  |  |         animation-name: wave-animation; /* Refers to the name of your @keyframes element below */ | 
					
						
							|  |  |  |         animation-duration: 2.5s; /* Change to speed up or slow down */ | 
					
						
							|  |  |  |         animation-iteration-count: infinite; /* Never stop waving :) */ | 
					
						
							|  |  |  |         transform-origin: 70% 70%; /* Pivot around the bottom-left palm */ | 
					
						
							|  |  |  |         display: inline-block; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @keyframes wave-animation { | 
					
						
							|  |  |  |         0% { | 
					
						
							|  |  |  |           transform: rotate(0deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         10% { | 
					
						
							|  |  |  |           transform: rotate(14deg); | 
					
						
							|  |  |  |         } /* The following five values can be played with to make the waving more or less extreme */ | 
					
						
							|  |  |  |         20% { | 
					
						
							|  |  |  |           transform: rotate(-8deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         30% { | 
					
						
							|  |  |  |           transform: rotate(14deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         40% { | 
					
						
							|  |  |  |           transform: rotate(-4deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         50% { | 
					
						
							|  |  |  |           transform: rotate(10deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         60% { | 
					
						
							|  |  |  |           transform: rotate(0deg); | 
					
						
							|  |  |  |         } /* Reset for the last half to pause */ | 
					
						
							|  |  |  |         100% { | 
					
						
							|  |  |  |           transform: rotate(0deg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public render(): TemplateResult { | 
					
						
							|  |  |  |     return html`
 | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |       ${this.manifested | 
					
						
							|  |  |  |         ? html`
 | 
					
						
							|  |  |  |             <div class="maincontainer" @click=${this.handleClick}> | 
					
						
							|  |  |  |               <div class="arrow"></div> | 
					
						
							|  |  |  |               <div class="speechbubble"> | 
					
						
							|  |  |  |                 ${this.wave ? html`<span class="wave">👋</span>` : html``} | 
					
						
							|  |  |  |                 ${directives.resolve(this.getHtml())} | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         : html``} | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |     `;
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 19:51:20 +02:00
										 |  |  |   public async handleClick() { | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |     console.log('speechbubble got clicked.'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public async firstUpdated() { | 
					
						
							|  |  |  |     // lets make sure we have a ref
 | 
					
						
							|  |  |  |     if (!this.reffedElement) { | 
					
						
							|  |  |  |       this.reffedElement = this.previousElementSibling as HTMLElement; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |     if (this.manifested) { | 
					
						
							|  |  |  |       await this.updatePosition(); | 
					
						
							|  |  |  |       (this.shadowRoot.querySelector('.maincontainer') as HTMLElement).style.opacity = '1'; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       // lets make sure we instrument it
 | 
					
						
							|  |  |  |       let speechbubble: DeesSpeechbubble; | 
					
						
							|  |  |  |       this.reffedElement.addEventListener('mouseenter', async () => { | 
					
						
							|  |  |  |         speechbubble = await DeesSpeechbubble.createAndShow(this.reffedElement, this.text); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       this.reffedElement.addEventListener('mouseleave', () => { | 
					
						
							|  |  |  |         speechbubble.destroy(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   public async updatePosition() { | 
					
						
							|  |  |  |     const refElement = this.reffedElement; | 
					
						
							|  |  |  |     const boundingClientRect = refElement.getBoundingClientRect(); | 
					
						
							|  |  |  |     this.style.position = 'fixed'; | 
					
						
							|  |  |  |     this.style.top = `${boundingClientRect.top - 13}px`; | 
					
						
							|  |  |  |     this.style.left = `${boundingClientRect.left + refElement.clientWidth + 4}px`; | 
					
						
							|  |  |  |     if (boundingClientRect.right > 250) { | 
					
						
							|  |  |  |       this.style.width = `250px`; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |   public async getHtml(): Promise<any> { | 
					
						
							|  |  |  |     if (!this.text) { | 
					
						
							|  |  |  |       return ''; | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-01-21 01:12:57 +01:00
										 |  |  |     const normalized = domtools.plugins.smartstring.normalize.standard(this.text); | 
					
						
							|  |  |  |     const result = await domtools.plugins.smartmarkdown.SmartMarkdown.easyMarkdownToHtml( | 
					
						
							|  |  |  |       normalized | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     return unsafeHTML(result); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public async show() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public async destroy() { | 
					
						
							|  |  |  |     (this.shadowRoot.querySelector('.maincontainer') as HTMLElement).style.opacity = '0'; | 
					
						
							|  |  |  |     this.windowLayer.destroy(); | 
					
						
							| 
									
										
										
										
											2022-05-20 18:44:33 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } |