From 6f0a6d49463cf6f287de9d124c8b0772e3c35ac8 Mon Sep 17 00:00:00 2001 From: Vinicius Date: Fri, 4 Aug 2023 17:45:57 -0300 Subject: [PATCH] feat: presence mouse --- src/web-components/index.ts | 1 + .../presence-mouses/index.test.ts | 51 ++++++++++ src/web-components/presence-mouses/index.ts | 98 +++++++++++++++++++ src/web-components/presence-mouses/styles.ts | 46 +++++++++ 4 files changed, 196 insertions(+) create mode 100644 src/web-components/presence-mouses/index.test.ts create mode 100644 src/web-components/presence-mouses/index.ts create mode 100644 src/web-components/presence-mouses/styles.ts diff --git a/src/web-components/index.ts b/src/web-components/index.ts index 346853cc..7122ec0e 100644 --- a/src/web-components/index.ts +++ b/src/web-components/index.ts @@ -1 +1,2 @@ export { HelloWorld } from './hello-world'; +export { Mouses } from './presence-mouses'; diff --git a/src/web-components/presence-mouses/index.test.ts b/src/web-components/presence-mouses/index.test.ts new file mode 100644 index 00000000..c548a3fa --- /dev/null +++ b/src/web-components/presence-mouses/index.test.ts @@ -0,0 +1,51 @@ +import sleep from '../../common/utils/sleep'; + +import '.'; + +const element = document.createElement('superviz-mouses'); +document.body.appendChild(element); + +describe('Mouses web component', () => { + test('should have a div id with attendee id and a attendee name in innerHTML', async () => { + const renderedElement = document.getElementsByTagName('superviz-mouses')[0]; + const attendeeId = 'Attendee1'; + const name = 'Attendee Name'; + const mouseFollower = document.createElement('div'); + mouseFollower.setAttribute('id', `${attendeeId}`); + mouseFollower.setAttribute('class', 'mouse-follower'); + renderedElement.appendChild(mouseFollower); + + const mouseUserName = document.createElement('div'); + mouseUserName.setAttribute('class', 'mouse-user-name'); + mouseUserName.innerHTML = name; + + renderedElement.appendChild(mouseUserName); + + await sleep(); + + const attendeeElement = renderedElement.shadowRoot?.querySelector('#Attendee1'); + expect(attendeeElement).toBeTruthy(); + + const mouseUserNameElement = renderedElement.shadowRoot?.querySelector('.mouse-user-name'); + expect(mouseUserNameElement).toBeTruthy(); + expect(mouseUserNameElement?.textContent).toEqual(name); + }); + + it('should add event listeners on resize window and mouse move', async () => { + // mock + const resizeHandler = jest.fn(); + const moveHandler = jest.fn(); + + // listeners + element.addEventListener('resize', resizeHandler); + element.addEventListener('mousemove', moveHandler); + + // simulate events + element.dispatchEvent(new Event('resize')); + element.dispatchEvent(new MouseEvent('mousemove')); + + // events called + expect(resizeHandler).toHaveBeenCalled(); + expect(moveHandler).toHaveBeenCalled(); + }); +}); diff --git a/src/web-components/presence-mouses/index.ts b/src/web-components/presence-mouses/index.ts new file mode 100644 index 00000000..ec192d73 --- /dev/null +++ b/src/web-components/presence-mouses/index.ts @@ -0,0 +1,98 @@ +import { LitElement, html } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +import { styles as customMouseStyles } from './styles'; + +@customElement('superviz-mouses') +export class Mouses extends LitElement { + declare name: string; + declare attendeeId: string; + declare pointerMouse: string; + + static properties = { + name: { type: String }, + attendeeId: { type: String }, + pointerMouse: { type: String }, + + }; + + static styles = [customMouseStyles]; + + constructor() { + super(); + + this.name = 'Attendee Name'; + this.attendeeId = 'Attendee1'; + } + + connectedCallback() { + super.connectedCallback(); + window.addEventListener('resize', this._handleResize); + window.addEventListener('mousemove', this._handleMove); + + // if use Iframe on mouse move + // document.addEventListener('DOMContentLoaded', this._onParentDOMContentLoaded); + } + + disconnectedCallback() { + super.disconnectedCallback(); + window.removeEventListener('resize', this._handleResize); + window.removeEventListener('mousemove', this._handleMove); + + // if use Iframe on mouse move + // document.removeEventListener('DOMContentLoaded', this._onParentDOMContentLoaded); + } + + _onParentDOMContentLoaded = () => { + this._trackMouseInIframes(); + }; + + // if use Iframe on mouse move + private _trackMouseInIframes() { + const iframes = document.getElementsByTagName('iframe'); + const iframeArray: HTMLIFrameElement[] = Array.from(iframes); + + iframeArray.forEach((iframe) => { + const iframeWindow = iframe.contentWindow; + if (iframeWindow) { + iframeWindow.addEventListener('mousemove', (event) => { + const x = event.clientX; + const y = event.clientY; + // console.log(`IFRAME (${iframe.src}) - X: ${x}, Y: ${y}`); + }); + } + }); + } + + private _handleMove = (e) => { + const x = e.clientX; + const y = e.clientY; + + const divMouseFollower = this.shadowRoot.getElementById(this.attendeeId); + if (!divMouseFollower) { + return; + } + divMouseFollower.style.left = `${x.toString()}px`; + divMouseFollower.style.top = `${y.toString()}px`; + // console.log(`DOM - X: ${x}, Y: ${y}`); + }; + + private _handleResize = (e) => { + // console.log('RESIZE: ', e.currentTarget.innerWidth, e.currentTarget.innerHeight); + }; + + protected render() { + return html` +
+
+
+
+
${this.name}
+
+
+
+ `; + } +} + +document.body.appendChild(document.createElement('superviz-mouses')); diff --git a/src/web-components/presence-mouses/styles.ts b/src/web-components/presence-mouses/styles.ts new file mode 100644 index 00000000..52886aad --- /dev/null +++ b/src/web-components/presence-mouses/styles.ts @@ -0,0 +1,46 @@ +import { css } from 'lit'; +// import { customElement } from 'lit/decorators.js'; +export const styles = css` +#mouse-container { + position: absolute; + display: flex; + justify-content: center; + align-items: center; +} + +#mouse-sync { + position: absolute; +} + +.mouse-board { + background: transparent; + position: absolute; + top: 0; + cursor: none !important; +} + +.mouse-follower { + position: absolute; + display: block; + transition: all 0.4s; +} + +.pointer-mouse { + display: flex; + height: 17px; + width: 17px; + background-image: url(https://production.cdn.superviz.com/static/pointers/0.svg); +} + +.mouse-user-name { + border-radius: 30px; + padding: 2px 8px; + font-weight: 700; + font-size: 14px; + line-height: 22px; + margin-left: 10px; + margin-top: -6px; + background: yellow; + white-space: nowrap; +} +`;